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

#ifndef _MGLocateOnObjects_HH_
#define _MGLocateOnObjects_HH_

#include "Common/LocateState.h"

class fugenDoc;

//
//Define MGLocateOnObjects Class.
//MGLocateOnObjects is a class to get point data(locate) on objects
//

//Class Declaration
class MGLocateOnObjects:public MGLocateState{

public:

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

/// Standard constructor. This state belongs to an owner.
///constructor type 1(objects and owner).
MGLocateOnObjects(
	std::list<const MGGel*>* objectives,///<Objects to locate on, cannot be null.
			///<When null is to input, use constructor5.
	MGCommandStateOwner* owner,///<Owner of this MGLocateOnObjects.
	SNAP_ATTRIB_LOCKKIND lock_snap_attrib=UNLOCK_SNAP_ATTRIB,
			///<indicates if lock the snap attrib.
	RUBBER_KIND rubberband=NO_RUBBER,
			///<Specify what type of rubberband is necessary.
	IPOINT_DRAWER_KIND input_drawer=NO_IPDRAW,
			///<specify what type of input points drawer be used.
	bool only_on_object=true	///<only_on_object==true means
			///<OnLocated is not invoked when a point is not on an object.
);

/// constructor that does not have an owner.
///constructor type 2(objects and fugenDoc).
MGLocateOnObjects(
	std::list<const MGGel*>* objectives,///<Objects to locate on, cannot be null.
			///<When null is to input, use constructor6.
	fugenDoc*  pDoc,		///<document.
	UINT	command_id,	///<command id
	RUBBER_KIND rubberband=NO_RUBBER,
		///<Specify what type of rubberband is necessary.
	IPOINT_DRAWER_KIND input_drawer=NO_IPDRAW,
		///<specify what type of input points drawer be used.
	bool only_on_object=true	///<only_on_object==true means
		///<OnLocated is not invoked when a point is not on an object.
);

/// Objectives is only one constructor. This state belongs to an owner.
///constructor type 3(an object and owner).
MGLocateOnObjects(
	const MGObject* objective,///<Object to locate on, cannot be null.
			///<When null is to input, use constructor5.
	MGCommandStateOwner* owner,///<Owner of this MGLocateOnObjects.
	SNAP_ATTRIB_LOCKKIND lock_snap_attrib=UNLOCK_SNAP_ATTRIB,
			///<indicates if lock the snap attrib.
	RUBBER_KIND rubberband=NO_RUBBER,
		///<Specify what type of rubberband is necessary.
	IPOINT_DRAWER_KIND input_drawer=NO_IPDRAW,
		///<specify what type of input points drawer be used.
	bool only_on_object=true	///<only_on_object==true means
		///<OnLocated is not invoked when a point is not on an object.
);

/// Objectives is only one constructor. Constructor that does not have an owner.
///constructor type 4(an object and fugenDoc).
MGLocateOnObjects(
	const MGObject* objective,///<Object to locate on, cannot be null.
			///<When null is to input, use constructor6.
	fugenDoc*  pDoc,		///<document.
	UINT	command_id,	///<command id
	RUBBER_KIND rubberband=NO_RUBBER,
		///<Specify what type of rubberband is necessary.
	IPOINT_DRAWER_KIND input_drawer=NO_IPDRAW,
		///<specify what type of input points drawer be used.
	bool only_on_object=true	///<only_on_object==true means
		///<OnLocated is not invoked when a point is not on an object.
);

///Constructor that does have an owner.
///constructor type 5(no objects and owner).
///Objects must be set by set_locate_objectives.
MGLocateOnObjects(
	MGCommandStateOwner* owner,///<Owner of this MGLocateOnObjects.
	SNAP_ATTRIB_LOCKKIND lock_snap_attrib=UNLOCK_SNAP_ATTRIB,
			///<indicates if lock the snap attrib.
	RUBBER_KIND rubberband=NO_RUBBER,
		///<Specify what type of rubberband is necessary.
	IPOINT_DRAWER_KIND input_drawer=NO_IPDRAW,
		///<specify what type of input points drawer be used.
	bool only_on_object=true	///<only_on_object==true means
		///<OnLocated is not invoked when a point is not on an object.
);

///Constructor that does not have an owner.
///constructor type 6(no objects and fugenDoc)
///Objects must be set by set_locate_objectives.
MGLocateOnObjects(
	fugenDoc*  pDoc,		///<document.
	UINT	command_id,	///<command id
	RUBBER_KIND rubberband=NO_RUBBER,
		///<Specify what type of rubberband is necessary.
	IPOINT_DRAWER_KIND input_drawer=NO_IPDRAW,
		///<specify what type of input points drawer be used.
	bool only_on_object=true	///<only_on_object==true means
		///<OnLocated is not invoked when a point is not on an object.
);

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

///Initiate the class.
///MGLocateOnObjects::initiate_tool() always return false.
virtual bool initiate_tool();

///Locate a point from the screen coordinate point_in to world coordinate point.
///Function's return value is snap_kind of the point located:
///nopos: no points located.
///endpos: end point located.
///knotpos: knot point located.
///vertexpos: vertex point located.
///nearpos: near point located.
///ON_SURFACE: point on MGFSurface is located.
MGSnapPositions::snap_kind locate_object_snap_point(
	fugenView* window,///<The fugenView pointer where point_in  belongs to.
	const CPoint& point_in,	///<Window's point coordinates.
	MGPosition& point,	///<located point will be output
	const MGObject*& obj,//When function's return value is nearpos, end, knot(Curve),
				//vertex(FSurface), or center(Curve&FSurface),
				//the point's parameter value of the object be returned.
	MGPosition& param	
);

///set the objectives to locate on.
///After set_locate_objectives(clear_locate_objectives),
///MGLocateOnObjects::initiate_tool() or initiate_snap_data() must be invoked.
void set_locate_objectives(const std::list<const MGGel*>& objectives);
void set_locate_objectives(const MGObject* objective);
void clear_locate_objectives();

///Set the only on object flag.
void set_only_on_object(bool only_on_object=true){m_only_on_object=only_on_object;};

///Terminate the class.
///Overrided terminate must invoke MGLocateTool::terminate_tool last.
///The function's return value is true, if the tool termination is accepted.
///False, if the termination is refuses.
virtual bool terminate_tool(bool cancel=false);

protected:

	
/////////////////////////////////////////////////////////////////

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

///When a point is located, the data will be output to documnet's cursor().
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.
);

private:

	std::list<const MGGel*> m_objectives2;
		//list of MGGell's pointer for the locate snap objects.

	bool m_only_on_object; //True indicates that OnLocated should not be invoked
			//when the point is not on an object.


MGSnapPositions::snap_kind locate_on_face(
	const MGStraight& sl,//straight line that is a point on the screen.
	MGPosition& point,	//located point will be output
	const MGObject*& obj,//When function's return value is nearpos, end, or knot,
		//the object pointer and the point's parameter value of the object will be returned.
		//When center, only MGObject pointer will be rturned.
	MGPosition& param	
)const;

};

#endif
