/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */
/********************************************************************/
/**
 * @file CurveKnotInsertTool.cpp
 * @brief CurveKnotInsertTool.h の実装
 */
#include "stdafx.h"
#include "mg/Knot.h"
#include "mg/KnotArray.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "CurveCmd/CurveKnotInsertTool.h"

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

//////////////////////////////////////////////////////////////////////
// MGCurveKnotInsertTool

MGCurveKnotInsertTool::MGCurveKnotInsertTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_CURVE_INSERT_KNOT), m_curve(0){
}

//////////////////////////////////////////////////////////////////////
// TEMPLATE METHOD

//Invoked when command is to terminate as a nomal end.
bool MGCurveKnotInsertTool::OnCommandEnd(
	UINT nIDS,	//=0: erase the current message, and display no messages.
				//=1: display "xxxx" normally end.
				//otherwise: nIDS is a string id, and load the message from string table to display.
	bool erase_temporary_display
){
	MGObject* newobj = m_tmp.clone();
	replace_object(m_curve, newobj);
	return MGCommandStateOwner::OnCommandEnd(nIDS);
}

//set the curve data into this member variables.
void MGCurveKnotInsertTool::set_the_member_data(MGPickObjects& curves){
	MGObject* obj = curves.front().top_object();
	m_curve= static_cast<MGLBRep*>(obj);
	m_tmp = MGLBRep(*m_curve);
	draw_temporary();
}

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

bool MGCurveKnotInsertTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	if(resetCurrentObjects(mgAll_LBRep)){
		set_the_member_data(MGPickObjects(current_objects()));
		//Input a point.
		set_child_current_command(new MGCurveKnotInsertToolIPoint(this));
	}else{
		//select a curve to evaluate.
		set_child_current_command(new MGCurveKnotInsertToolSCurve(this));
	}
	return false;
}

/////////////// curve selection class/////////////
MGCurveKnotInsertToolSCurve::MGCurveKnotInsertToolSCurve(
	MGCommandStateOwner* owner
	):MGSelectState(owner,MGSelectState::SINGLE_SELECT,mgAll_LBRep)//single selection mode
{;}

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

	// 最初のメッセージ
	SetStatusMessage(IDS_PROMPT_CURVE);
	return false;
}

bool MGCurveKnotInsertToolSCurve::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).
){
	MGCurveKnotInsertTool* owner=state_owner();
	owner->set_the_member_data(objs);

	//Input a point.
	set_sibling_next_command(new MGCurveKnotInsertToolIPoint(owner));
	return false;
}

/////////////Point input class//////////////
MGCurveKnotInsertToolIPoint::MGCurveKnotInsertToolIPoint(MGCommandStateOwner* owner)
: MGLocateState(owner, LOCK_SNAP_ATTRIB, NO_RUBBER, POINT_IPDRAW){
	turn_on_knot();
	turn_on_near();
}

bool MGCurveKnotInsertToolIPoint::OnLocated(
	const MGLocateInfo& linfo
){
	const LInfoVec& locs=locates();
	size_t n=locs.size();
	MGKnotArray knots;
	for(size_t i=0; i<n; i++){
		const MGLocateInfo& linfo=*(locs[i]);
		knots.push_back(MGKnot(linfo.curve_parameter(),1));
	}

	MGCurveKnotInsertTool* owner=state_owner();
	owner->m_tmp=*(owner->m_curve);
	owner->m_tmp.addKnots(knots);
	return false;
}

bool MGCurveKnotInsertToolIPoint::initiate_tool(){
	MGLocateState::initiate_tool();
	SetStatusMessage(IDS_PROMPT_KNOT);
	return false;
}

void MGCurveKnotInsertToolIPoint::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	MGLBRep& lb=state_owner()->m_tmp;
	const MGKnotVector& t = lb.knot_vector();
	int n = t.bdim(), k=t.order();
	std::vector<MGPosition> ip;
	for(int i =k-1; i<=n; i++){
		if(i>=k && t[i] == t[i-1]) continue;
		ip.push_back(lb.eval(t[i]));
	}

	const MGColor& black=MGColor::get_instance(MGColor::Black);
	const MGColor& white=MGColor::get_instance(MGColor::White);

	sgl.drawPoints(black,white,ip);
	const MGColor& hd=MGColor::get_instance(MGColor::Honeydew);
	hd.exec(sgl);
	lb.drawWire(sgl);
}
