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

/**
 * @file CurveMoveTool.cpp
 * @brief MGCurveMoveTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/Straight.h"
#include "Calc/mgcalc.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "CurveCmd/CurveMoveTool.h"


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

// MGCurveMoveTool

MGCurveMoveTool::MGCurveMoveTool(fugenDoc* pDoc)
: MGLocateState(pDoc,ID_CURVE_MOVE,LINE_RUBBER,POINT_IPDRAW),m_lbrep(0){
	turn_on_near();
	turn_on_center();
	turn_on_knot();
	turn_on_end();
}

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

bool MGCurveMoveTool::initiate_tool(){
	MGLocateState::initiate_tool();
	clear_pick_object();
	return false;
}

std::unique_ptr<MGCurve> MGCurveMoveTool::make_model(const MGPosition& dest){
	MGCurve* new_curve;
	double ts=m_originalCurve->param_s();
	double te=m_originalCurve->param_e();
	MGPosition Ps=m_originalCurve->eval(ts), Pe=m_originalCurve->eval(te);
	if(!m_lbrep){
		//////Case of MGStraight
		if(m_param-ts<=te-m_param){
			///When to move start point.
			Ps=dest;
		}else{
			///When to move end point.
			Pe=dest;
		}		
		new_curve=new MGStraight(Pe,Ps);
	}else{
		//////Case of MGLBRep
		MGLBRep* lb=new MGLBRep(*m_lbrep);
		int k=m_lbrep->order();
		if(k==2){
			///When  polyline.
			MGKnotVector& t=m_lbrep->knot_vector();
			int id=t.locate(m_param);
			if(m_param-t[id]<=t[id+1]-m_param)
				id-=1;
			//id is the id of MGBPointSeq to move.
			MGBPointSeq& bp=m_lbrep->line_bcoef();
			const double* destData=dest.data();
			bp.store_at(id,destData);//Update the target point.

			if(Ps == Pe){//If closed polyline.
				int nm1=lb->bdim()-1;//id of last point of bp.
				if(id==0){
					bp.store_at(nm1,destData);
				}else if(id==nm1)
					bp.store_at(0,destData);
			}
		}else{
			///When usual LBRep.
			double fp[2];
			int mk = 1;
			if(m_param == ts){
				mk = 2;
				fp[0] = m_lbrep->param_e();
			}else if(m_param == te){
				mk = 2;
				fp[0] = m_lbrep->param_s();
			}
			lb->move(mk, m_param, dest, fp);
		}
		new_curve=lb;
	}
	return std::unique_ptr<MGCurve>(new_curve);
}

void MGCurveMoveTool::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	if(locates().empty()){
		return;
	}
	std::unique_ptr<MGCurve> tmpCrv=make_model(cursor());
	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	tmpCrv->drawWire(sgl);
}

bool MGCurveMoveTool::OnLocated(const MGLocateInfo& info){
	const LInfoVec& linfos=locates();
	if(linfos.size()==0){
		m_lbrep = nullptr;
		m_straight = nullptr;
		m_originalCurve=nullptr;;
	}else if(linfos.size()==1){//最初の移動対象の点が入力された場合
		const MGCurve* crv = dynamic_cast<const MGCurve*>(info.object());
		if(crv){
			const MGLBRep* lbrep = dynamic_cast<const MGLBRep*>(crv);
			const MGStraight* sl = dynamic_cast<const MGStraight*>(crv);
			if(lbrep || sl){
				m_lbrep = const_cast<MGLBRep*>(lbrep);
				m_straight = const_cast<MGStraight*>(sl);
				m_originalCurve=const_cast<MGCurve*>(crv);;
				m_param = info.curve_parameter();
			}else{
				cancel_last_locate();//Only MGLBRep or MGStraight is allowed.
			}
		}else{
			cancel_last_locate();//Only curve(MGLBRep or MGStraight) is allowed.
		}
	}
	if(linfos.size()<=1){
		return false;
	}

	// 移動後の点(Second point)が入力された
	std::unique_ptr<MGCurve> crvP=make_model(linfos[1]->point_world());
	replace_object(m_originalCurve, crvP.release());
	return OnCommandEnd(1);
}

void MGCurveMoveTool::prompt_message() const{
	if(locates().empty()){
		SetStatusMessage(IDS_PROMPT_CURVE_MOVE_POINT);
	}else{
		SetStatusMessage(IDS_PROMPT_DESTINATION);
	}
}
