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

/**
 * @file SurfExtend.cpp
 * @brief MGSurfExtendTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/Surface.h"
#include "Calc/mgcalc.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "GLSurfExtendDlg.h"
#include "SurfCmd/SurfExtend.h"

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

MGSurfExtendTool::MGSurfExtendTool(fugenDoc* pDoc)
: MGSelectState(pDoc,ID_SURFACE_EXTEND,
	MGSelectState::SINGLE_SELECT, // single-pick
	mgAll_Surface, MGSelectState::BOUNDARY_SELECT // edge-pick
){
	// ダイアログを準備する
	attachModelessDialogue<CGLSurfExtendDlg>(this);
}

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

bool MGSurfExtendTool::initiate_tool(){
	MGSelectState::initiate_tool();
	clear_pick_object();

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

std::unique_ptr<MGSurface> MGSurfExtendTool::calculate(){
	const MGSurface* tmp = m_sb.surface();
	if(!tmp) return std::unique_ptr<MGSurface>(nullptr);

	std::unique_ptr<MGSurface> surf(tmp->clone());

	double param;
	switch(m_sb.perimeter()){ // next to nothing thought
	case 0:
	case 2:
		param = (surf->param_s_u() + surf->param_e_u())*.5;
		break;
	case 1:
	case 3:
		param = (surf->param_s_v() + surf->param_e_v())*.5;
		break;
	}

	CGLSurfExtendDlg& dialog=*getSurfExtendDialog();
	double len = dialog.GetLength();
	if(::MGAZero(len)) return std::unique_ptr<MGSurface>(nullptr);
	double dk = dialog.GetVary();

	surf->extend(m_sb.perimeter(), param, len, dk); // extend
	return surf;
}

void MGSurfExtendTool::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	if(!m_spPreview.get())
		return;
	if(m_sb.perimeter() == -1)
		return;

	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	mgcalc::CreateDrawFunctor(sgl)(m_spPreview.get());
}

//Invoked when command is to terminate as a nomal end.
bool MGSurfExtendTool::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
){
	Execute();
	return MGSelectState::OnCommandEnd(1);
}

void MGSurfExtendTool::Execute(){
	std::unique_ptr<MGSurface> surf = calculate();
	if(surf.get())
		replace_object(m_sb.surface(), surf.release());
}

namespace
{
	double CalcLength(MGPickObjectSB& sb)
	{
		const MGSurface* target = sb.surface();
		ASSERT(target);

		int nMinId = 0, nMaxId = 2;
		switch(sb.perimeter()){
		case 1:
		case 3:
			nMinId = 1;
			nMaxId = 3;
			break;
		}

		const std::unique_ptr<MGCurve> minbc(target->perimeter_curve(nMinId));
		const std::unique_ptr<MGCurve> maxbc(target->perimeter_curve(nMaxId));
		return (minbc->length() + maxbc->length()) * .5;
	}
}

// Surface のエッジがピックされたら呼ばれることになっている
bool MGSurfExtendTool::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); // single-pick
	MGPickObjectSB* boundary = dynamic_cast<MGPickObjectSB*>(&objs.front());
	ASSERT(boundary);

	SetStatusMessage(IDS_PROMPT_LENGTH);

	// UI 的に不自然なのだが、
	// 曲線の全長の 1/5 程度の値をプリセット値とする。
	CGLSurfExtendDlg& dialog=*getSurfExtendDialog();
	m_sb = *boundary;
	dialog.SetLength(CalcLength(m_sb) * .2);
	dialog.UpdateData(FALSE);
	UpdateView();

	if(!dialog.IsWindowVisible()){
		CPoint pt;
		::GetCursorPos(&pt);
		pt.Offset(-4, -4);
		dialog.SetWindowPos(&CWnd::wndTop, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
	}

	return false; // この段階ではコマンドは終了しない
}

void MGSurfExtendTool::UpdateView(){
	m_spPreview = calculate();
	draw_temporary();
}

CGLSurfExtendDlg * MGSurfExtendTool::getSurfExtendDialog(){
	return static_cast<CGLSurfExtendDlg*>(getModelessDialogPointer());;
}