/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
/**
 * @file SurfUntrim.cpp
 * @brief MGSurfUntrimTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "topo/Face.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "SurfCmd/SurfUntrim.h"
#include "topo/Loop.h"
#include "topo/Edge.h"
#include "Calc/curve.h"
#include "Undo/GelAddAction.h"
#include "Undo/GelReplaceAction.h"
#include "Undo/MultiActions.h"

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

// MGSurfUntrimTool

MGSurfUntrimTool::MGSurfUntrimTool(fugenDoc* pDoc, UINT nCmdID, bool bKeep)
	 : MGSelectState(
		 pDoc,
		 nCmdID,
		 SINGLE_SELECT,
		 mgAll_Face,
		 BOUNDARY_SELECT),
	   m_bKeep(bKeep)
{
}

MGCommandBase* MGSurfUntrimTool::initial_clone(fugenDoc* pDoc) const
{
	// 少々特殊な処理になる
	UINT nCmdUI=command_id();
	return new MGSurfUntrimTool(
		pDoc, nCmdUI, nCmdUI == ID_SURFACE_UNTRIM_EXTRACT);
}

bool MGSurfUntrimTool::initiate_tool(){
	MGSelectState::initiate_tool();
	if(resetCurrentObjects(mgAll_Face)){
		MGPickObject pobj(current_objects().front());
		MGFace* f=static_cast<MGFace*>(pobj.top_object());
		if(f->number_of_boundaries()==1 && f->hasOuterBoundaryLoop()){
			if(!calculate(pobj))
				return OnCommandEnd(3);
			// コマンド正常終了
			return OnCommandEnd(1);
		}
	}

	// 強制クリア
	clear_pick_object();
	// 最初のメッセージ
	prompt_message();
	return false;
}

bool MGSurfUntrimTool::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case 'k':
	case 'K':
		m_bKeep = !m_bKeep;
		prompt_message();
		return false;
	default:
		return MGSelectState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
	}
}

bool MGSurfUntrimTool::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(!calculate(objs[0])){
		// failed
		return OnCommandEnd(3);
	}
	// コマンド正常終了
	return OnCommandEnd(1);
}

bool MGSurfUntrimTool::calculate(MGGelPosition& pobj){
	MGFace* face=static_cast<MGFace*>(pobj.top_object());
	MGPickObjectFB* fb=dynamic_cast<MGPickObjectFB*>(&pobj);

	// First, obtain the parent boundary.
	const MGLoop* loop=0;
	if(fb) loop= fb->edge()->loop();
	const std::vector<UniqueLoop>& bnds=face->boundaries();
	int id=0;
	if(fb){
		MGFace::const_iterator cur=face->boundaryIterator(loop);
		id= (int)std::distance(bnds.begin(), cur);
	}

	fugenDoc* doc=document();
	//Save the old boundary if designated so.
	CMultiActions* act = new CMultiActions(doc);
	if(m_bKeep){
		std::unique_ptr<MGCurve> kept(mgcalc::create_curve(*face->loop(id)));
		act->push_back(new CGelAddAction(doc, make_gelpos(kept.release())));
	}

	MGObject* newf;
	if(bnds.size()>1){
		std::unique_ptr<MGFace> result(new MGFace(*face));
		// ループを取り除いたfaceを生成する
		result->erase_boundary(id);
		if(id == 0)
			result->make_outer_boundary();
		newf=result.release();
	}else{
		std::unique_ptr<MGSurface> result(face->surface()->copy_surface());
		newf=result.release();
	}
	newf->copy_appearance(*face);

		// モデルを置き換える
	MGGroup* grp=pobj.bottom_group();
	act->push_back(
		new CGelReplaceAction(
			doc, 
			MGGelPosition(grp,face),
			MGGelPosition(grp,newf)));
	act->Do();
	return true;
}

void MGSurfUntrimTool::prompt_message() const{
	CString strYesNo;
	strYesNo.LoadString(m_bKeep ? IDS_YES : IDS_NO);
	SetStatusMessage(IDS_PROMPT_SURFACE_UNTRIM, strYesNo);
}

// ファクトリー用
MGCommandBase* CreateSurfUntrimTool(fugenDoc* pDoc, UINT nCmdId)
{
	switch(nCmdId){
	case ID_SURFACE_UNTRIM:
		return new MGSurfUntrimTool(pDoc, nCmdId, false);
	case ID_SURFACE_UNTRIM_EXTRACT:
		return new MGSurfUntrimTool(pDoc, nCmdId, true);
	default:
		return 0;
	}
}
