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

/**
 * @file CurveParamLineTool.cpp
 * @brief MGCurveParamLineTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/Point.h"
#include "mg/Plane.h"
#include "Calc/curve.h"
#include "Calc/mgcalc.h"
#include "ParamLineDlg.h"
#include "Misc/UserPreference.h"
#include "Common/LocateOnObjects.h"
#include "CurveCmd/CurveParamLineTool.h"

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

// MGCurveParamLineTool

MGCurveParamLineTool::MGCurveParamLineTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc,ID_CURVE_ISOPARAM),m_surf(0){
}

bool MGCurveParamLineTool::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
){
	// m_result を 移し変える

	// ドキュメント変更
	size_t n=m_result.size();
	for(size_t i=0; i<n; i++){
		addUniqueGelsToCurrentGroup(m_result[i].begin(), m_result[i].end());
	}
	return MGCommandStateOwner::OnCommandEnd(1);
}

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

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

	// 曲面オブジェクトの選択状態をチェック
	resetCurrentObjects(mgAll_FSurface);
	const MGPickObjects& curobj = current_objects();
	if(curobj.size() == 1){
		const MGObject* obj = curobj.front().top_object();
		if(!dynamic_cast<const MGPlane*>(obj)){
			m_surf = dynamic_cast<const MGFSurface*>(obj);
			// パラメータ位置指定から開始
			set_child_current_command(new MGParamLineIPoint(this));
			return false;
		}
	}

	// 曲面選択から開始
	set_child_current_command(new MGParamLineSSurf(this));
	return false;
}

// MGParamLineSSurf

MGParamLineSSurf::MGParamLineSSurf(MGCurveParamLineTool* owner)
: MGSelectState(owner, MGSelectState::MULTIPLE_SELECT, // multiple
mgAll_FSurface){
}

bool MGParamLineSSurf::initiate_tool(){
	MGSelectState::initiate_tool();
	clear_pick_object(); // 1個の平面が選択されている可能性があるのでクリア
	// 最初のメッセージ
	prompt_message();
	SetStatusMessage(IDS_PROMPT_SURFACE);
	return false;
}

bool MGParamLineSSurf::OnSelected(
	fugenView* pView,
	MGPickObjects& curobj,
	MGPickObjects&
){
	ASSERT(curobj.size() == 1);
	MGCurveParamLineTool* owner = state_owner();
	owner->m_surf = dynamic_cast<const MGFSurface*>(curobj.front().top_object());
	ASSERT(owner->m_surf);

	// パラメータ入力状態へ遷移
	set_sibling_next_command(new MGParamLineIPoint(owner));
	return false;
}

void MGParamLineSSurf::prompt_message() const{
	SetStatusMessage(IDS_PROMPT_SURFACE);
}

// MGParamLineIPoint

MGParamLineIPoint::MGParamLineIPoint(MGCurveParamLineTool* owner)
: MGLocateOnObjects(owner->m_surf->object_pointer(),owner,
LOCK_SNAP_ATTRIB,  // 面上限定オプション希望
NO_RUBBER, POINT_IPDRAW), m_bU(true){
	turn_on_vertex();
	turn_on_center();
}

MGParamLineIPoint::~MGParamLineIPoint(){
}

bool MGParamLineIPoint::initiate_tool(){
	MGLocateOnObjects::initiate_tool();
	UserPreference& pref = UserPreference::getInstance();
	m_bU = pref.GetBoolValue(upv_Curve_ParamLine_UV);
	return false;
}

bool MGParamLineIPoint::terminate_tool(bool cancel){
	UserPreference& pref = UserPreference::getInstance();
	pref.SetBoolValue(upv_Curve_ParamLine_UV, m_bU);

	return MGLocateState::terminate_tool(cancel);
}

bool MGParamLineIPoint::OnKeyDown(
	fugenView* pView,
	UINT           nChar,
	UINT           nRepCnt,
	UINT           nFlags
){
	MGCurveParamLineTool* owner = state_owner();
	switch(nChar){
	case 'd':
	case 'D':
		// パラメータカーブの方向をチェンジ
		m_bU = !m_bU;
		break;
	case 'p':
	case 'P':{
		// 数値入力
			const MGFSurface& surf = *owner->m_surf;

			// パラメータの指定が妙に面倒
			const MGBox& range = surf.box_param2();

			CGLParamLineDlg dlg;
			dlg.SetCaption(range[0].low_point(), range[0].high_point(), true);
			dlg.SetCaption(range[1].low_point(), range[1].high_point(), false);
			dlg.SetLimit(
				range[0].low_point(),
				range[0].high_point(),
				range[1].low_point(),
				range[1].high_point());

			if(IDOK == dlg.DoModal()){
				owner->m_result.push_back(surf.parameter_curves(dlg.m_nRadio,dlg.m_dParam));
			}
		}
		break;
	default:;
	}

	// そして再描画
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGParamLineIPoint::OnLocated(const MGLocateInfo& info){
	MGCurveParamLineTool* owner = state_owner();
	if(info.is_deleted()){
		owner->m_result.pop_back();
	}else{
		// マウスポインタが面上にあるか...
		const MGFSurface& surf = *owner->m_surf;
		MGPosition uv;
		MGLocateInfo& cinf=*locates().back();
		auto sk=cinf.snap_kind();
		if(cinf.object()){
				uv=cinf.parameter();
				assert(surf.object_pointer() == cinf.object());
		}
		// カーブを追加
		double param = m_bU ? uv[1] : uv[0];
		owner->m_result.push_back(surf.parameter_curves(!m_bU, param));
	}

	// そして再描画
	return false;
}

void MGParamLineIPoint::prompt_message() const{
	CString strUV;
	strUV.LoadString(m_bU ? IDS_PARAM_U : IDS_PARAM_V);
	SetStatusMessage(IDS_PROMPT_ISOPARAM, strUV);
}

void MGParamLineIPoint::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);

	MGCurveParamLineTool* owner = state_owner();
	const MGFSurface& surf = *owner->m_surf;
	auto drawObj = mgcalc::CreateDrawFunctor(sgl);

	// マウスポインタが面上を動いているかチェック
	if(snappedObject()==surf.object_pointer()){
		MGPosition uv=snappedParam();
		// 一時描画用
		// 現在マウスで動かしているものを描画
		double param = m_bU ? uv[1] : uv[0];
		auto& crvs =owner->m_tmp= surf.parameter_curves(!m_bU, param);
		for (auto& crv : crvs)
			drawObj(crv.get());
	}

	// 既に決まっているものを描画
	auto& result=owner->m_result;
	size_t n=result.size();
	for(size_t i=0; i<n; i++){
		std::vector<UniqueCurve>::iterator j = result[i].begin(), jend = result[i].end();
		for (; j != jend; j++)
			drawObj(j->get());
	}
}
