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

/**
 * @file Rect3Point.cpp
 * @brief MGRect3PointTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "Calc/mgcalc.h"
#include "fugen.h"
#include "fugenView.h"
#include "GLInputRealDlg.h"
#include "Misc/UserPreference.h"
#include "Common/CommandStateOwner.h"
#include "CurveCmd/Rect3Point.h"

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

// MGRect3PointTool

namespace{
	const double dRadius = 3.0;
	const double dRho    = 0.5;
	const bool   bCircle = true;
}

MGRect3PointTool::MGRect3PointTool(fugenDoc* pDoc)
: MGLocateState(pDoc,ID_CURVE_RECT_3POINTS,LINE_RUBBER,POINT_IPDRAW),
m_dRadius(dRadius), m_bRound(false){
}

MGRect3PointTool::MGRect3PointTool(MGCommandStateOwner* owner)
: MGLocateState(owner,UNLOCK_SNAP_ATTRIB,NO_RUBBER,POINT_IPDRAW),
m_dRadius(dRadius),m_bRound(false){
}

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

bool MGRect3PointTool::initiate_tool(){
	MGLocateState::initiate_tool();
	const UserPreference& pref = UserPreference::getInstance();
	m_dRadius = pref.GetDoubleValue(upv_Curve_Rect3Point_Radius);
	//m_dRho = pref.GetDoubleValue(upv_Curve_Rect3Point_Rho);
	//m_bCircle = pref.GetBoolValue(upv_Curve_Rect3Point_Circle);
	return false;
}

bool MGRect3PointTool::terminate_tool(bool cancel){
	UserPreference& pref = UserPreference::getInstance();
	pref.SetDoubleValue(upv_Curve_Rect3Point_Radius, m_dRadius);
	//pref.SetDoubleValue(upv_Curve_Rect3Point_Rho, m_dRho);
	//pref.SetBoolValue(upv_Curve_Rect3Point_Circle, m_bCircle);

	return MGLocateState::terminate_tool(cancel);
}

bool MGRect3PointTool::calculate(){
	const LInfoVec& linfos=locates();
	assert(linfos.size()>=3);

	const MGPosition& P0=linfos[0]->point_world();
	const MGPosition& P1=linfos[1]->point_world();
	const MGPosition& P2=linfos[2]->point_world();
	m_rect.create_from_edge(P0,P1,P2);
	if(!m_rect.valid()){
		// fail
		return false;
	}

	if(m_bRound){
		if(linfos.size() == 4){
			m_round_rect.create(&m_rect,linfos[3]->point_world());
		}else{
			m_round_rect.create(&m_rect,m_dRadius);
		}

		if(!m_round_rect.valid()){
			// fail
			return false;
		}
	}

	// ドキュメント変更
	add_object_to_current_group(m_bRound ? m_round_rect.release() : m_rect.release());
	return true;
}

void MGRect3PointTool::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	const LInfoVec& linfos=locates();
	size_t np=linfos.size();
	if(np>=2){
		const MGPosition& P0=linfos[0]->point_world();
		const MGPosition& P1=linfos[1]->point_world();
		if(np==3){
			m_rect.create_from_edge(P0,P1,linfos[2]->point_world());
			if(m_bRound)
				m_round_rect.create(&m_rect,cursor());
		}else
			m_rect.create_from_edge(P0,P1,cursor());

		MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
		if(m_round_rect.valid()){
			m_round_rect.draw(sgl);
		}else if(m_rect.valid()){
			m_rect.draw(sgl);
		}
	}else{
		m_rect.clear();
		m_round_rect.clear();
	}
}

bool MGRect3PointTool::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	LInfoVec& linfos=locates();
	size_t np=linfos.size();
	switch(nChar){
	case 'r':
	case 'R':
		// round option
		if(np==0 && !m_bRound){
			m_bRound = true;
		}else if(np==3 && m_bRound){
			// 数値入力(real)
			CString title; title.LoadString(IDS_PROMPT_CIRCLE_RADIUS);
			CGLInputRealDlg dlg(title);
			dlg.SetValue(m_dRadius);
			if(dlg.DoModal()==IDOK){
				double x = dlg.GetValue();
				if(x > 0){
					m_dRadius = x;
					if(calculate())
						return OnCommandEnd(1);
					else
						// failed
						return OnCommandEnd(IDS_FAIL_GENERATE_CURVE);
				}
			}
		}
		break;
	case VK_RETURN:
		if(np==2){
			const MGPosition& P0=linfos[0]->point_world();
			MGLocateInfo& linf1=*linfos[1];
			const MGPosition& P1=linf1.point_world();

			// 長方形のもう一辺の長さを len(P0, P1) とする。
			MGVector V01=P1-P0;
			const MGPlane& pl = linfos[0]->window()->cplane().plane();
			const MGVector& nrml=pl.normal();//is a unit.
			MGVector directn=nrml*V01;

			///Simulate that P2 is input as the 3rd point.
			MGPosition P2 = (P0+P1)*.5 + directn;
			MGLocateInfo* linfP2=new MGLocateInfo(linf1);//CPoint data is invalid.
			linfP2->point_world()=P2;
			linfos.emplace_back(linfP2);

			if(!m_bRound){
				// ドキュメント変更
				if(calculate())
					return OnCommandEnd(1);
				else
					// failed
					return OnCommandEnd(IDS_FAIL_GENERATE_CURVE);
			}
		}
		return false;
	default:;
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGRect3PointTool::OnLocated(const MGLocateInfo& info){
	size_t np=locates().size();
	if(np==1)
		setDrawerRubber(LINE_RUBBER);
	else
		setDrawerRubber(NO_RUBBER);

	if(np<=2){
		m_rect.clear();
		m_round_rect.clear();
	}
	if(np>=4 || (!m_bRound && np>=3)){
		if(calculate())
			return OnCommandEnd(1);
		else
			// failed
			return OnCommandEnd(IDS_FAIL_GENERATE_CURVE);
	}
	return false;
}

void MGRect3PointTool::prompt_message() const{
	std::vector<MGPosition>::size_type np = locates().size();
	switch(np){
	case 0:
		{
			UINT nIDS = m_bRound
				? IDS_PROMPT_RECT_POINT_START_NO_R : IDS_PROMPT_RECT_POINT_START_R;
			SetStatusMessage(nIDS);
		}
		break;
	case 1:
		SetStatusMessage(IDS_PROMPT_RECT_POINT_END);
		break;
	case 2:
		SetStatusMessage(IDS_PROMPT_RECT_POINT_BROAD);
		break;
	case 3:
		{
			SetStatusMessage(IDS_PROMPT_RECT_ROUND, m_dRadius);
		}
		break;
	}
}
