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

/**
 * @file CurveSectionTool.cpp
 * @brief MGCurveSectionTool クラスのインプリメンテーション
 */
#include "stdafx.h"
#include "mg/isect.h"
#include "mg/FSurface.h"
#include "mg/Plane.h"
#include "topo/Shell.h"
#include "Calc/mgcalc.h"
#include "fugenView.h"
#include "CurveCmd/CurveSectionTool.h"

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

// MGCurveSectionTool

MGCurveSectionTool::MGCurveSectionTool(fugenDoc* pDoc)
: MGCommandStateOwner(pDoc,ID_CURVE_SECTION),m_nIDS(1){
}

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

bool MGCurveSectionTool::initiate_tool(){
	MGCommandStateOwner::initiate_tool();
	if(resetCurrentObjects(mgAll_2Manifold)){
		//Input a point for the cutting plane
		m_surf = select_from_current_objects(mgAll_FSurface);
		m_shell = select_from_current_objects(mgAll_Shell);
		set_child_current_command(new MGCurveSectionToolIPoint(this));
	}else{
		//select 2 manifold to get the section.
		set_child_current_command(new MGCurveSectionToolSSurf(this));
	}
	return false;
}

bool MGCurveSectionTool::calculate(){
	if(m_surf.empty() && m_shell.empty()){
		// cancel
		return false;
	}
	if(m_line.is_null()){
		// cancel
		return false;
	}

	// 断面
	const LInfoVec& linfos=locates();
	const MGPosition& P1=linfos[1]->point_world();
	MGPlane plane(m_line, P1);

	std::vector<const MGFSurface*> surf(m_surf.size());
	for (size_t i = 0, n = m_surf.size(); i < n; i++)
		surf[i] = dynamic_cast<const MGFSurface*>(m_surf[i].top_object());

	std::vector<const MGShell*> she(m_shell.size());
	for (size_t i = 0, n = m_shell.size(); i < n; i++)
		she[i] = dynamic_cast<const MGShell*>(m_shell[i].top_object());


	MGisects isects;

	// 1. surface
	std::vector<const MGFSurface*>::iterator i=surf.begin(), ie=surf.end();
	for(; i!=ie; i++)
		isects.push_back(plane.isect(**i));

	// 2. shell
	std::vector<const MGShell*>::iterator j=she.begin(), je=she.end();
	for(; j!=je; j++)
		isects.push_back(plane.isect(**j));

	if(isects.empty()){
		// 生成物がなにもない
		m_nIDS = IDS_FAIL_GENERATE_CURVE;
		return false;
	}

	// ドキュメント変更
	//Conversion to MGGelPositions from MGisects.
	MGGroup* grp=current_group();
	MGGelPositions gpos;
	MGisects::const_iterator is=isects.begin(), ise=isects.end();
	for(; is!=ise; is++)
		gpos.push_back(MGGelPosition(grp,(*is)->isect().clone()));
	add_object_to_document(gpos);
	return true;
}

///////////////2 manifold selection class/////////////
MGCurveSectionToolSSurf::MGCurveSectionToolSSurf(MGCommandStateOwner* owner)
:MGSelectState(owner, MGSelectState::MULTIPLE_SELECT,mgAll_2Manifold){
}

bool MGCurveSectionToolSSurf::initiate_tool(){
	MGSelectState::initiate_tool();
	set_add_mode();
	prompt_message();
	return false;
}

bool MGCurveSectionToolSSurf::OnKeyDown(fugenView* pView, UINT nChar, UINT nRepCnt, UINT nFlags){
	switch(nChar){
	case VK_RETURN:{
			MGCurveSectionTool* owner = state_owner();
			
			if(current_objects().empty()){
				// キャンセルとみなす
				return owner->OnCommandEnd(2);
			}
			// 対象となる面データ決定
			owner->m_surf = select_from_current_objects(mgAll_FSurface);
			owner->m_shell = select_from_current_objects(mgAll_Shell);

			set_sibling_next_command(new MGCurveSectionToolIPoint(owner));
		}
		return false;
	default:
		return MGSelectState::OnKeyDown(pView, nChar, nRepCnt, nFlags);
	}
}

void MGCurveSectionToolSSurf::prompt_message()const{
	SetStatusMessage(IDS_PROMPT_SURFACE);
}

/////////////Point input class//////////////

MGCurveSectionToolIPoint::MGCurveSectionToolIPoint(MGCommandStateOwner* owner)
: MGLocateState(owner,UNLOCK_SNAP_ATTRIB,LINE_RUBBER,POINTLINE_IPDRAW){
}

bool MGCurveSectionToolIPoint::OnLocated(const MGLocateInfo& linfo){
	MGCurveSectionTool* owner=state_owner();
	const auto& linfos=locates();
	size_t np=linfos.size();
	if(np==1){
		MGStraight sl;
		linfo.window()->unproject_to_sl(linfos[0]->point_screen(), sl);
		owner->m_line = MGStraight(MGSTRAIGHT_UNLIMIT,sl.direction(),linfo.point_world());
	}else if(np>=2){
		// 計算開始
		if(!owner->calculate()){
			return owner->OnCommandEnd(owner->m_nIDS);
		}
		return owner->OnCommandEnd(1);
	}
	return false;
}

void MGCurveSectionToolIPoint::prompt_message() const{
	if(locates().empty()){
		SetStatusMessage(IDS_PROMPT_SECTION_START);
	}else{
		SetStatusMessage(IDS_PROMPT_SECTION_END);
	}
}
