#include "stdafx.h"
#include "mg/LBRep.h"
#include "mg/PickObject.h"
#include "Calc/curve.h"
#include "Calc/mgcalc.h"
#include "GLInputNumberDlg.h"
#include "fugenView.h"
#include "Misc/UserPreference.h"
#include "CurveCmd/SplineCurveUpdateTangentTool.h"

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

// 接ベクトル変更コマンド

// MGSplineCurveUpdateTangentTool
MGSplineCurveUpdateTangentTool::MGSplineCurveUpdateTangentTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_CURVE_SPLINE_MOVE_POINT){
}

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

bool MGSplineCurveUpdateTangentTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();

	// ピックされている場合は、一度クリアする
	clear_pick_object();

	// 曲線(mgAll_LBRep)の選択からスタート
	set_child_current_command(new MGSplineCurveSelectTarget(this));

	return false;
}

// MGSplineCurveSelectTarget
MGSplineCurveSelectTarget::MGSplineCurveSelectTarget(MGSplineCurveUpdateTangentTool* owner)
: MGSelectState(owner, MGSelectState::SINGLE_SELECT, mgAll_LBRep){
}

bool MGSplineCurveSelectTarget::initiate_tool(){
	MGSelectState::initiate_tool();

	SetStatusMessage(IDS_PROMPT_CURVE);
	return false;
}

bool MGSplineCurveSelectTarget::OnSelected(
	fugenView* window,//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).
){
	MGSplineCurveUpdateTangentTool* owner = state_owner();

	// 選択されたオブジェクトを取得
	MGPickObject& obj = owner->m_pickedCurve = objs.front();

	// targetCurveの取得
	owner->m_targetCurve = static_cast<MGLBRep*>(obj.leaf_object());
	const MGLBRep& lb = *owner->m_targetCurve;

	// 制御点の取得
	size_t nm = lb.bdim();

	// 制御点の数が2の場合は、コマンドキャンセル
	if (nm == 2) {
		return OnCommandEnd(IDS_ERROR_SPLINE_CURVE_TO_STRAIGHT);
	}

	// 選択された点座標のパラメータ値(t_selctied)を取得
	const MGPosition& tt = obj.parameter();
	double t_selctied = tt[0];

	// 始点と終点のパラメータを取得し、選択された点が始点と終点のどちらが近いかを判定
	double ts = lb.param_s(), te = lb.param_e();
	owner->m_target_is_start = (t_selctied - ts) <= (te - t_selctied);

	// m_curveにtargetCurveをコピーする
	owner->m_curve = std::unique_ptr<MGLBRep>(new MGLBRep(lb));

	// 次のstate(制御点指定)へ進む 
	set_sibling_next_command(new MGSplineCurveUpdateTangent(state_owner()));

	return false;
}

// MGSplineCurveUpdateTangent
MGSplineCurveUpdateTangent::MGSplineCurveUpdateTangent(MGSplineCurveUpdateTangentTool* owner)
: MGLocateState(owner,
LOCK_SNAP_ATTRIB,//Prohibit to update snap attrib
NO_RUBBER,POINTLINE_IPDRAW){
}

bool MGSplineCurveUpdateTangent::initiate_tool(){
	MGLocateState::initiate_tool();

	SetStatusMessage(IDS_PROMPT_UPDATE_TANGENT_1);
	return false;
}

void MGSplineCurveUpdateTangent::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	MGSplineCurveUpdateTangentTool* owner = state_owner();
	MGBPointSeq& bp = owner->m_curve->line_bcoef();

	// 始点側と終点側のどちらが近いか
	if(owner->m_target_is_start){
		// 制御点変更
		bp.store_at(1, cursor());
	}else{
		// 終点の1つ前の座標
		int nm2 = bp.length()-2;
		// 制御点変更
		bp.store_at(nm2, cursor());
	}

	// 始点とその次の点
	MGPosition P0(bp(1)), P1(bp(0));
	// 始点側の延長点
	MGPosition P2(2 * bp(0)(0) - bp(1)(0), 2 * bp(0)(1) - bp(1)(1), 2 * bp(0)(2) - bp(1)(2));

	int n = bp.length();
	// 終点とその前の点
	MGPosition Pnm0(bp(n-1)), Pnm1(bp(n-2));
	// 終点側の延長点
	MGPosition Pnm2(2 * bp(n-1)(0) - bp(n-2)(0), 2 * bp(n-1)(1) - bp(n-2)(1), 2 * bp(n-1)(2) - bp(n-2)(2));

	// 線に色つける(とりあえずMGColor::Blue)
	MGColor::get_instance(MGColor::Blue).exec(sgl);
	// 接ベクトルを描く
	sgl.drawStraight(P0, P1);
	sgl.drawStraight(P0, P2); // 始点と始点側の延長点を結んだ直線
	sgl.drawStraight(Pnm0, Pnm1);
	sgl.drawStraight(Pnm0, Pnm2); // 終点と終点側の延長点を結んだ直線
	// 線に色つける
	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	// 曲線を描く
	owner->m_curve->drawWire(sgl);
}

bool MGSplineCurveUpdateTangent::OnLocated(const MGLocateInfo& info){
	MGSplineCurveUpdateTangentTool* owner = state_owner();

	MGGelPosition replaceObj(owner->m_pickedCurve.bottom_group(), owner->m_curve.release());
	// 古いオブジェクトと新しいオブジェクトの入れ替え
	replace(owner->m_pickedCurve, replaceObj);
	return OnCommandEnd(1);
}

bool MGSplineCurveUpdateTangent::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	MGSplineCurveUpdateTangentTool* owner = state_owner();

	switch(nChar){
	case 'c':
	case 'C':
		// 変更する始点と終点を変える
		owner->m_target_is_start = !owner->m_target_is_start;

		// 始点終点変更時にカーソルの値が制御点になってしまっていたので、
		// 始点終点変更時は、m_curveを一度選択された曲線に戻す 
		owner->m_curve = std::unique_ptr<MGLBRep>(new MGLBRep(*owner->m_targetCurve));
		break;
	default:;
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}
