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

/**
 * @file SurfSweepRibbon.cpp
 * @brief MGSurfSweepRibbonTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/Straight.h"
#include "mg/SBRep.h"
#include "mg/LBRep.h"
#include "mg/CSisects.h"
#include "fugenView.h"
#include "SurfCmd/SurfSweepRibbon.h"

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

// class MGSurfSweepRibbonTool

MGSurfSweepRibbonTool::MGSurfSweepRibbonTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc, ID_SURFACE_EXTRUDE_RIBBON), m_curve(0){
}

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

bool MGSurfSweepRibbonTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	if(resetCurrentObjects(mgAll_Curve)
	   && current_objects().size() == 1){
		// オフセット位置決定ステートから
		m_curve = dynamic_cast<const MGCurve*>(current_objects().front().top_object());
		set_child_current_command(new MGSurfSweepRibbonIPoint(this));
	}else{
		// 曲線選択からスタート
		set_child_current_command(new MGSurfSweepRibbonSCurve(this));
	}
	return false;
}

bool MGSurfSweepRibbonTool::calculate(){
	if(m_perims.empty()){
		// 失敗
		return false;
	}else if(m_perims.size() == 1){
		UniqueCurve tmp2[2] = {
			std::unique_ptr<MGCurve>(new MGStraight(m_curve->start_point(), m_perims[0]->start_point())),
			std::unique_ptr<MGCurve>(new MGStraight(m_curve->end_point(), m_perims[0]->end_point()))
		};
		const MGCurve* tmp[4] = { tmp2[0].get(), m_curve, tmp2[1].get(), m_perims[0].get()};

		// m_curve, s2, c, s1 が囲む曲面を生成する...
		std::unique_ptr<MGLBRep> perim2[4];
		int ret = construct_perimeters(tmp, perim2);
		MGSBRep* srf = new MGSBRep; srf->buildGeneralizedRuledSurface(perim2,false);
		add_object_to_current_group(srf);
	}else{
		// 無理
		return false;
	}

	return true;
}

// class MGSurfSweepRibbonSCurve

MGSurfSweepRibbonSCurve::MGSurfSweepRibbonSCurve(MGSurfSweepRibbonTool* owner)
: MGSelectState(owner, MGSelectState::SINGLE_SELECT, mgAll_Curve){
}

bool MGSurfSweepRibbonSCurve::initiate_tool(){
	MGSelectState::initiate_tool();
	clear_pick_object();
	prompt_message();
	return false;
}

bool MGSurfSweepRibbonSCurve::OnSelected(
	fugenView* pView,
	MGPickObjects& objs,
	MGPickObjects& unobjs
){
	ASSERT(objs.size() == 1);
	const MGObject* obj = objs.front().top_object();
	ASSERT(obj);
	const MGCurve* curve = dynamic_cast<const MGCurve*>(obj);
	ASSERT(curve);
	
	// 曲線を記憶する
	MGSurfSweepRibbonTool* owner = state_owner();
	owner->m_curve = curve;

	// 次の state へ
	set_sibling_next_command(new MGSurfSweepRibbonIPoint(owner));
	return false;
}

void MGSurfSweepRibbonSCurve::prompt_message()const{
	SetStatusMessage(IDS_PROMPT_CURVE);
}

// class MGSurfSweepRibbonIPoint

MGSurfSweepRibbonIPoint::MGSurfSweepRibbonIPoint(MGSurfSweepRibbonTool* owner)
: MGLocateState(owner, 
LOCK_SNAP_ATTRIB,//Prohibit to update snap attrib
NO_RUBBER, POINT_IPDRAW){
	// 曲線にスナップ
	turn_on_near();
	turn_on_end();
}

bool MGSurfSweepRibbonIPoint::OnLocated(const MGLocateInfo& info){
	MGSurfSweepRibbonTool* owner = state_owner();
	ASSERT(owner->m_curve);

	const MGCurve& curve = *owner->m_curve;

	// 1. マウスカーソル位置における gluLookAt ビーム
	MGStraight ray;
	info.window()->unproject_to_sl(info.point_screen(), ray);

	// 2. 一番近い点
	MGPosition param = curve.closest(ray);
	MGPosition pos = curve.eval(param[0]);
	MGPosition ref = ray.eval(param[1]);

	// 曲面を生成...
	MGVector v1 = ref - pos;
	MGVector T, N, B;
	double curva, tors;
	curve.Frenet_frame(param[0], T, N, B, curva, tors);
	
	double len = v1 % N; // オフセット方向を考慮に入れてある

	owner->m_perims = curve.offset(len, B);

	if(!owner->calculate()){
		return OnCommandEnd(3);
	}
	return OnCommandEnd(1);
}

void MGSurfSweepRibbonIPoint::prompt_message() const{
	SetStatusMessage(IDS_PROMPT_LENGTH);
}


// マウスカーソルがターゲットの曲線に近づいたときに、
// closest な曲線上の点から垂線を一時表示する。
//
// その点における接ベクトルを法線方向とする平面と、
// マウスビームとの交点を計算し、そこまでの線分を一時表示する。
void MGSurfSweepRibbonIPoint::do_make_temporary_display(mgSysGL& sgl,fugenView* pView){	
	MGSurfSweepRibbonTool* owner = state_owner();
	ASSERT(owner->m_curve);

	const MGCurve& curve = *owner->m_curve;

	// 1. マウスカーソル位置における gluLookAt ビーム
	MGStraight ray;
	CPoint point=pView->mousemove_old_point();
	pView->unproject_to_sl(point, ray);

	// 2. 一番近い点
	MGPosition param = curve.closest(ray);
	MGPosition pos = curve.eval(param[0]);
	MGPosition ref = ray.eval(param[1]);
	sgl.setStaticAttribColor(.5f,1.f,.5f);
	sgl.drawStraight(pos, ref);
}
