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

/**
 * @file SurfQuadGCon.cpp
 * @brief SurfQuadGCon.h の実装
 */
#include "stdafx.h"
#include "mg/Straight.h"
#include "mg/SBRep.h"
#include "mg/SBRepVecTP.h"
#include "Calc/mgcalc.h"
#include "Calc/surface.h"
#include "fugenDoc.h"
#include "SurfCmd/SurfQuadGCon.h"

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

// MGSurfQuadGConTool

MGSurfQuadGConTool::MGSurfQuadGConTool(fugenDoc* pDoc)
:MGCommandStateOwner(pDoc, ID_SURFACE_QS),m_perimNum(0){
}

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

bool MGSurfQuadGConTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	m_perimNum = 0;	// 強制クリア
	clear_pick_object();// 曲線選択からスタート
	set_child_current_command(new MGSurfQuadGConSCurve(this));
	return false;
}

bool MGSurfQuadGConTool::OnCommandCanceled(UINT nIDS){
	clear_pick_object();
	return MGCommandStateOwner::OnCommandCanceled(nIDS);
}


bool MGSurfQuadGConTool::calculate(){
	const MGCurve* perim_org[4];
	for(int i=0; i<4; i++)
		perim_org[i] = dynamic_cast<const MGCurve*>(m_perims[i].top_object());
	
	// convert MGPickObject(tangent faces) to MGFSurface
	std::vector<const MGFSurface*> faces[4];
	for (int i = 0; i < 4; i++) {
		MGPickObjects& tangentFaces = m_tangentFace[i];
		size_t n = tangentFaces.size();
		std::vector<const MGFSurface*>& facesi = faces[i];
		facesi.resize(n);
		for (size_t j = 0; j < n; j++)
			facesi[j] = dynamic_cast<const MGFSurface*>(tangentFaces[j].top_object());
	}

	// Convert side curves to valid perimeters.
	std::unique_ptr<MGLBRep> perimeters[4];
	if(rebuildCurveTrimDirectionUpdate(perim_org, perimeters))
		return false;	

	// TPを求める
	MGSBRepTP tp; tp.build(perimeters, faces);

	// 面を生成する
	std::unique_ptr<MGSBRep> surf(new MGSBRep);
	surf->buildFromSidesBoolSumWithTP(perimeters, tp);
	add_object_to_current_group(surf.release());	
	return true;
}

// MGSurfQuadGConSCurve

MGSurfQuadGConSCurve::MGSurfQuadGConSCurve(MGSurfQuadGConTool* owner)
:MGSelectState(owner, MGSelectState::SINGLE_SELECT, mgAll_Curve){
}

bool MGSurfQuadGConSCurve::initiate_tool(){
	MGSelectState::initiate_tool();
	prohibit_unselect();
	set_add_mode();
	// メッセージ更新
	prompt_message();
	return false;
}

bool MGSurfQuadGConSCurve::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).
){
	MGSurfQuadGConTool* owner = state_owner();
	int& perimNum = owner->m_perimNum;

	MGPickObject& c = objs.back();
	if (perimNum < 4) {
		MGPickObject* perims = owner->m_perims;
		perims[perimNum] = c;
		lock_so_far();
		set_sibling_next_command(new MGSurfQuadGConSSurf(owner));
		return false;
	}
	lock_so_far();
	
	if (!owner->calculate()) {// 計算開始
		return OnCommandCanceled(1);
	}
	// コマンド終了
	return OnCommandEnd(1);
}

void MGSurfQuadGConSCurve::prompt_message() const{
	const MGSurfQuadGConTool* owner = state_owner();
	int perimNum = owner->m_perimNum;

	static const UINT msg[4] = { IDS_PROMPT_QS_CURVE_VMIN ,IDS_PROMPT_QS_CURVE_UMAX ,
					IDS_PROMPT_QS_CURVE_VMAX, IDS_PROMPT_QS_CURVE_UMIN };
	SetStatusMessage(msg[perimNum]);
}

// MGSurfQuadGConSSurf

MGSurfQuadGConSSurf::MGSurfQuadGConSSurf(MGSurfQuadGConTool* owner)
: MGSelectState(owner, MGSelectState::MULTIPLE_SELECT, mgAll_FSurface){
}

bool MGSurfQuadGConSSurf::initiate_tool(){
	MGSelectState::initiate_tool();
	set_add_mode();
	// メッセージ更新
	prompt_message();
	return false;
}

bool MGSurfQuadGConSSurf::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	MGSurfQuadGConTool* owner = state_owner();
	int& perimNum = owner->m_perimNum;

	switch(nChar){
	case VK_RETURN: {
		// VK_RETURN のときは接続面を確定する処理とみなす必要がある
		perimNum++;
		if (perimNum >= 4) {
			// ダイアログボックスとか
			// 計算開始
			if (!owner->calculate()) {
				return OnCommandCanceled(1);
			}
			// コマンド終了
			return OnCommandEnd(1);
		}else {
			lock_so_far();
			set_sibling_next_command(new MGSurfQuadGConSCurve(owner));
			prompt_message();
			return false;
		}
	}
	default:;
	}
	prompt_message();
	return MGSelectState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGSurfQuadGConSSurf::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).
){
	MGSurfQuadGConTool* owner = state_owner();
	MGPickObjects& tangentFaces = owner->m_tangentFace[owner->m_perimNum];
	if (!objs.empty())
		tangentFaces += objs;
	if (!unselected_objects.empty())
		tangentFaces -= unselected_objects;
	lock_so_far();
	return false;
}

void MGSurfQuadGConSSurf::prompt_message() const{
	const MGSurfQuadGConTool* owner = state_owner();
	int periNum = owner->m_perimNum;
	if (periNum < 4) {
		static const UINT msg[4] = { IDS_PROMPT_QS_SURFACE_VMIN ,IDS_PROMPT_QS_SURFACE_UMAX ,
						IDS_PROMPT_QS_SURFACE_VMAX, IDS_PROMPT_QS_SURFACE_UMIN };
		SetStatusMessage(msg[periNum]);
	}
}
