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

/**
 * @file LineNormal.cpp
 * @brief MGLineNormalTool クラスの実装
 */
#include "stdafx.h"
#include "mg/Straight.h"
#include "Calc/line.h"
#include "fugenView.h"
#include "Misc/UserPreference.h"
#include "CurveCmd/LineNormal.h"

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

// MGLineNormalTool

MGLineNormalTool::MGLineNormalTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_CURVE_LINE_NORMAL), m_surf(0), m_bBoth(false){
}

MGLineNormalTool::MGLineNormalTool(MGCommandStateOwner* owner)
: MGCommandStateOwner(owner->document()), m_surf(0), m_bBoth(false){
}

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

bool MGLineNormalTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	const UserPreference& pref = UserPreference::getInstance();
	m_bBoth = pref.GetBoolValue(upv_Curve_LineNormal_Both);

	// うまくいけば最初のstateをスキップできる
	resetCurrentObjects(mgAll_FSurface);
	const MGPickObjects& curobj = current_objects();
	if(curobj.size() == 1){
		const MGObject* obj = curobj.front().top_object();
		m_surf = obj->fsurface();
		// IPointからスタート
		set_child_current_command(new MGLineNormalIPoint(this));
	}else{
		// 1曲面を選択するところからスタート
		set_child_current_command(new MGLineNormalSSurf(this));
	}
	return false;
}

bool MGLineNormalTool::terminate_tool(bool cancel){
	UserPreference& pref = UserPreference::getInstance();
	pref.SetBoolValue(upv_Curve_LineNormal_Both, m_bBoth);

	return MGCommandStateOwner::terminate_tool(cancel);
}

std::unique_ptr<MGCurve> MGLineNormalTool::make_line(const MGPosition& P){
	if(m_baseline.get()){
		double t=m_baseline->closest(P);
		return std::unique_ptr<MGCurve>(mgcalc::create_line(
			m_baseline->root_point(), m_baseline->eval(t), m_bBoth).release());
	}else
		return nullptr;
}

// MGLineNormalSSurf
MGLineNormalSSurf::MGLineNormalSSurf(MGLineNormalTool* owner)
: MGSelectState(owner, MGSelectState::SINGLE_SELECT, mgAll_FSurface){
}

bool MGLineNormalSSurf::initiate_tool(){
	MGSelectState::initiate_tool();

	// 最初のメッセージ
	SetStatusMessage(IDS_PROMPT_SURFACE);
	return false;
}

bool MGLineNormalSSurf::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).
){
	MGLineNormalTool* owner = state_owner();
	owner->m_surf = dynamic_cast<const MGFSurface*>(objs.front().top_object());
	set_sibling_next_command(new MGLineNormalIPoint(owner));
	return false;
}

// MGLineNormalIPoint

MGLineNormalIPoint::MGLineNormalIPoint(MGLineNormalTool* owner)
:MGLocateOnObjects(owner->m_surf->object_pointer(),owner,UNLOCK_SNAP_ATTRIB,
	NO_RUBBER,POINT_IPDRAW){
}

bool MGLineNormalIPoint::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case 'b':
	case 'B':
		state_owner()->m_bBoth = !state_owner()->m_bBoth;
		break;
	default:;
	}
	return MGLocateOnObjects::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGLineNormalIPoint::OnLocated(const MGLocateInfo& info){
	MGLineNormalTool* owner = state_owner();
	const LInfoVec& linfos=locates();
	size_t np = linfos.size();
	if(np==0){
		owner->m_baseline.reset();
	}else if(np==1){
		// 面上チェック
		const MGPosition& posOnSurf = info.point_world();
		// 法線の基準線をセット
		MGVector v = owner->m_surf->unit_normal(info.parameter());
		owner->m_baseline =std::unique_ptr<MGStraight>(
			new MGStraight(MGSTRAIGHT_UNLIMIT, v, posOnSurf));
		set_only_on_object(false);
		clear_locate_objectives();
	}else if(np>=2){
		const MGPosition& P1=linfos[1]->point_world();
		std::unique_ptr<MGCurve> line=owner->make_line(P1);// 補正
		add_object_to_current_group(line.release());
		return owner->OnCommandEnd(1);
	}
	return false;
}

void MGLineNormalIPoint::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	std::unique_ptr<MGCurve> line=state_owner()->make_line(cursor());
	if(line.get()){
		MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
		line->drawWire(sgl);
	}
}

void MGLineNormalIPoint::prompt_message() const{
	switch(locates().size()){
	case 0:
		SetStatusMessage(IDS_PROMPT_LINE_START);
		break;
	case 1:
		{
			CString strYesNo;
			strYesNo.LoadString(state_owner()->m_bBoth ? IDS_YES : IDS_NO);
			SetStatusMessage(IDS_PROMPT_LINE_END, strYesNo);
		}
		break;
	}
}
