/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
// EvalSSDevTool.cpp: MGEvalSSDevTool クラスのインプリメンテーション

#include "stdafx.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "EvalCmd/EvalSSDevTool.h"

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

MGEvalSSDevTool::MGEvalSSDevTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_EVAL_GAP){}

void MGEvalSSDevTool::set_member_data(
	const MGPickObjects& pobjs	//pobjs must be of MGFSurface.
){
	if(m_face1.is_null()){
		m_face1=pobjs[0];
		if(pobjs.size()<=1) return;
		m_face2=pobjs[1];
		return;
	}
	m_face2=pobjs[0];
}

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

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

	const MGPickObjects& cobjs=current_objects();
	if(is_breaking_command()){
		MGPickObjects surfs;
		cobjs.select_fsurfaces(surfs);
		set_member_data(surfs);
		if(!m_face2.is_null())
			draw_temporary(new MGEvalSSDevSysGL(m_face1,m_face2),false,false);
		return true;
	}
	if(resetCurrentObjects(mgAll_FSurface))
		set_member_data(cobjs);
	if(!m_face2.is_null()){
		return OnCommandEnd(1,false);
	}

	//select a face to evaluate.
	set_child_current_command(new MGEvalSSDevToolSObj(this));
	return false;
}

//////////////////////////////////////////////////////////
//

//Invoked when command is to terminate as a nomal end.
bool MGEvalSSDevTool::OnCommandEnd(
	UINT nIDS,
	bool erase_temporary_display
){
	if(!m_face1.is_null() && !m_face2.is_null()){
		MGPickObjects pobjs(m_face1);
		pobjs.push_back(m_face2);
		set_current_object(pobjs);
		draw_temporary(new MGEvalSSDevSysGL(m_face1,m_face2),false,false);
	}
	return MGCommandStateOwner::OnCommandEnd(1,false);
}

//display prompting message for face selection.
void  MGEvalSSDevTool::selection_message() const{
	if(m_face1.is_null())
		SetStatusMessage(IDS_PROMPT_SURFACE_NTH, 1);
	else
		SetStatusMessage(IDS_PROMPT_SURFACE_NTH, 2);
}

///////////////Object for transformation selection class/////////////
MGEvalSSDevToolSObj::MGEvalSSDevToolSObj(
	MGCommandStateOwner* owner
):MGSelectState(owner,MGSelectState::MULTIPLE_SELECT,mgAll_FSurface){;}

bool MGEvalSSDevToolSObj::initiate_tool(){
	MGSelectState::initiate_tool();
	state_owner()->selection_message();
	return false;
}

bool MGEvalSSDevToolSObj::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).
){
	MGEvalSSDevTool* owner=state_owner();
	if(owner->resetCurrentObjects(mgAll_FSurface))
		owner->set_member_data(current_objects());
	if(!owner->m_face2.is_null()){
		return owner->OnCommandEnd(1,false);
	}
	owner->selection_message();
	return false;
}

MGEvalSSDevSysGL::MGEvalSSDevSysGL(
	MGPickObject surf1, MGPickObject surf2
):mgSys2GL(ID_EVAL_GAP,surf1.top_object(),
	surf2.top_object()){;}

const MGFSurface* MGEvalSSDevSysGL::surf1()const{
	const MGGel* gel=object_id();
	if(gel){
		return dynamic_cast<const MGFSurface*>(gel);
	}else
		return 0;
}

const MGFSurface* MGEvalSSDevSysGL::surf2()const{
	const MGGel* gel=gel2();
	if(gel){
		return dynamic_cast<const MGFSurface*>(gel);
	}else
		return 0;
}

//Construct new object by copying to newed area.
//User must delete this copied object by "delete".
mgSysGL* MGEvalSSDevSysGL::clone()const{
	return new MGEvalSSDevSysGL(*this);
}

//Draw this Sysgl.
//This draw is used to draw the pictures for Undo(, Redo) operations.
#define INNER_POINT_NUMBER 10
void MGEvalSSDevSysGL::drawSysGL(){
	const MGFSurface* f1=surf1();
	const MGFSurface* f2=surf2();
	if(!f1 || !f2)
		return;

	std::vector<MGPosition> uvuvs;
	f1->eval_discrete_deviation(*f2, uvuvs, INNER_POINT_NUMBER, 1.0);////
	if(uvuvs.empty())
		return;

	// Paint the points of pos1[i] and pos2[i] cyan.
	const MGColor& clr1 = MGColor::get_instance(MGColor::Magenta);
	const MGColor& clr2 = MGColor::get_instance(MGColor::Cyan);
	for(auto& uvuvi: uvuvs){
		const MGPosition& pos1 = f1->eval(uvuvi[0],uvuvi[1]);
		const MGPosition& pos2 = f2->eval(uvuvi[2],uvuvi[3]);
		const MGPosition& posm = (pos1 + pos2) * .5;

		double gap=pos1.distance(pos2);
		MGUnit_vector N1=f1->unit_normal(uvuvi[0],uvuvi[1]);
		MGUnit_vector N2=f2->unit_normal(uvuvi[2],uvuvi[3]);
		if(N1%N2<0.) N2.negate();
		double fold=MGCL::radian_to_degree(N1.angle(N2));

		CString str;
		str.Format(IDS_FORMAT_SS_DEVIATION, gap, fold);
		drawString(str, posm);

		clr1.exec(*this);
		drawPoint(pos1);

		clr2.exec(*this);
		drawPoint(pos2);
	}
}
