/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/* ***************************************************** */
/********************************************************************/
/**
 * @file SelectState.h
 * @brief クラス MGSelectState の宣言
 */
#ifndef _MGSelectState_HH_
#define _MGSelectState_HH_

#include "Common/RectDrawer.h"
#include "Common/CommandBase.h"

class fugenView;
class fugenDoc;
class MGCommandStateOwner;
class MGRectRubberBand;

/// @class MGSelectState SelectState.h "Common/SelectState.h"
/// Define MGSelectState Class.
/// MGSelectState is a class to select (pick) objects.
///
/// 何かのコマンドで曲線や曲面等の選択を行うためのクラス。
/// 特に、マウスクリックで選択を行うための機能がある。
class MGSelectState : public MGCommandBase{

public:

	enum SELECTION_TYPE {
		SINGLE_SELECT=0,
		MULTIPLE_SELECT
	};
	enum BOUNDARY_SELECTION {
		NO_BOUNDARY_SELECT=0,
		BOUNDARY_SELECT
	};

	///indicates if unselection is allowed or not.
	enum PROHIBIT_UNSELECTION{
		ALLOW_UNSELECT=0,
		PROHIBIT_UNSELECT
	};

	//////////Constructor//////////

	/// Standard constructor. This state belongs to owner.
	MGSelectState(
		MGCommandStateOwner* owner,///<Owner of this MGSelectState.
		SELECTION_TYPE rect_selection=MULTIPLE_SELECT,	///<MULTIPLE_SELECT if multiple object is to select.
		///<SINGLE_SELECT if only one object is to select.
		const MGAbstractGels& gell_types=mgAll_Gell,	///<type of gells to select.
		BOUNDARY_SELECTION boundary=NO_BOUNDARY_SELECT,	///<BOUNDARY_SELECT if the boundary of the gell is to select.
		PROHIBIT_UNSELECTION prohibit_unselect=ALLOW_UNSELECT///<indicates if  unselect is allowed when add mode
			///<prohibit_unselect is valid only when add mode(ctrl key is down).
	);

	/// constructor that does not have an owner.
	MGSelectState(
		fugenDoc*  pDoc,		///<document.
		UINT	command_id,	///<command id
		SELECTION_TYPE rect_selection=MULTIPLE_SELECT,	///<MULTIPLE_SELECT if multiple object is to select.
		///<SINGLE_SELECT if only one object is to select.
		const MGAbstractGels& gell_types=mgAll_Gell,	///<type of gells to select.
		BOUNDARY_SELECTION boundary=NO_BOUNDARY_SELECT,	///<BOUNDARY_SELECT if the boundary of the gell is to select.
		PROHIBIT_UNSELECTION prohibit_unselect=ALLOW_UNSELECT///<indicates if  unselect is allowed when add mode
			///<prohibit_unselect is valid only when add mode(ctrl key is down).
	);

	///Virtual Destructor
	virtual ~MGSelectState();

	//////////Member Function//////////

	///clear the curennt object.
	virtual void clear_pick_object();

	///Exclude objs from the curennt object.
	virtual void exclude_pick_object(
		const MGPickObjects& objs	///<selected objects at this selection operation.
	);

	///Initiate the class.
	///Overrided initiate must invoke MGSelectState::initiate_tool first.
	///Function's return value is true:if this command should be terminated on return,
	///false if not.
	///MGSelectState::initiate_tool() always returns false, does not return true.
	virtual bool initiate_tool();

	///Select objects of specified type from the document's current objects,
	///and reset the current objects with them.
	virtual void reset_current_objects(const MGAbstractGels& type);

	///lock so far selected objects.
	void lock_so_far();
	void unlock_so_far();

	///prohibit an unselect operation, or allow it.
	void prohibit_unselect(){m_prohibit_unselect=PROHIBIT_UNSELECT;};
	void allow_unselect(){m_prohibit_unselect=ALLOW_UNSELECT;};

	///add mode(to simulate ctrl key down mode) setting.
	void set_add_mode(){m_add=true;};
	void reset_add_mode(){m_add=false;};

	/// Return the reference to types of objects
	/// that are selectable when this state is active.
	MGAbstractGels& abstract_gels(){ return m_gell_types;}

	///set type of gells to select.
	void set_gells_to_select(MGAbstractGels gel_type){m_gell_types=gel_type;};

	const MGAbstractGels& abstract_gels() const{ return m_gell_types;}

	virtual bool OnSelected(
		fugenView* window,///<The fugenView pointer where point input event took place.
		MGPickObjects&	selected_objects,	///<selected objects at this selection operation.
		MGPickObjects&	unselected_objects	///<unselected objects at this selection operation.
		///<unselected_objects.size()>=1 only when the already selected objects are selected
		///<when add mode is set(or when operation is done with a crtl key pressed).
		);

	virtual bool OnLButtonDown(
		fugenView* window,///<The fugenView pointer where this event took place.
		UINT nFlags, CPoint point
		///<These parameters are of CWnd::OnLButtonDown. See the document.
		);

	virtual bool OnLButtonUp(
		fugenView* window,///<The fugenView pointer where this event took place.
		CPoint old_point,	///<The old point(point when LButtonDown).
		UINT nFlags, CPoint point
		///<These parameters are of CWnd::OnLButtonUp. See the document.
		);

	virtual bool OnMouseMove(
		fugenView* window,///<The fugenView pointer where this event took place.
		UINT nFlags, CPoint point
		///<These parameters are of CWnd::OnMouseMove. See the document.
		);

	virtual void ModifyContextMenu(CMenu& popup);

	virtual bool CanHandle(UINT nID) const;
	virtual bool HandleMessage(UINT nID);
	virtual bool HandleUpdateUI(UINT nID, CCmdUI* pCmdUI);

private:

	mgRectDrawer m_PickRectangle;	///<VBO to draw a pick rectangle by screen coordinates.

	MGAbstractGels m_gell_types;           //type of gells to select.
	MGPickObjects   m_locked_objects;       //locked objects will be copied into this member.
	MGPickObjects   m_objects_after_locked; //objects selected after locked.
	
	SELECTION_TYPE m_rect_selection;//true if rectangle object selection is allowed,
	                            //false if rectangle object selection is not allowed.
	bool m_add:1;//true if newly picked objects be appended to current_object().
	        //false if replace with the newly picked objects.
			//m_add==true means the operation is expected to simulate Ctrl key down.
	PROHIBIT_UNSELECTION m_prohibit_unselect;//true if unselect operation not allowed.
	BOUNDARY_SELECTION m_boundary;//true if the boundary of the gell is to select.

//Perform selection operation.
bool selection(
	fugenView* pView,   // ピックイベントの発生したビュー
	MGPickObjects& picked,//the oroginal picked objects are input. 
		//Will be modified so that picked will contain newly picked objects.
	UINT           nFlags   // MK_CONTROL, MK_SHIFT を見るため
);

};


#endif
