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

/**
 * @file CPlaneToObj.cpp
 * @brief CPlaneToObj.h の実装
 */
#include "stdafx.h"
#include "mg/Point.h"
#include "mg/FSurface.h"
#include "fugen.h"
#include "fugenView.h"
#include "ViewCmd/CPlaneUtil.h"
#include "ViewCmd/CPlaneToObj.h"

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

// MGCPlaneToObjTool

MGCPlaneToObjTool::MGCPlaneToObjTool(fugenDoc* pDoc)
:MGCommandStateOwner(pDoc,ID_CPLANE_TO_OBJ),
m_pView(theApp.currentfugenView(pDoc)){
}

MGCPlaneToObjTool::MGCPlaneToObjTool(fugenView* pView)
:MGCommandStateOwner(pView->GetDocument(),ID_CPLANE_TO_OBJ),m_pView(pView){
}

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

bool MGCPlaneToObjTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	const MGPickObjects& pobjs=current_objects();
	const MGPoint* pt;
	size_t npicked=pobjs.size();
	if(npicked == 1){
		m_obj = pobjs.front();
		MGCurve* curve= dynamic_cast<MGCurve*>(m_obj.leaf_object());
		if(curve){
			MGCPlaneCurveIPoint* curveCommand=new MGCPlaneCurveIPoint(this,m_pView,curve);
			set_child_current_command(curveCommand);//invoke MGCPlaneCurveIPoint.
		}else if(pt= dynamic_cast<const MGPoint*>(m_obj.leaf_object())){

			execCPlaneTranslateAction(m_pView,pt->position());//cplane translation.
			return OnCommandEnd(1);

		}else{
			MGFSurface* f=m_obj.leaf_object()->fsurface();
			if(f)//invoke MGCPlaneToSurfaceIPoint to locate surface point.
				set_child_current_command(
				new MGCPlaneToSurfaceIPoint(this,m_pView,f));
		}
	}else{
		// サブステートへ
		set_child_current_command(new MGCPlaneToObjSObj(this));//Select object on which
			//cplane's origin to locate
	}
	return false;
}

// MGCPlaneToObjSObj

MGCPlaneToObjSObj::MGCPlaneToObjSObj(MGCommandStateOwner* owner)
: MGSelectState(owner, MGSelectState::SINGLE_SELECT) // single-pick
{}

bool MGCPlaneToObjSObj::initiate_tool(){
	MGSelectState::initiate_tool();
	clear_pick_object();
	SetStatusMessage(IDS_PROMPT_CPLANE_OBJECT);
	return false;
}

bool MGCPlaneToObjSObj::OnSelected(
	fugenView* pView,//The fugenView pointer where point input event took place.
	MGPickObjects&	objs,	//selected objects at this selection operation.
	MGPickObjects&	unselected_objects	//unselected objects at this selection operation.
		//unselected_objects.size()>=1 only when the already selected objects are selected
		//when add mode is set(or when operation is done with a crtl key pressed).
){
	ASSERT(objs.size() == 1);

	MGCPlaneToObjTool* owner=state_owner();
	MGPickObject pobj=objs.front();
	const MGObject* obj=pobj.leaf_object();
	switch(obj->manifold_dimension()){
	case 0:
		execCPlaneTranslateAction(pView, dynamic_cast<const MGPoint*>(obj)->position());
		break;
	case 1:
			set_sibling_next_command(
				new MGCPlaneCurveIPoint(owner,pView, dynamic_cast<const MGCurve*>(obj)));
		return false;
	case 2:
		{
			const MGFSurface* f=obj->fsurface();
			if(f)
				set_sibling_next_command(
				new MGCPlaneToSurfaceIPoint(owner,pView,f));
		}
		return false;
	default:;
	}
	return OnCommandEnd(1);
}

// MGCPlaneToSurfaceIPoint

MGCPlaneToSurfaceIPoint::MGCPlaneToSurfaceIPoint(
	MGCommandStateOwner* owner,
	fugenView* pView, // 対象となるビュー
	const MGFSurface* f // CPlane をフィットさせる曲線
	): MGLocateOnObjects(f->object_pointer(),owner),
m_pView(pView),m_f(f),m_alongU(true), m_CplaneKind(2),m_OnlyMove(false){
	const MGContext& ctx=*(document()->context());
	const MGColor* gridColors=ctx.gridColors();
	m_zColor=&gridColors[3];
	if(!m_pView->is_mainView())
		m_OnlyMove=true;
	turn_on_vertex();
	turn_on_center();
}

void MGCPlaneToSurfaceIPoint::compute_plane(MGPosition& org,MGVector& X,MGVector& Y){
	org = m_f->eval(m_param);

	MGVector Normal[3];
	MGVector& Tu=Normal[0];
	MGVector& Tv=Normal[1];
	MGVector& N=Normal[2];

	Tu=m_f->eval(m_param,1,0);
	Tv=m_f->eval(m_param,0,1);
	N=m_f->unit_normal(m_param);
	if(m_OnlyMove || !m_pView->is_mainView()){
		const MGPlane& pl=m_pView->cplane().plane();
		X=pl.u_deriv();
		Y=pl.v_deriv();
	}else{
		if(m_alongU){
			Tv=N*Tu;
		}else{
			Tu=Tv*N;
		}
		X=Normal[(m_CplaneKind+1)%3];
		Y=Normal[(m_CplaneKind+2)%3];
	}
}

void MGCPlaneToSurfaceIPoint::display(mgSysGL& sgl,fugenView* pView){
	MGVector X,Y;
	MGPosition org;
	compute_plane(org,X,Y);
	const MGConstructionPlane& cplane = m_pView->cplane();
	PreviewCPlane(sgl,cplane, org,X,Y,m_zColor);
}

bool MGCPlaneToSurfaceIPoint::OnKeyDown(
	fugenView* pView,///<The fugenView pointer where this event took place.
	UINT nChar,	UINT nRepCnt, UINT nFlags
		///<These parameters are of CWnd::OnKeyDown. See the document.
){
	if(m_pView->is_mainView()){
		switch(nChar){
		case 'm':
		case 'M':
			m_OnlyMove=!m_OnlyMove;
		case 't':
		case 'T':
			m_CplaneKind=0;
			break;
		case 'n':
		case 'N':
			m_CplaneKind=2;
			break;
		case 'b':
		case 'B':
			m_CplaneKind=1;
			break;
		case 'u':
		case 'U':
			m_alongU=true;
			break;
		case 'v':
		case 'V':
			m_alongU=false;
			break;
		}
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGCPlaneToSurfaceIPoint::OnLocated(const MGLocateInfo& info){	
	// 曲面上のパラメータが取れているはず...
	const MGFSurface* f = info.object()->fsurface();
	if(f != m_f){
		return false;
	}
	m_param = info.parameter();

	// OK. CPlaneの計算を開始する
	MGVector X,Y;
	MGPosition org;
	compute_plane(org,X,Y);
	ExecPlaneAction(m_pView, X, Y, org);
	setActiveView(m_pView);
	return OnCommandEnd(1);
}

void MGCPlaneToSurfaceIPoint::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	const MGObject* obj = snappedObject();
	if(obj){
		const MGFSurface* f = obj->fsurface();
		if(m_f == f){
			m_param = snappedParam();
			display(sgl,pView);
		}
	}
}

void MGCPlaneToSurfaceIPoint::prompt_message() const{
	CString base(m_alongU ? "U":"V");
	CString other(m_alongU ? "V":"U");
	CString normal("tan U"),kb("B-tangnt v, N-norml");
	if(m_CplaneKind==1){
		normal="tan V";
		kb="N-norml, T-tangnt U";
	}else if(m_CplaneKind==2){
		normal="N";
		kb="T-tangnt u, B-tangnt v";
	}
	
	CString moveOnly;moveOnly.LoadString(IDS_STRING_MOVE_ONLY);
	CString rotateToo;rotateToo.LoadString(IDS_STRING_ROTATE_TOO);
	if(m_OnlyMove)
		SetStatusMessage(IDS_PROMPT_CPLCRV_ORIGIN2,moveOnly,rotateToo);
	else
		SetStatusMessage(IDS_PROMPT_CPLSRF_ORIGIN,rotateToo,moveOnly,
			base,other,other,normal,kb);
}
