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

/**
 * @file SplitTool.h
 * @brief クラス MGSplitTool の宣言
 */
#if !defined(AFX_SPLITTOOL_H__3E14647F_E042_4C50_B1A8_BE5A16BE2FFE__INCLUDED_)
#define AFX_SPLITTOOL_H__3E14647F_E042_4C50_B1A8_BE5A16BE2FFE__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "Common/CommandStateOwner.h"
#include "Common/SelectState.h"
#include "SurfCmd/SplitLocateIsoCurves.h"

/// 分割タイプ
enum SplitBy{
	ByIntersection, ///< 通常の分割。カッターオブジェクトとの交点・交線を使用。
	ByPoints, ///< 分割ターゲット上の曲線上点を使用。
	ByIsocurves, ///< 分割ターゲットのアイソカーブを使用。
};

/// @class MGSplitTool SplitTool.h "EditCmd/SplitTool.h"
///
/// Splits an object.
/// You can split curves and surfaces with curves, surfaces and shell. 
/// Shells can only be split with surfaces and shells.
///
/// When you split a surface with a curve in a plan parallel view 
/// like the fugenView2Dxy, fugenView2Dyz, and fugenView2Dxz view, 
/// the cutting curve is projected on the surface in the view direction.
///
/// When you split a surface with a planar curve in an angled parallel
/// or a perspective view like the default fugenView view, the cutting
/// curve is projected on the surface in a direction perpendicular to 
/// the curve plane.
///
/// When you split a surface with a 3-D curve in an angled parallel
/// or a perspective view, the cutting curve is pulled on the surface
/// by closest points.
///
/// @note 仕様は doc/edit-split.doc にある。
class MGSplitTool : public MGCommandStateOwner{
	friend class MGSplitLocatePoints;
	friend class MGSplitLocateIsocurves;
	friend class MGSplitSelCutter;
	friend class MGSplitSelTarget;
	friend class MGSplitSelTargetSurf;

	SplitBy m_splitMode;
	MGPickObjects m_target; ///< 分割コマンドのターゲット
	MGPickObjects m_cutter; ///< ByInterface によるカッター要素

	///m_param[i], m_preview_points[i] is a pair.
	std::vector<double> m_param; ///< 曲線を点で分割する際に利用.
		///<Parameter valu of the curve m_target.
	std::vector<MGPosition> m_preview_points; ///< ByPoints による確定分

public:
	explicit MGSplitTool(fugenDoc* pDoc);

	virtual MGCommandBase* initial_clone(fugenDoc* pDoc) const;
	virtual bool initiate_tool();

	virtual bool OnCommandEnd(UINT nIDS,bool erase_temporary_display=true);
	virtual bool OnCommandCanceled(UINT nIDS);
	SplitBy GetSplitType() const;
	void SetSplitType(SplitBy mode);

	/// 分割コマンドのターゲットを取得する。
	const MGPickObjects& GetSplitTarget() const;

	/// 分割コマンドのターゲットをセットする。
	void SetSplitTarget(const MGPickObjects& target);

	const MGPickObjects& GetCutter() const;

	/// 分割カッターセット
	void SetCutter(const MGPickObjects& added, const MGPickObjects& removed);

	/// ByPoints 専用
	//@{
	const MGCurve* GetSplitTargetCurve() const;
	void AddSplitParam(double dParam);
	//@}

	/// ByIsocurves 専用
	//@{
	const MGFSurface* GetSplitTargetSurf() const;
	void AddSplitParam(const MGPosition& uv, bool bU);
	//@}
	
	/// ByPoints専用
	void RemoveSplitParam();


private:
	/// これまでの分割点を描く。
	void DrawPoints(mgSysGL& sgl,fugenView* pView) const;
};

/*
  split

1. 分割するオブジェクトを選択[複数]
	選べる種類: curve, surface, face, shell

2. 切断オブジェクトを選択[複数]
	1. でshellがひとつでも選ばれているときは
	surface, face, shellしか選択することができない(理由は不明)
	
	curve \ point
		交点で分割するだけ。投影とか余計なことはしない。
		点が複数ある場合、先に分割されたものを分割する。
		
		
		
	curve \ curve
	surface \ curve
	face \ curve

            ビューの種類   2D                     perspective
曲線の種類
平面曲線                   ビュー方向に投影       average planeの法線方向に投影
3D曲線                     ビュー方向に投影       面直投影


	curve \ surface
	surface \ surface
	face \ surface
	shell \ surface
		単なる交線計算となる。この交線で分割する。
	
		面として共有部分があるような場合が面倒
	
	face \ face
	shell \ face
	
	shell \ shell
	
curveによるsplit:

  */

/// @class MGSplitSelTarget
///
/// 分割されるオブジェクトを選択する state
/// @note 仕様書の [S1] に相当する状態を表現する。
class MGSplitSelTarget : public MGSelectState{
public:
	MGSplitSelTarget(MGSplitTool* owner);

	MGSplitTool* state_owner(){
		return static_cast<MGSplitTool*>(get_owner_command());
	}

	virtual bool initiate_tool();
	virtual bool OnKeyDown(fugenView* window, UINT nChar, UINT nRepCnt, UINT nFlags);
	virtual bool OnSelected(
		fugenView* pView,
		MGPickObjects& added,
		MGPickObjects& removed);

private:
	void prompt_message()const;
	bool CanChangeSelCurveState() const;///<test if no selection or current objects include curve.
	bool CanChangeSelSurfState() const;///<test if no selection or current objects include fsurface.
	bool CanChangeSelSpecialTargetState(const MGAbstractGels& type) const;
};

/// @class MGSplitSelTargetCurve
///
/// 切断オブジェクトとしてカーブ一本を選択するステート。
/// @note 仕様書の [S2] に相当する。
class MGSplitSelTargetCurve : public MGSelectState{
public:
	MGSplitSelTargetCurve(MGSplitTool* owner);

	MGSplitTool* state_owner(){
		return static_cast<MGSplitTool*>(get_owner_command());
	}

	virtual bool initiate_tool();

	virtual bool OnSelected(
		fugenView* pView,
		MGPickObjects& added,
		MGPickObjects& removed);

private:
	void prompt_message()const;
};

/// @class MGSplitSelCutter
///
/// 切断オブジェクトを選択するステート。
/// @note 仕様書の [S3] に相当する。
class MGSplitSelCutter : public MGSelectState{
public:
	MGSplitSelCutter(MGSplitTool* owner);

	MGSplitTool* state_owner(){
		return static_cast<MGSplitTool*>(get_owner_command());
	}
	const MGSplitTool* state_owner()const{
		return static_cast<const MGSplitTool*>(get_owner_command());
	}

	virtual bool initiate_tool();
	virtual bool OnKeyDown(fugenView* window, UINT nChar, UINT nRepCnt, UINT nFlags);
	virtual bool OnSelected(
		fugenView* pView,
		MGPickObjects& added,
		MGPickObjects& removed);

private:
	void prompt_message()const;

	bool CanChangeLocatePointsState()const; // [S5]
	bool CanChangeLocateIsocurvesState()const; // [S6]
	bool CanChangeLocateSpecialState(const MGAbstractGels& type)const;
};

/// @class MGSplitSelTargetSurf
///
/// 切断オブジェクトとしてカーブ一本を選択するステート。
/// @note 仕様書の [S4] に相当する。
class MGSplitSelTargetSurf : public MGSelectState{
public:
	MGSplitSelTargetSurf(MGSplitTool* owner);

	MGSplitTool* state_owner(){
		return static_cast<MGSplitTool*>(get_owner_command());
	}

	virtual bool initiate_tool();

	virtual bool OnSelected(
		fugenView* pView,
		MGPickObjects& added,
		MGPickObjects& removed);

private:
	void prompt_message()const;
};

/// @class MGSplitLocatePoints
///
/// ターゲットが曲線一本の時の特別分割ステート。
/// @note 仕様書の [S5] に相当する。
class MGSplitLocatePoints : public MGLocateOnObjects{
public:
	MGSplitLocatePoints(MGSplitTool* owner);

	MGSplitTool* state_owner(){
		return static_cast<MGSplitTool*>(get_owner_command());
	}
	const MGSplitTool* state_owner()const{
		return static_cast<const MGSplitTool*>(get_owner_command());
	}

	virtual bool initiate_tool();
	virtual bool OnLocated(const MGLocateInfo& info);
	virtual void do_make_temporary_display(mgSysGL& sgl,fugenView* pView);

private:
	void prompt_message()const;
};

#endif // !defined(AFX_SPLITTOOL_H__3E14647F_E042_4C50_B1A8_BE5A16BE2FFE__INCLUDED_)
 