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

/**
 * @file CurveConvert.cpp
 * @brief MGCurveConvertTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "CurveCmd/CurveConvert.h"
#include "Calc/curve.h"
#include "GLInputRealDlg.h"
#include "Undo/GelAddAction.h"
#include "Undo/GelRemoveAction.h"
#include "Undo/MultiActions.h"
#include "Misc/UserPreference.h"

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

MGCommandBase* CreateCurveConvertTool(fugenDoc* pDoc, UINT nCmdID){
	return new MGCurveConvertTool(pDoc, nCmdID);
}

// MGCurveConvertTool

MGCurveConvertTool::MGCurveConvertTool(fugenDoc* pDoc, UINT nCmdID)
	 : MGSelectState(
		 pDoc,
		 nCmdID,
		 MGSelectState::MULTIPLE_SELECT,
		 mgAll_Curve),
	   m_azero(0.05),
	   m_lzero(1.0),
	   m_nIDS(1),
	   m_bPolyline(true),
	   m_bRemove(false)
{
	ASSERT(nCmdID == ID_CURVE_CONVERT_LINE || nCmdID == ID_CURVE_CONVERT_ARC);
	m_bPolyline = (nCmdID == ID_CURVE_CONVERT_LINE);
}

MGCommandBase* MGCurveConvertTool::initial_clone(fugenDoc* pDoc)const{
	return new MGCurveConvertTool(pDoc, command_id());
}

bool MGCurveConvertTool::initiate_tool(){
	MGSelectState::initiate_tool();
	UserPreference& pref = UserPreference::getInstance();
	m_azero = pref.GetDoubleValue(upv_Curve_Convert_AngleZero);
	m_lzero = pref.GetDoubleValue(upv_Curve_Convert_LineZero);
	m_bRemove = pref.GetBoolValue(upv_Curve_Convert_Remove);

	// 選択モデルを選別
	current_object_is_valid(mgAll_Curve,m_curve);
	set_current_object(m_curve);
	prompt_message();
	return false;
}

bool MGCurveConvertTool::terminate_tool(bool cancel)
{
	UserPreference& pref = UserPreference::getInstance();
	pref.SetDoubleValue(upv_Curve_Convert_AngleZero, m_azero);
	pref.SetDoubleValue(upv_Curve_Convert_LineZero, m_lzero);
	pref.SetBoolValue(upv_Curve_Convert_Remove, m_bRemove);

	return MGSelectState::terminate_tool(cancel);
}

bool MGCurveConvertTool::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case 'a':
	case 'A':{// 角度許容差の設定
			CGLInputRealDlg dlg;
			dlg.SetValue(m_azero);
			if(IDOK == dlg.DoModal()){
				double d = dlg.GetValue();
				if(d > 0){
					m_azero = d;
				}
			}
		}
		break;
	case 'd':
	case 'D':
		// 削除フラグの変更
		m_bRemove = !m_bRemove;
		break;
	case 't':
	case 'T':{// 許容差の設定
			CGLInputRealDlg dlg;
			dlg.SetValue(m_lzero);
			if(IDOK == dlg.DoModal()){
				double d = dlg.GetValue();
				if(d > 0){
					m_lzero = d;
				}
			}
		}
		break;
	case VK_RETURN:
		if(m_curve.empty()){
			// 曲線の選択が決定したのか
			if(current_object_is_valid(mgAll_Curve,m_curve)){
				set_current_object(m_curve);
			}else{
				// 単なるキャンセル
				return OnCommandEnd(m_nIDS);
			}
		}
		// 計算開始
		if(!calculate()){
			// failed
			return OnCommandEnd(m_nIDS);
		}
		return OnCommandEnd(1);
	default:;
	}
	draw_temporary();
	prompt_message();
	return MGSelectState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGCurveConvertTool::calculate(){
	ASSERT(m_azero > 0);
	ASSERT(m_lzero > 0);
	if(m_curve.empty()){
		// キャンセル
		return false;
	}
	
	SetStatusMessage(IDS_PROMPT_COMPUTE);
	CWaitCursor sandglass;

	// 1. すべての曲線を変換
	std::vector<MGCurve*> crvs;
	MGPickObjects::iterator first = m_curve.begin(), last = m_curve.end();
	for(; first != last; ++first){
		std::unique_ptr<MGCurve> cnv;
		const MGCurve& curve = *dynamic_cast<const MGCurve*>((*first)->top_object());
		if(m_bPolyline){
			cnv=mgcalc::convert_to_polyline(curve,m_azero,m_lzero);
		}else{
			// see #519: 提供しない。
			//cnv=mgcalc::convert_to_joined_arc(curve,m_azero,m_lzero);
		}
		if(cnv.get()){
			crvs.push_back(cnv.release());
		}
	}

	if(crvs.empty()){
		// failed
		m_nIDS = IDS_FAIL_CONVERT_CURVE;
		return false;
	}

	// 2. ドキュメント変更
	if(m_bRemove){
		fugenDoc* doc=document();
		MGGroup* grp=current_group();
		// 少しややこしい
		CMultiActions* act = new CMultiActions(doc);
		// 2.1. オリジナルを削除
		act->push_back(new CGelRemoveAction(doc, m_curve));
		// 2.2. 変換曲線を追加
		act->push_back(new CGelAddAction(doc,make_gelpos(crvs.begin(),crvs.end(),grp)));
		// 2.3. アクション
		act->Do();
	}else{
		addGelsToCurrentGroup(crvs.begin(), crvs.end());
	}
	
	return true;
}

void MGCurveConvertTool::prompt_message() const{
	if(m_curve.empty()){
		SetStatusMessage(IDS_PROMPT_CURVE);
	}else{
		CString strYesNo;
		strYesNo.LoadString(m_bRemove ? IDS_YES : IDS_NO);

		SetStatusMessage(
			IDS_PROMPT_CURVE_CONVERT,
			strYesNo,
			m_azero,
			m_lzero);
	}
}
