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

// TransRotate3D.cpp: MGTransRotate3DTool クラスのインプリメンテーション

#include "stdafx.h"
#include "mg/Straight.h"
#include "mg/CSisects.h"
#include "Calc/mgcalc.h"
#include "Calc/mgfunctor.h"
#include "fugenView.h"
#include "GLInputRealDlg.h"
#include "TransCmd/TransRotate3D.h"

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

// MGTransRotate3DTool

MGTransRotate3DTool::MGTransRotate3DTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_TRANSFORM_ROTATE_3D){
}

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

bool MGTransRotate3DTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	
	if(current_objects().empty()){
		// オブジェクト選択からスタート
		set_child_current_command(new MGTransRotate3DSObj(this));
	}else{
		// 参照点入力からスタート
		set_child_current_command(new MGTransRotate3DIPoint(this));
	}
	return false;
}


// MGTransRotate3DSObj

MGTransRotate3DSObj::MGTransRotate3DSObj(MGTransRotate3DTool* owner)
: MGSelectState(owner, MGSelectState::MULTIPLE_SELECT){
}

bool MGTransRotate3DSObj::initiate_tool(){
	MGSelectState::initiate_tool();
	prompt_message();
	return false;
}

bool MGTransRotate3DSObj::OnKeyDown(fugenView* window, UINT nChar,UINT nRepCnt, UINT nFlags){
	if(nChar == VK_RETURN){
		if(current_objects().empty()){
			// キャンセルとみなす
			return get_owner_command()->OnCommandEnd(3);
		}else{
			// 次の state へ進む
			set_sibling_next_command(new MGTransRotate3DIPoint(state_owner()));
			return false;
		}
	}else{
		return MGSelectState::OnKeyDown(window, nChar, nRepCnt, nFlags);
	}
}

void MGTransRotate3DSObj::prompt_message()const{
	SetStatusMessage(IDS_PROMPT_OBJECT);
}

// MGTransRotate3DIPoint

MGTransRotate3DIPoint::MGTransRotate3DIPoint(MGTransRotate3DTool* owner)
: MGLocateState(owner, UNLOCK_SNAP_ATTRIB, NO_RUBBER, POINT_IPDRAW)
,m_bCopy(false){
}

bool MGTransRotate3DIPoint::OnKeyDown(
	fugenView* pView,
	UINT           nChar,
	UINT           nRepCnt,
	UINT           nFlags
){
	static double angle=0.;

	if(nChar == 'c' || nChar == 'C'){
		toggle_copy_mode();
	}else if(nChar == 'k' || nChar == 'K'){
		if(locates().size()>=2){
			// 角度入力の、数値入力ダイアログ出現
			double angleR;
			if(InputAngleFromDialogue(angle,pView,angleR)){
				disable_AETPmode();
				calculate(angleR);
				// コマンド終了
				return OnCommandEnd(1);
			}
		}
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGTransRotate3DIPoint::OnLocated(const MGLocateInfo& info){
	const LInfoVec& linfos=locates();
	switch(linfos.size()){
	case 0:
		disable_AETPmode();
		break;

	case 1:// 原点を入力した直後, orgを確定
		setDrawerRubber(LINE_RUBBER);
		disable_AETPmode();
		break;

	case 2:// 回転軸の方向を指定した直後, ref0を確定
		setDrawerRubber(NO_RUBBER);
		m_normal=linfos[1]->point_world()-linfos[0]->point_world();
		setPlanarRestrictionPointToProhibitUpdate(m_normal,linfos[0]->point_world());
		break;

	case 3:// 参照点1を指定した直後, ref1を確定。
		break;

	case 4:// 参照点2を指定した直後, 一旦pop, ref2確定
		{
		const MGPosition& org=linfos[0]->point_world();
		const MGPosition& P1=linfos[2]->point_world();
		const MGPosition& P2=linfos[3]->point_world();
		double angle = MGCL::angle(org, P1, P2, m_normal);

		// 変換を計算
		// メインの計算開始
		disable_AETPmode();
		calculate(angle);
		return OnCommandEnd(1);
		}
	}
	return false;
}

void MGTransRotate3DIPoint::prompt_message()const{
	CString strYesNo;
	strYesNo.LoadString(is_copy_mode() ? IDS_YES : IDS_NO);

	switch(locates().size()){
	case 0:
		SetStatusMessage(IDS_PROMPT_ROTATE_3D_ORIGIN);
		break;
	case 1:
		SetStatusMessage(IDS_PROMPT_ROTATE_3D_AXIS, strYesNo);
		break;
	case 2:
		SetStatusMessage(IDS_PROMPT_ROTATE_3D_AXIS_START, strYesNo);
		break;
	case 3:
		SetStatusMessage(IDS_PROMPT_ROTATE_3D_AXIS_END, strYesNo);
		break;
	}
}

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

	sgl.LineWidth(2.f);

	const MGPosition& org=linfos[0]->point_world();
	const MGPosition& normalEnd= np>=2 ? linfos[1]->point_world() : cursor();
	// 補助線を描画(Normal).
	MGColor::get_instance(MGColor::White).exec(sgl);
	sgl.Begin(GL_LINES);
	sgl.Vertex3dv(org.data());
	sgl.Vertex3dv(normalEnd.data());
	sgl.End();
	if(np<=1)
		return;

	// 角度計測用線分(Baseline)を描画
	const MGPosition& P1= np>=3 ? linfos[2]->point_world() : cursor();
	sgl.drawOpenPolyline(&org,&P1,nullptr);
	if(np<=2)
		return;

	const MGPosition& P2=cursor(); // 偏角をなす線分の端点
	sgl.drawOpenPolyline(&org,&P2,nullptr);
		
	//Arc from the base line to the angle measuring line segment.
	MGVector Xaxis=P1-org;
	double r1=Xaxis.len(), r2=(P2-org).len();
	double arcRadius= r1<=r2 ? r1:r2; arcRadius*=.666;
	double angle = MGCL::angle(org, P1, P2, m_normal);
	if(angle>mgPAI)
		angle-=mgDBLPAI;
	MGEllipse arc(org,org+Xaxis.normalize()*arcRadius, angle, m_normal);
	arc.drawWire(sgl);

	// temporaryなモデルを描画
	fugenView& glv=*pView;
	const MGDrawParam& para=glv.draw_param();
	int density=para.line_desity_wire_face();
	MGTransf transf; transf.set_rotate_3D(m_normal, angle, org);

	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	const MGPickObjects& objs=current_objects();
	MGPickObjects::const_iterator cur = objs.begin(), last = objs.end();
	for(; cur != last; ++cur){
		std::unique_ptr<MGObject> obj((*cur)->top_object()->clone());
		obj->transform(transf);
		obj->drawWire(sgl,density);
	}
}

void MGTransRotate3DIPoint::calculate(double angle){
	const LInfoVec& linfos=locates();
	const MGPosition& org=linfos[0]->point_world();
	MGTransf transf; transf.set_rotate_3D(m_normal, angle, org);

	const MGPickObjects& curobj = current_objects();
	MGGelPositions gelps;
	MGPickObjects::const_iterator first = curobj.begin(), last = curobj.end();
	for(; first != last; ++first){
		MGObject* newobj = (*first)->top_object()->clone();
		newobj->transform(transf);
		gelps.push_back(MGGelPosition((*first)->bottom_group(),newobj));
	}

	if(m_bCopy){
		add_object_to_document(gelps);
	}else{
		replace(curobj,gelps);
	}
}
