/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
/**
 * @file CurveRebuildTool.cpp
 * @brief MGRebuildTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/LBRep.h"
#include "mg/SBRep.h"
#include "mg/RSBRep.h"
#include "topo/Edge.h"
#include "topo/Loop.h"
#include "topo/Face.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "CurveCmd/CurveRebuildDlg.h"
#include "EditCmd/EditRebuildTool.h"
#include "SurfaceRebuildDlg.h"

#include "Calc/mgcalc.h"

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

// MGRebuildTool

MGRebuildTool::MGRebuildTool(fugenDoc* pDoc)
:MGSelectState(pDoc,ID_EDIT_REBUILD, MGSelectState::SINGLE_SELECT,mgAll_Object,
MGSelectState::NO_BOUNDARY_SELECT,MGSelectState::PROHIBIT_UNSELECT)
,m_target_to_select(mgAll_Object), m_curve(0), m_lbrep(0), m_rlbrep(0)
,m_face(0),m_surface(0), m_sbrep(0), m_rsbrep(0){}

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

bool MGRebuildTool::initiate_tool(){
	MGSelectState::initiate_tool();
	if(select_objects(current_objects())){
		if(calculate())
			return OnCommandEnd(1);
		else
			return OnCommandEnd(2);
	}
	clear_pick_object();// 強制的にクリア
	SetStatusMessage(IDS_PROMPT_REBUILD_SEL);// 最初のメッセージ
	return false;
}

bool MGRebuildTool::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).
){
	if(select_objects(objs)){
		if(calculate())
			return OnCommandEnd(1);
		else
			return OnCommandEnd(2);
	}
	clear_pick_object();// 強制的にクリア
	SetStatusMessage(IDS_PROMPT_REBUILD_SEL);// 最初のメッセージ
	return false;
}

///Rebuild curve
bool MGRebuildTool::rebuild_curve(){
	CCurveRebuildDlg dlg(this);
	if(dlg.DoModal() == IDCANCEL)
		return false;

	int reparaType,splineApprox;
	double error;
	double prange[2];
	size_t neworder;
	dlg.get_param(splineApprox,reparaType,error,neworder,prange);
	std::unique_ptr<MGCurve> curvenew=
		m_curve->rebuild(splineApprox,reparaType,error,(int)neworder,prange);
	replace_object(m_curve, curvenew.release());
	return true;
}

///Rebuild surface
bool MGRebuildTool::rebuild_surface(){
	CSurfaceRebuildDlg dlg(this);
	if(dlg.DoModal() == IDCANCEL){
		return false;
	}

	CWaitCursor crsrs;
	int reparaType,splineApprox;
	double error;
	double prange[4];
	int neworder[2];
	dlg.get_surf_param(splineApprox,reparaType,error,prange);

	neworder[0]=neworder[1]=4;//Set the new order 4(cubic spline)
	std::unique_ptr<MGSurface> srfnew;
	int reparaType2=reparaType;
	if(reparaType==3){
		reparaType2=1;
	}
	if(m_sbrep){
		std::unique_ptr<MGSBRep>
			nsrf=m_sbrep->rebuild(1,reparaType2,error,neworder);
		srfnew=std::unique_ptr<MGSurface>(nsrf.release());
	}else if(m_rsbrep){
		srfnew=m_rsbrep->rebuild(splineApprox,reparaType2,error,neworder);
	}else{
		srfnew=std::unique_ptr<MGSurface>(m_surface->clone());
	}
	if(reparaType==3){
		srfnew->change_range(1,prange[0],prange[1]);
		srfnew->change_range(0,prange[2],prange[3]);
	}
	replace_object(m_surface, srfnew.release());
	return true;
}

///Rebuild surface
bool MGRebuildTool::rebuild_face(){
	CSurfaceRebuildDlg dlg(this);
	if(dlg.DoModal() == IDCANCEL){
		return false;
	}

	CWaitCursor crsrs;
	int reparaType,splineApprox;
	double error;
	double prange[4];
	int neworder[2];
	//bool edgeRebuild,C1EdgeJoin,removeShortEdg;
	bool C1EdgeJoin;
	//double minimumEdgeLength;
	dlg.get_face_param(splineApprox,reparaType,error,prange,C1EdgeJoin);
	
	neworder[0]=neworder[1]=4;//Set the new order 4(cubic spline)
	std::unique_ptr<MGFace> fnew;
	if(m_sbrep){
		std::unique_ptr<MGFace>
			nsrf=m_face->rebuild(1,reparaType,error,neworder,prange);
		fnew=std::unique_ptr<MGFace>(nsrf.release());
	}else if(m_rsbrep){
		fnew=m_face->rebuild(splineApprox,reparaType,error,neworder,prange);
	}else{
		fnew=std::unique_ptr<MGFace>(m_face->clone());
	}
	//std::cout<<*fnew<<std::endl;

	//if(edgeRebuild){
		//Rebuild(remove short edges, or join C1 continuous edges);
		if(C1EdgeJoin){
			if(reparaType==3)
				reparaType=2;
			int nloops=fnew->number_of_loops();
			for(int i=0; i<nloops; i++){
				UniqueLoop& loopi=fnew->loop(i);
				loopi->join_C1_edges(reparaType);
			}
		}
	//}
	replace_object(m_face, fnew.release());
	return true;
}

///Perform the rebuild process.
///Function's return value is true if process was done, false if canceled.
bool MGRebuildTool::calculate(){
	CWaitCursor crsrs;
	SetStatusMessage(IDS_PROMPT_COMPUTE);
	MGObject* target=m_object.leaf_object();
	if(m_curve){
		return rebuild_curve();
	}else if(m_face){
		return rebuild_face();
	}else if(m_surface){
		return rebuild_surface();
	}
	return true;
}

bool MGRebuildTool::OnKeyDown(
	fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case 'a':
	case 'A':
		// Any type of obejects are allowed.
		m_target_to_select = mgAll_Object;
		break;
	case 'c':
	case 'C':
		// Curves are allowed.
		m_target_to_select = mgAll_Curve;
		break;
	case 's':
	case 'S':
		// Surfaces are allowed.
		m_target_to_select = mgAll_Surface;
		break;
	case 'f':
	case 'F':
		// Surfaces and Faces are allowed.
		m_target_to_select = mgAll_FSurface;
		break;
	default:;
	}
	set_gells_to_select(m_target_to_select);
	SetStatusMessage(IDS_PROMPT_REBUILD_SEL);
	return MGSelectState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

///Select the target objects from the cobjs into m_target_objects.
///Function's return value is true if some are selected, false if none.
bool MGRebuildTool::select_objects(const MGPickObjects& cobjs){
	MGPickObjects objects = cobjs.select(mgAll_Curve);
	if(!objects.empty()){
		m_object=objects.front();
		MGStraight* sl=dynamic_cast<MGStraight*>(m_object.leaf_object());
		if(sl){
			if(!sl->finite())
				objects.remove(mgAll_Straight);
		}
	}
	if(!objects.empty()){
		m_target_selected=mgAll_Curve;
	}else{
		objects = cobjs.select(mgAll_Surface);
		objects.remove(mgAll_Plane);
		objects.remove(mgAll_SPhere);
		objects.remove(mgAll_Cylinder);
		if(objects.empty()){
			objects = cobjs.select(mgAll_Face);
			if(objects.empty())
				return false;
			m_target_selected=mgAll_Face;
		}else{
			m_target_selected=mgAll_Surface;
		}
	}

	m_object=objects.front();
	MGObject* obj=m_object.leaf_object();
	if(m_target_selected==mgAll_Curve){
		m_curve=static_cast<MGCurve*>(obj);
		m_lbrep=dynamic_cast<MGLBRep*>(m_curve);
		if(!m_lbrep)
			m_rlbrep=dynamic_cast<MGRLBRep*>(m_curve);
	}else{
		if(m_target_selected==mgAll_Face){
			m_face=static_cast<MGFace*>(obj);
			m_surface=m_face->get_surface_pointer();
		}else{
			m_surface=static_cast<MGSurface*>(obj);
		}
		m_sbrep=dynamic_cast<MGSBRep*>(m_surface);
		if(!m_sbrep){
			m_rsbrep=dynamic_cast<MGRSBRep*>(m_surface);
			if(!m_rsbrep && m_target_selected==mgAll_Surface)
				return false;
		}
	}
	set_current_object(m_object,true);
	return true;
}
