/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
/**
 * @file SurfBlendAll.cpp
 * @brief MGSurfBlendAllTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/LBRepEndC.h"
#include "mg/SBRepTP.h"
#include "fugenDoc.h"
#include "fugenView.h"
#include "SurfCmd/SurfBlendAll.h"
#include "GLBlendFuncDlg.h"
#include "Calc/mgcalc.h"

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

// MGSurfBlendAllTool

MGSurfBlendAllTool::MGSurfBlendAllTool(fugenDoc* pDoc)
: MGSelectState(pDoc,ID_SURFACE_FUNC_ALL,
		 SINGLE_SELECT, // single-pick
		 mgAll_Curve, NO_BOUNDARY_SELECT, PROHIBIT_UNSELECT), m_first(true)
{
	attachModelessDialogue<CGLBlendFuncDlg>(this);
}

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

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

	clear_pick_object();
	set_add_mode();
	// 最初のメッセージ
	prompt_message();
	return false;
}

//Build m_surf from the current dialogue data.
void MGSurfBlendAllTool::build_surf(){
	CGLBlendFuncDlg& dialog=*getBlendFuncDlg();
	dialog.UpdateData();

	double us = dialog.m_us;
	double ue = dialog.m_ue;
	MGLBRep blu;
	blend_curve(us, ue, blu);

	double vs = dialog.m_vs;
	double ve = dialog.m_ve;
	MGLBRep blv;
	blend_curve(vs, ve, blv);

	const MGLBRep* peris[4];
	extractConstPointerVec(m_perimeter, m_perimeter+4, peris);
	int	err = m_surf.buildByBlend(peris, &blu, &blv);
	if(err){
		CString str, strMsg;
		strMsg.Format(IDS_SURF_FUNC_ALL_FAILURE, err);
		str.Format(IDS_ERROR, strMsg);
		putInOutputWindow(str);
		return;
	}
}

void MGSurfBlendAllTool::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	build_surf();
	MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
	mgcalc::CreateDrawFunctor(sgl)(&m_surf);
}

//Invoked when command is to terminate as a nomal end.
bool MGSurfBlendAllTool::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_surf.sdim())//sdim()==0 means m_surf not initialized.
		add_object_to_current_group(m_surf.clone());
	return MGSelectState::OnCommandEnd(1);
}

// 曲線がピックされたらすぐに呼ばれる
bool MGSurfBlendAllTool::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).
){
	if(m_vmin_c.is_null()){
		m_vmin_c = objs.back();
		prompt_message();
		return false;
	}
	if(m_vmin_c.top_object() == objs.back().top_object()){
		objs.pop_back();
		prompt_message();
		return false;
	}
	
	if(m_umax_c.is_null()){
		m_umax_c =objs.back();
		prompt_message();
		return false;
	}
	if(m_umax_c.top_object() == objs.back().top_object()){
		objs.pop_back();
		prompt_message();
		return false;
	}
	
	if(m_vmax_c.is_null()){
		m_vmax_c = objs.back();
		prompt_message();
		return false;
	}
	if(m_vmax_c.top_object() == objs.back().top_object()){
		objs.pop_back();
		prompt_message();
		return false;
	}

	if(m_umin_c.is_null()){
		m_umin_c = objs.back();
	}

	// 曲線が4本来たのでperimeterを計算する
	const MGCurve* perim_org[4] = {
		dynamic_cast<const MGCurve*>(m_vmin_c.top_object()),
		dynamic_cast<const MGCurve*>(m_umax_c.top_object()),
		dynamic_cast<const MGCurve*>(m_vmax_c.top_object()),
		dynamic_cast<const MGCurve*>(m_umin_c.top_object()),
	};

	// 1 - check all corners of four perimeter curves
	if(rebuildCurveTrimDirectionUpdate(perim_org, m_perimeter))
		return OnCommandCanceled(IDS_SURF_FUNC_ALL_FAILURE);

	ASSERT(m_perimeter[0]->knot_vector() == m_perimeter[2]->knot_vector());
	ASSERT(m_perimeter[1]->knot_vector() == m_perimeter[3]->knot_vector());
	// カーブが4本たまったら
	// ダイアログボックスを表示する
	if(m_first){
		clear_pick_object();
		m_first = false;
		
		SetStatusMessage(IDS_PROMPT_PARAMETER);
		
		CPoint point;
		::GetCursorPos(&point);
		point.Offset(-4, -4);
		CGLBlendFuncDlg& dialog = *getBlendFuncDlg();
		dialog.SetWindowPos(&CWnd::wndTop, point.x, point.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);

		draw_temporary();
	}

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

void MGSurfBlendAllTool::blend_curve(double ds, double de, MGLBRep& b){
	MGBPointSeq bp(2, 1);
	MGPosition s(1), e(1);
	s(0) = 0.; e(0) = 1.;
	bp.store_at(0, s);
	bp.store_at(1, e);

	s(0) = ds; e(0) = de;
	MGLBRepEndC start(MGENDC_1D, s);
	MGLBRepEndC end(MGENDC_1D, e);

	MGKnotVector t(2, 2);
	t(0) = t(1) = 0.;
	t(2) = t(3) = 1.;

	MGNDDArray tau;
	tau.buildByKnotVector(t);

	b.buildByInterpolationEC(start, end, tau, bp);
}

void MGSurfBlendAllTool::prompt_message() const{
	UINT msgid = IDS_PROMPT_CURVE_UMIN;
	if(m_vmin_c.is_null()){
		msgid=IDS_PROMPT_CURVE_VMIN;
	}else if(m_umax_c.is_null()){
		msgid=IDS_PROMPT_CURVE_UMAX;
	}else if(m_vmax_c.is_null()){
		msgid=IDS_PROMPT_CURVE_VMAX;
	} else
		msgid = IDS_PROMPT_CURVE_UMIN;
	SetStatusMessage(msgid);
}

CGLBlendFuncDlg* MGSurfBlendAllTool::getBlendFuncDlg(){
	return static_cast<CGLBlendFuncDlg*>(getModelessDialogPointer());
}
