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

/**
 * @file LinePerp1Tool.cpp
 * @brief MGLinePerp1Tool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/CParam_list.h"
#include "mg/Straight.h"
#include "Calc/line.h"
#include "Calc/mgcalc.h"
#include "fugenView.h"
#include "Common/CommandStateOwner.h"
#include "CurveCmd/LinePerp1Tool.h"


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

// MGLinePerp1Tool

MGLinePerp1Tool::MGLinePerp1Tool(fugenDoc* pDoc)
: MGLocateState(pDoc,ID_CURVE_LINE_PERP1,NO_RUBBER,POINT_IPDRAW),
m_curve(nullptr), m_bBoth(false){
	// near が必須となる
	turn_on_near();
	turn_on_end();
}

MGLinePerp1Tool::MGLinePerp1Tool(MGCommandStateOwner* owner)
: MGLocateState(owner, UNLOCK_SNAP_ATTRIB, NO_RUBBER, POINT_IPDRAW),
m_curve(nullptr), m_bBoth(false){
	// near が必須となる
	turn_on_near();
	turn_on_end();
}

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

void MGLinePerp1Tool::fix_start_pos(){
	// m_param における垂線を評価、キャッシュしておく。
	MGVector dirD, dirT, dirN, dirB;
	m_curve->Frenet_frame2(m_param, dirD, dirT, dirN, dirB);

	m_line_fix.reset(new MGStraight(
		MGSTRAIGHT_UNLIMIT, dirN, m_curve->eval(m_param)));
}

void MGLinePerp1Tool::update_lines(const MGPosition& Plast){
	const LInfoVec& linfos=locates();
	if(linfos.empty()){
		// 1点目入力待ち
		// 一時描画をしない
		m_line.reset();
		m_line_t.reset();
		m_line_fix.reset();
	}else{
		// 2点目入力待ち or ラストロケート
		MGPosition endpos = Plast;
		if(m_line_fix.get()){
			// 1 点目が固定点の場合
			// 垂線上に cursor を投影した位置をもうひとつの端点とする。

			endpos = m_line_fix->eval(m_line_fix->closest(endpos));
			m_line = mgcalc::create_line(m_curve->eval(m_param), endpos, m_bBoth);
			m_line_t.reset();
		}else{
			const MGPosition& P0=linfos[0]->point_world();
			if(m_curve){
				std::pair<MGCurve*, MGCurve*> tmp = mgcalc::create_perp_line_ex(*m_curve, endpos, m_bBoth);
				m_line.reset(tmp.first);
				m_line_t.reset(tmp.second);
			}else{
				m_line.reset();
				m_line_t.reset();
			}
		}
	}
}

void MGLinePerp1Tool::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){
	update_lines(cursor());
	if(m_line_t.get()){
		MGColor::get_instance(MGColor::White).exec(sgl);
		m_line_t->drawWire(sgl);
	}
	if(m_line.get()){
		MGColor::get_instance(MGColor::SpringGreen).exec(sgl);
		m_line->drawWire(sgl);
	}
}

bool MGLinePerp1Tool::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	// 1点目入力待ち
	switch(nChar){
	case 'b':
	case 'B':
		m_bBoth = !m_bBoth;
		break;
	case 'f':
	case 'F':
		// 2点目入力待ち
		if(!locates().empty()){
			// 固定オプションを操作できる条件は、
			// 1 点目を既存曲線上点に指定してあること。
			if(m_curve)
				fix_start_pos();
		}
		break;
		default:;
	}
	return MGLocateState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
}

bool MGLinePerp1Tool::OnLocated(const MGLocateInfo& info){
	size_t np=locates().size();
	if(np==0){
		m_curve=nullptr;
	}else if(np == 1){
		// 1点目の入力チェック
		m_curve = dynamic_cast<const MGCurve*>(info.object());
		if(m_curve){
			// 1点目は曲線上にある
			m_param = info.curve_parameter();
		}else
			cancel_last_locate();
	}else{
		// 計算開始
		// 最終的な形状を決定して線分を生成する
		update_lines(locates().back()->point_world());

		// ドキュメント変更
		add_object_to_current_group(m_line.release());
		return OnCommandEnd(1);
	}
	return false;
}

void MGLinePerp1Tool::prompt_message() const{
	UINT nIDS = 0;
	CString strYesNo; strYesNo.LoadString(m_bBoth ? IDS_YES : IDS_NO);
	if(locates().empty()){
		// 1点目入力待ち
		nIDS = IDS_PROMPT_LINE_PERP1_START_BP;
	}else{
		// 2点目入力待ち
		if(m_line_fix.get()){
			nIDS = IDS_PROMPT_LINE_PERP1_END;
		}else{
			nIDS = IDS_PROMPT_LINE_PERP1_END_FP;
		}
	}
	ASSERT(nIDS);
	SetStatusMessage(nIDS,strYesNo);
}
