/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
/**
 * @file SurfSweepToPointTool.cpp
 * @brief MGSurfSweepToPointTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "fugenDoc.h"
#include "SurfCmd/SurfSweepToPointTool.h"
#include "Calc/surface.h"

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

// MGSurfSweepToPointTool

MGSurfSweepToPointTool::MGSurfSweepToPointTool(fugenDoc* pDoc)
	 : MGCommandStateOwner(pDoc, ID_SURFACE_EXTRUDE_TO_POINT)
{
}

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

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

	// すでに曲線が一本だけ選択されている場合は
	// indicate state にスキップ
	if(resetCurrentObjects(mgAll_Curve)
	   && current_objects().size() == 1){
		const MGPickObjects& objs = current_objects();
		ASSERT(objs.size() == 1);
		ASSERT(dynamic_cast<const MGCurve*>(objs.front().top_object()));
		m_curve = objs.front();
		set_child_current_command(new MGSurfSweepToPointIPoint(this));
	}
	else{
		// 曲線を選ばせるところからコマンドスタート
		set_child_current_command(new MGSurfSweepToPointSCurve(this));
	}

	return false;
}

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

bool MGSurfSweepToPointTool::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
){
	if(m_curve.is_null() || m_position.is_null()){
		// みなしキャンセル
		return OnCommandCanceled(1);
	}
	// スイープ面を作成
	const MGCurve* c = dynamic_cast<const MGCurve*>(m_curve.top_object());
	std::unique_ptr<MGSurface> swept(mgcalc::create_sweep_surface(*c, m_position));
	if(!swept.get()){
		// failed
		return OnCommandCanceled(1);
	}
	
	MGGelPosition gelp(m_curve.bottom_group(),swept.release());
	add_object_to_document(gelp);
	
	return MGCommandStateOwner::OnCommandEnd(1);
}

// MGSurfSweepToPointSCurve

MGSurfSweepToPointSCurve::MGSurfSweepToPointSCurve(MGCommandStateOwner* owner)
	 : MGSelectState(
		 owner,
		 MGSelectState::SINGLE_SELECT, // single pick
		 mgAll_Curve)
{
}

bool MGSurfSweepToPointSCurve::initiate_tool(){
	MGSelectState::initiate_tool();
	clear_pick_object();
	// 最初のメッセージ
	SetStatusMessage(IDS_PROMPT_SWEEP_CURVE);
	return false;
}

// 曲線がピックされたらここが呼ばれる
bool MGSurfSweepToPointSCurve::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).
){
	ASSERT(objs.size() == 1);
	ASSERT(dynamic_cast<const MGCurve*>(objs.front().top_object()));

	// カーブをセットして次の state へ移る
	ASSERT(state_owner());
	ASSERT(state_owner()->m_curve.is_null());
	state_owner()->m_curve = objs.front();

	set_sibling_next_command(new MGSurfSweepToPointIPoint(state_owner()));
	return false; // why false?
}

// MGSurfSweepToPointIPoint

MGSurfSweepToPointIPoint::MGSurfSweepToPointIPoint(MGCommandStateOwner* owner)
: MGLocateState(owner, 
LOCK_SNAP_ATTRIB,//Prohibit to update snap attrib
NO_RUBBER, POINT_IPDRAW){
}

bool MGSurfSweepToPointIPoint::initiate_tool(){
	MGLocateState::initiate_tool();

	// 曲線を選択後、最初のメッセージ
	SetStatusMessage(IDS_PROMPT_DEGENERATE_POINT);
	return false;
}

// ここには一度しかこないはず
bool MGSurfSweepToPointIPoint::OnLocated(const MGLocateInfo& info){
	ASSERT(current_objects().size() == 1);
	ASSERT(state_owner());
	ASSERT(state_owner()->m_position.is_null());
	state_owner()->m_position = info.point_world();

	// 計算開始
	return state_owner()->OnCommandEnd(1);
}
