/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */

/**
 * @file LineSegmentTool.cpp
 * @brief MGLineSegmentTool クラスのインプリメンテーション
 */
#include "stdafx.h"

#include "fugenDoc.h"
#include "mg/Straight.h"
#include "Calc/mgcalc.h"
#include "Calc/line.h"
#include "fugenView.h"
#include "Misc/UserPreference.h"
#include "CurveCmd/LineSegmentTool.h"
#include "CurveCmd/Line4Point.h"
#include "CurveCmd/LineAngled.h"
#include "CurveCmd/LineExtend.h"
#include "CurveCmd/LineNormal.h"
#include "CurveCmd/LinePerp1Tool.h"
#include "CurveCmd/LineTan1Tool.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// MGLineGeneralTool

MGLineGeneralTool::MGLineGeneralTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_CURVE_LINE){
}

MGCommandBase* MGLineGeneralTool::initial_clone(fugenDoc* pDoc)const{
	return new MGLineGeneralTool(pDoc);
}

bool MGLineGeneralTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	set_child_current_command(new MGLineSingleTool(this));
	return false;
}

// MGLineSingleTool

MGLineSingleTool::MGLineSingleTool(fugenDoc* pDoc)
: MGLocateState(pDoc, ID_CURVE_LINE, NO_RUBBER, POINT_IPDRAW), m_bBoth(false){
}

MGLineSingleTool::MGLineSingleTool(MGLineGeneralTool* owner)
: MGLocateState(owner, UNLOCK_SNAP_ATTRIB,
NO_RUBBER, POINT_IPDRAW), m_bBoth(false){
}

bool MGLineSingleTool::initiate_tool(){
	MGLocateState::initiate_tool();
	const UserPreference& pref = UserPreference::getInstance();
	m_bBoth = pref.GetBoolValue(upv_Curve_LineSingle_Both);
	return false;
}

void MGLineSingleTool::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	const LInfoVec& linfos=locates();
	size_t np=linfos.size();
	if(np==0)
		return;

	const MGPosition& P0=linfos[0]->point_world();
	const MGPosition& P1=cursor();
	// 直線(線分)を生成してドキュメントに追加
	std::unique_ptr<MGCurve> line(mgcalc::create_line(P0, P1, m_bBoth));
	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	line->drawWire(sgl);
}

bool MGLineSingleTool::terminate_tool(bool cancel){
	UserPreference& pref = UserPreference::getInstance();
	pref.SetBoolValue(upv_Curve_LineSingle_Both, m_bBoth);

	return MGLocateState::terminate_tool(cancel);
}

bool MGLineSingleTool::OnCommandEnd(
	UINT nIDS,	//=0: erase the current message, and display no messages.
				//=1: display "xxxx" normally end.
				//otherwise: nIDS is a string id, and load the message from string table to display.
	bool erase_temporary_display
){
	const LInfoVec& linfos=locates();
	const MGPosition& P0=linfos[0]->point_world();
	const MGPosition& P1=linfos[1]->point_world();
	// 直線(線分)を生成してドキュメントに追加
	std::unique_ptr<MGCurve> line(mgcalc::create_line(P0, P1, m_bBoth));
	add_object_to_current_group(line.release());
	return MGLocateState::OnCommandEnd(nIDS);
}

bool MGLineSingleTool::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case 'a':
	case 'A':
		// 角度(A) へ移行
		set_sibling_next_command(new MGLineAngledTool(get_owner_command()));
		break;
	case 'e':
	case 'E':
		// 延長(E) へ移行
		set_sibling_next_command(new MGLineExtendTool(get_owner_command()));
		break;
	case 'f':
	case 'F':
		// 4点(F) へ移行
		set_sibling_next_command(new MGLine4PointTool(get_owner_command()));
		break;
	case 'n':
	case 'N':
		// 法線(N) へ移行
		set_sibling_next_command(new MGLineNormalTool(get_owner_command()));
		break;
	case 'b':
	case 'B':
		// 両方向オプションをトグル
		m_bBoth ^= true;
		break;
	case 'p':
	case 'P':
		// 直交(P) へ移行
		set_sibling_next_command(new MGLinePerp1Tool(get_owner_command()));
		break;
	case 't':
	case 'T':
		// 接点(T) へ移行
		set_sibling_next_command(new MGLineTan1Tool(get_owner_command()));
		break;
	default:;
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGLineSingleTool::OnLocated(const MGLocateInfo&){
	if(locates().size() < 2){
		// メッセージを更新するだけ
		return false;
	}
	// 計算して終了
	return OnCommandEnd(1);
}

void MGLineSingleTool::prompt_message() const{
	UINT nIDS = 0;
	switch(locates().size()){
	case 0:
		nIDS = IDS_PROMPT_LINE_SINGLE_START;
		break;
	case 1:
		nIDS = IDS_PROMPT_LINE_END;
		break;
	}
	CString strYesNo;
	strYesNo.LoadString(m_bBoth ? IDS_YES : IDS_NO);
	SetStatusMessage(nIDS, strYesNo);
}

// MGLineSegmentTool

MGLineSegmentTool::MGLineSegmentTool(fugenDoc* pDoc)
: MGLocateState(pDoc,ID_CURVE_SEGMENTS,LINE_RUBBER,POINTLINE_IPDRAW),
m_bClose(false){
;}

MGCommandBase* MGLineSegmentTool::initial_clone(fugenDoc* pDoc)const{
	return new MGLineSegmentTool(pDoc);
}

//Invoked when command is to terminate as a nomal end.
bool MGLineSegmentTool::calculate(){
	const LInfoVec& linfos=locates();
	size_t n=linfos.size();
	if(n<2){
		// キャンセル扱い
		return false;
	}

	// オブジェクト生成	
	size_t nm1=n-1;
	size_t lnum=m_bClose ? n : nm1;
	std::list<MGStraight*> tmp(lnum);
	std::list<MGStraight*>::iterator tmpi=tmp.begin();
	for(size_t i=0; i<nm1; i++){
		*tmpi = new MGStraight(linfos[i+1]->point_world(), linfos[i]->point_world());
		++tmpi;
	}

	if(m_bClose){
		ASSERT(tmp.back() == 0);
		tmp.back() = new MGStraight(linfos[0]->point_world(), linfos[nm1]->point_world());
	}

	// ドキュメントを変更
	addGelsToCurrentGroup(tmp.begin(), tmp.end());	
	return true;
}

bool MGLineSegmentTool::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case 'c':
	case 'C':
		if(locates().size() > 2)
			m_bClose = !m_bClose;
		break;
	case VK_RETURN:
		if(!calculate()){
			return OnCommandEnd(2);
		}
		return OnCommandEnd(1);
	default:;
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGLineSegmentTool::OnLocated(const MGLocateInfo&){
	// メッセージを更新するだけ
	return false;
}

void MGLineSegmentTool::prompt_message() const{
	switch(locates().size()){
	case 0:
		SetStatusMessage(IDS_PROMPT_LINE_START);
		break;
	case 1:
		SetStatusMessage(IDS_PROMPT_SEGMENT_VERTEX);
		break;
	default:
		{
			CString strYesNo;
			strYesNo.LoadString(m_bClose ? IDS_YES : IDS_NO);
			SetStatusMessage(IDS_PROMPT_SEGMENT, strYesNo);
		}
		break;
	}
}
