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

/**
 * @file EditSplitTool.cpp
 * @brief EditSplitTool.h の実装
 */
#include "stdafx.h"
#include "Calc/mgcalc.h"
#include "fugenView.h"
#include "EditCmd/editfunc.h"
#include "SurfCmd/SplitLocateIsocurves.h"

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

// MGSplitLocateIsocurves
//////////////////////////////////////////////////////////////////////
// [S6] MGSplitLocateIsocurves
//

MGSplitLocateIsocurves::MGSplitLocateIsocurves(
MGCommandStateOwner* owner, MGPickObject& target)
: MGLocateOnObjects(owner,
LOCK_SNAP_ATTRIB//Prohibit to update snap attrib
),m_direction(0),m_target(target){
	turn_on_vertex();
	turn_on_center();
}

bool MGSplitLocateIsocurves::initiate_tool(){
	set_locate_objectives(m_target.top_object());
	MGLocateOnObjects::initiate_tool();
	return false;
}

const MGFSurface* MGSplitLocateIsocurves::GetSplitTargetSurf()const{
	return m_target.top_object()->fsurface();
}

bool MGSplitLocateIsocurves::OnKeyDown(
	fugenView* window, UINT nChar, UINT nRepCnt, UINT nFlags
){
	switch(nChar){
	case 'b':
	case 'B':
		// U と V いっぺんに
		m_direction=2;
		break;
	case 'u':
	case 'U':
		// U 一定のアイソカーブ
		m_direction=0;
		break;
	case 'v':
	case 'V':
		// V 一定のアイソカーブ
		m_direction=1;
		break;
	case VK_RETURN:
		if(updateModel())
			return MGLocateOnObjects::OnCommandEnd(1);
		else
			return MGLocateOnObjects::OnCommandEnd(3);
	default:;
	}
	return MGLocateOnObjects::OnKeyDown(window, nChar, nRepCnt, nFlags);
}

bool MGSplitLocateIsocurves::OnLocated(const MGLocateInfo& info){
	if(info.is_deleted()){
		RemoveSplitParam();
	}else{
		// ロケートされたアイソカーブで分割するので、
		// U/V の種類とパラメータをすべて記憶する。
		const MGPosition& par = info.parameter();
		AddSplitParam(par, m_direction);
	}
	return false;
}

void MGSplitLocateIsocurves::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	const MGFSurface* f=dynamic_cast<MGFSurface*>(snappedObject());
	if(f==GetSplitTargetSurf()){
		ASSERT(f);
		const MGPosition& uv=snappedParam();
	
		// 一時描画用
		if(m_direction==0||m_direction==2){
			// Vカーブを描く
			std::vector<UniqueCurve> isocurves_work = f->parameter_curves(true, uv[0]);
			DrawIsocurves(MGColor::get_instance(MGColor::SpringGreen),isocurves_work,sgl,pView);
		}
		if(m_direction==1||m_direction==2){
			// Uカーブを描く
			std::vector<UniqueCurve> isocurves_work = f->parameter_curves(false, uv[1]);
			DrawIsocurves(MGColor::get_instance(MGColor::SpringGreen),isocurves_work,sgl,pView);
		}
	}
	DrawIsocurves(MGColor::get_instance(MGColor::DeepPink), m_preview_isocurves, sgl, pView);
}

void MGSplitLocateIsocurves::AddSplitParam(const MGPosition& uv, int direction){
	m_paramKinds.push_back(direction);
	m_params.push_back(uv);
	if(direction!=1)
		AddPreviewCurves(uv,true);
	if(direction!=0)
		AddPreviewCurves(uv,false);
}

void MGSplitLocateIsocurves::AddPreviewCurves(const MGPosition& uv, bool isU){
	double t=isU ? uv[0]:uv[1];
	const MGFSurface* surf = GetSplitTargetSurf();

	// プレビューデータを更新
	std::vector<UniqueCurve> preview(surf->parameter_curves(isU, t));
	std::move(preview.begin(), preview.end(), std::back_inserter(m_preview_isocurves));
}

void MGSplitLocateIsocurves::RemoveSplitParam(){
	m_paramKinds.pop_back();
	m_params.pop_back();
	resetPreview();
}
void MGSplitLocateIsocurves::resetPreview(){
	m_preview_isocurves.erase(m_preview_isocurves.begin(), m_preview_isocurves.end());
	size_t n=m_params.size();
	for(size_t i=0; i<n; i++){
		AddSplitParam(m_params[i],m_paramKinds[i]);
	}
}

void MGSplitLocateIsocurves::DrawIsocurves(
	const MGColor& color,
	std::vector<UniqueCurve>& curves,mgSysGL& sgl,fugenView* pView
){
	// これまでの確定分
	sgl.setStaticAttribColor(color);
	auto drawObj = mgcalc::CreateDrawFunctor(sgl);
	for (auto& curve : curves)
		drawObj(curve.get());
}

void MGSplitLocateIsocurves::prompt_message()const{
	CString strUV;
	if(m_direction==2){
		strUV = _T("U&V");
	}else if(m_direction==0){
		strUV = _T("U");
	}else{
		strUV = _T("V");
	}
	CString str;
	str.Format(IDS_PROMPT_SURFACE_KNOT_BOTH, strUV);

	SetStatusMessage(str);
}

//Update the model from m_paramKinds, m_params.
//Return value is true: successfully updated, false not.
bool MGSplitLocateIsocurves::updateModel(){
	const MGFSurface& surf = *GetSplitTargetSurf();

	size_t nuv=m_params.size();
	if(!nuv){
		// 分割位置がまったく指定されていないのでキャンセル扱い
		return false;
	}

	std::vector<bool> paramKinds;
	std::vector<double> params;
	for(size_t i=0; i<nuv; i++){
		int dir=m_paramKinds[i];
		if(dir==0 || dir==2){
			bool isU=true;
			paramKinds.push_back(isU);
			params.push_back(m_params[i][0]);
		}
		if(dir==1 || dir==2){
			bool isU=false;
			paramKinds.push_back(isU);
			params.push_back(m_params[i][1]);
		}
	}
	const size_t nRes = ExecSplitSurfByIsocurves(m_target, paramKinds, params, *this);
	CString str;
	str.Format(IDS_SPLIT_RESULT_BY_ISOCURVES, 1, nRes);
	COUT << (TCAST)str << std::endl;

	return true;
}
