/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */
/********************************************************************/
/**
 * @file LineAngled.cpp
 * @brief MGLineAngledTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/Straight.h"
#include "Calc/line.h"
#include "Calc/mgcalc.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "Misc/UserPreference.h"
#include "Common/CommandStateOwner.h"
#include "GLInputRealDlg.h"
#include "CurveCmd/LineAngled.h"

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

// MGLineAngledTool

namespace{
	double dAngle = 10.;
	const bool   bBoth  = false;
}

MGLineAngledTool::MGLineAngledTool(fugenDoc* pDoc)
:MGLocateState(pDoc,ID_CURVE_LINE_ANGLED,LINE_RUBBER,POINT_IPDRAW),
m_bBoth(bBoth){
}

MGLineAngledTool::MGLineAngledTool(MGCommandStateOwner* owner)
:MGLocateState(owner,UNLOCK_SNAP_ATTRIB,LINE_RUBBER,POINT_IPDRAW),
m_bBoth(bBoth){
}

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

bool MGLineAngledTool::initiate_tool(){
	MGLocateState::initiate_tool();
	const UserPreference& pref = UserPreference::getInstance();
	m_dAngle = pref.GetDoubleValue(upv_Curve_LineAngled_Angle);
	m_bBoth = pref.GetBoolValue(upv_Curve_LineAngled_Both);

	m_baseLineEnd.set_null();
	return false;
}

bool MGLineAngledTool::terminate_tool(bool cancel){
	UserPreference& pref = UserPreference::getInstance();
	pref.SetDoubleValue(upv_Curve_LineAngled_Angle, m_dAngle);
	pref.SetBoolValue(upv_Curve_LineAngled_Both, m_bBoth);

	return MGLocateState::terminate_tool(cancel);
}

//make the target line and add the line to the document.
bool MGLineAngledTool::make_line(){
	ASSERT(!m_rho.is_null());
	
	const LInfoVec& linfos=locates();	
	const MGPosition& P0=linfos[0]->point_world();
	const MGPosition& P1=linfos[1]->point_world();
	MGVector v(P1-P0);
	v = P0+v.project(m_rho);

	std::unique_ptr<MGCurve> line(mgcalc::create_line(P0, v, m_bBoth));
	// ドキュメントを変更
	add_object_to_current_group(line.release());
	return true;
}

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

	const double* baseLineEnd;
	if(np==1){
		if(m_baseLineEnd.is_null())
			baseLineEnd=cursor().data();
		else
			baseLineEnd=m_baseLineEnd.data();
	}
	const MGPosition& P0=linfos[0]->point_world();

	//Draw base line to measure angle to the target line.
	sgl.Begin(GL_LINES);
		MGColor::get_instance(MGColor::White).exec(sgl);
		sgl.Vertex3dv(P0.data());
		sgl.Vertex3dv(baseLineEnd);
	sgl.End();
	if(np==1 && m_baseLineEnd.is_null())
		return;

	MGVector v(cursor() - P0);
	MGPosition end = P0 + v.project(m_rho);
	std::unique_ptr<MGCurve> line = mgcalc::create_line(P0, end, m_bBoth);
	if(line.get()){
		MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
		line->drawWire(sgl);
	}
}

bool MGLineAngledTool::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case 'b':
	case 'B':
		if(locates().size()>=1){
			m_bBoth ^= true;
		}
		break;
	default:
		;
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGLineAngledTool::OnLocated(const MGLocateInfo& info){
	const LInfoVec& linfos=locates();
	size_t np = linfos.size();
	
	switch(np){
	case 0:
		m_baseLineEnd.set_null();
		break;
	case 2:{
		const MGPosition& P0=linfos[0]->point_world();
		const MGPosition& P1=linfos[1]->point_world();
		if(m_baseLineEnd.is_null()){
			// ダイアログを表示する, and input the angle from the dialogue.
			fugenView* win=info.window();
			double rAngle;
			if(InputAngleFromDialogue(m_dAngle,win,rAngle)){
				m_rho = P1-P0;
				MGVector normal = win->cplane().plane().normal();
				MGMatrix mat;
				mat.set_rotate_3D(normal, rAngle);
				m_rho*=mat;
				m_baseLineEnd=P1;
			}
		}else{
			// 直線を作成する
			make_line();
			return OnCommandEnd(1);
		}

		}
		cancel_last_locate();
		break;//To input the second point.
	default:;
	}
	if(linfos.size()==1){
		if(m_baseLineEnd.is_null())
			setDrawerRubber(LINE_RUBBER);
		else
			setDrawerRubber(NO_RUBBER);
	}

	return false;
}

void MGLineAngledTool::prompt_message() const{
	CString strYesNo;
	switch(locates().size()){
	case 0:
		SetStatusMessage(IDS_PROMPT_LINE_START);
		break;
	case 1:
		if(	m_baseLineEnd.is_null()){
			SetStatusMessage(IDS_PROMPT_BASELINE_END);
			break;
		}
	case 2:
		{
			strYesNo.LoadString(m_bBoth ? IDS_YES : IDS_NO);
			SetStatusMessage(IDS_PROMPT_LINE_END, strYesNo);
		}
		break;
	}
}
