#pragma once
#ifndef __RAILMOVEHPP__
	#define __RAILMOVEHPP__

	#include "mw4.hpp"
	#include "adept\applicationtask.hpp"
	#include "aiutils.hpp"
	#include "vehicle.hpp"
	#include <gameos\gameos.hpp>
	#include "quadtree.hpp"

#pragma warning(push)
#include <vector>
#include <stack>
#pragma warning (pop)

// Editor specific code
//#ifdef GAMEEDITOR
	#include <ElementRenderer\LineCloudElement.hpp>
//#endif

//#include "utils\utils.h"

//--------------------------------------------------------------------
	
	
Stuff::Scalar GetMapY(Stuff::Scalar x, Stuff::Scalar z);
	
	
namespace MW4AI
{

	extern HGOSHEAP g_AIHeap,g_MoverAIHeap,g_CombatAIHeap,g_RailHeap;

	typedef void (*WorkCallBack) (float);
	extern Stuff::Scalar MinZ, MaxZ, MinX, MaxX;
	extern bool twofalse[2],twotrue[2];
	extern int	twomax[2];

	class CRailNode;
	class CRailLink;
	class CRailGraph;
	class CMoveGrid;
	class CAirMoveGrid;
	class CPathRequest;
	class CGridPath;
	class CRailPath;
	class CMoveRectList;
	struct OBRect;

	const int MAXLINKS=10000;
	const int MAXNODES=2000;
	const int MINLINKCALC = 10;
	const int MAXLINKCALC = 15;
	const int LINKDIST = 300;
	const int BLOCK_GRID_SIZE = 128;
	const int BLOCK_GRID_RES = 10;			// meters per cell
	const int MACROBLOCK_GRID_RES = 80;	// meters per cell
	const int MACROBLOCK_GRID_SIZE = 1280 / MACROBLOCK_GRID_RES;
	const int BLOCK_TO_MACROBLOCK = (MACROBLOCK_GRID_RES / BLOCK_GRID_RES);
	
	const int AIR_BLOCK_GRID_SIZE = 64;
	const int AIR_BLOCK_GRID_RES = 20;			// meters per cell

	const int GRIDMOVE_FAIL_THRESHOLD = 250;	// number of cells to visit before failure to find path
	const int GRIDMOVE_MAX_CHECK_THRESHOLD = 5000;

	// mapquery project has a copy of these also.

	const unsigned char 	AIRPASS_FLAG			= 0x01;			// true if air units cannot pass


	const unsigned short	LEGPASS_FLAG 			= 0x0001;		// true if legged units cannot use
	const unsigned short	HOVERPASS_FLAG		= 0x0002;		// true if hover units cannot use
	const unsigned short	TRACKPASS_FLAG		= 0x0004;		// true if track units cannot use
	const unsigned short  WHEELPASS_FLAG		= 0x0008;		// true if wheel units cannot use
	const unsigned short  WATERPASS_FLAG		= 0x0010;		// true if water units cannot use
	const unsigned short  JUMPPASS_FLAG			= 0x0020;		// true if cannot jump through
	const unsigned short	MOVEPASSNOW_FLAG	= 0x0040;		// if a vehicle has this cell blocked now
	const unsigned short	BRIDGE_FLAG				= 0x0080;		// true if this cell is a bridge cell
	const unsigned short	WATER1_FLAG				= 0x0100;		// with water 2 for four levels of water
	const unsigned short	WATER2_FLAG				= 0x0200;		//  no, shallow, medium, deep
	const unsigned short	STEEP1_FLAG				= 0x0400;		// with steep 2 for steepness of slope for descending, going up uses blocked flags
	const unsigned short	STEEP2_FLAG				= 0x0800;		// mech down, track down, wheel down, hover down
	const unsigned short	SLOPEDIR1_FLAG		= 0x1000;		// quanta of slope direction
	const unsigned short	SLOPEDIR2_FLAG		= 0x2000;	
	const unsigned short	SLOPEDIR3_FLAG		= 0x4000;	

	
	const int HOVERDOWN_SLOPE = 0;
	const int WHEELDOWN_SLOPE = 1;
	const int TRACKDOWN_SLOPE = 2;
	const int LEGDOWN_SLOPE		= 3;
	const int STEEP_MASK			= 0x0c00;
	const int STEEP_SHIFT			= 10;

	const int NO_WATER				= 0;
	const int SHALLOW_WATER		= 1;
	const int MEDIUM_WATER		= 2;
	const int DEEP_WATER			= 3;
	const int WATER_MASK			= 0x0300;
	const int WATER_SHIFT			= 8;

	const int SLOPEDIR_MASK		= 0x7000;
	const int SLOPEDIR_SHIFT	= 12;

	const int UPSLOPE_STRAIGHT_COST		= 14;
	const int UPSLOPE_DIAG_COST				= 21;
	const int STRAIGHT_COST						= 10;
	const int DIAG_COST								= 15;
	const int DOWNSLOPE_STRAIGHT_COST	= 13;
	const int DOWNSLOPE_DIAG_COST			= 19;

//	const float LEGUP_SLOPE_THRESHOLD			= 0.707f;					//cos (45 deg)
//	const float LEGDOWN_SLOPE_THRESHOLD		= 0.5f;					//cos (60 deg)
	
//	const float TRACKUP_SLOPE_THRESHOLD		= 0.819f;					//cos (35 deg)
//	const float TRACKDOWN_SLOPE_THRESHOLD = 0.707f;					//cos (45 deg)
	
//	const float WHEELUP_SLOPE_THRESHOLD		= 0.906f;					//cos (25 deg)
//	const float WHEELDOWN_SLOPE_THRESHOLD = 0.819f;					//cos (35 deg)

//	const float HOVERUP_SLOPE_THRESHOLD		= 0.965f;					//cos (15 deg)
//	const float HOVERDOWN_SLOPE_THRESHOLD = 0.906f;					//cos (25 deg)

	const unsigned short  BLOCKED_FLAGS			= 0x003f;		// for all blocked flags
	

//--------------------------------------------------------------------
// note: these two areas of const's must match
	const int JUMPFLAG 		= 0x0001;			
	const int TRACKFLAG 	= 0x0002;
	const int FLYFLAG 		= 0x0004;
	const int WHEELFLAG 	= 0x0008;
	const int LEGFLAG 		= 0x0010;
	const int HOVERFLAG 	= 0x0020;
	const int HELIFLAG 		= 0x0040;
	const int WATERFLAG		= 0x0100;
	const int BRIDGEFLAG 	= 0x0080;		// implied from data so not listed as index

	const int JUMPINDEX = 0;
	const int TRACKINDEX = 1;
	const int FLYINDEX = 2;
	const int WHEELINDEX = 3;
	const int LEGINDEX = 4;
	const int HOVERINDEX = 5;
	const int HELIINDEX = 6;
	const int BRIDGEINDEX = 7;
	const int WATERINDEX = 8;
	const int NUM_MOVE_TYPES = 9;

	struct gridpoint
	{
		int x,y;
		gridpoint (int p1,int p2);
		gridpoint (float p1,float p2);
	};

	void FillCircle (stlport::vector<gridpoint>& points,Stuff::Point3D center,Stuff::Scalar rad);

//--------------------------------------------------------------------

	typedef CRailNode *CRailNodePtr;
	typedef CRailLink *CRailLinkPtr;

	class CRailLink
	{
		friend class CRailGraph;
	private:

		unsigned int m_ID;
		CRailNode *m_Loc[2];
		unsigned int m_LocID[2];
		float m_Weight[NUM_MOVE_TYPES][2];
		float m_CalcedWeight[NUM_MOVE_TYPES][2];
		int m_Bridge;													// id of bridge object

		int m_UsageFlags[2];

		void ID (unsigned int id)
		{ m_ID = id; }

		~CRailLink();
	public:
		// would you believe that all this is to just draw a single line?

		static void ConstructLinkObjectStream(int id,Stuff::MemoryStream *stream,Stuff::NotationFile *model_file);
		void DumpNotationFile (Stuff::NotationFile *file);
		CRailLink (Stuff::MemoryStream *stream,CRailGraph *parent);
		CRailLink (void);
		CRailLink (CRailNode *loc1,CRailNode *loc2,float weight[NUM_MOVE_TYPES][2],bool jump[2] = twofalse,bool track[2]=twofalse,bool fly[2]=twofalse,bool wheel[2]=twofalse,bool leg[2]=twotrue,bool hover[2] =twofalse,bool heli[2] = twofalse);
		CRailLink (CRailNode *loc1,CRailNode *loc2,float weight[NUM_MOVE_TYPES][2],int moveflags[2] = twomax);

		int Bridge (void) const
		{ return m_Bridge; }
		void Bridge (int id)
		{ m_Bridge = id; }
		void DestroyBridge (void);
		float Weight (int type,CRailNode *src) const;
		float LowestWeight (int usage,int &type,CRailNode *src) const;
		bool Jump (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & JUMPFLAG;
			else
				return m_UsageFlags[1] & JUMPFLAG;
		#pragma warning (default:4800)
		}
		bool Tracked (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & TRACKFLAG;
			else
				return m_UsageFlags[1] & TRACKFLAG;
		#pragma warning (default:4800)
		}
		bool Flyer (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & FLYFLAG;
			else
				return m_UsageFlags[1] & FLYFLAG;
		#pragma warning (default:4800)
		}
		bool Wheeled (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & WHEELFLAG;
			else
				return m_UsageFlags[1] & WHEELFLAG;
		#pragma warning (default:4800)
		}
		bool Legged (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & LEGFLAG;
			else
				return m_UsageFlags[1] & LEGFLAG;
		#pragma warning (default:4800)
		}
		bool Hover (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & TRACKFLAG;
			else
				return m_UsageFlags[1] & HOVERFLAG;
		#pragma warning (default:4800)
		}
		bool Heli (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & HELIFLAG;
			else
				return m_UsageFlags[1] & HELIFLAG;
		#pragma warning (default:4800)
		}
		bool Water (CRailNode *src) const
		{
		#pragma warning (disable :4800)
			if (m_Loc[0] == src)
				return m_UsageFlags[0] & WATERFLAG;
			else
				return m_UsageFlags[1] & WATERFLAG;
		#pragma warning (default:4800)
		}
		
		void Weight (float amount,int which,CRailNode *src,bool calc=false);
		void Jump (bool p1,CRailNode *src);
		void Tracked (bool p1,CRailNode *src);
		void Flyer (bool p1,CRailNode *src);
		void Wheeled (bool p1,CRailNode *src);
		void Legged (bool p1,CRailNode *src);
		void Hover (bool p1,CRailNode *src);
		void Heli (bool p1,CRailNode *src);

		unsigned int ID (void) const
		{ return m_ID; }

		const CRailNode *Location (unsigned int id) const;
		unsigned int LocID (unsigned int id) const;
		CRailNode *OtherLocation (const CRailNode *temp);
		CRailNode *Location (int id);
		void TestInstance (void) const
		{}

	};


	class CRailNode
	{
		friend class CRailGraph;
	private:
		struct RailSubNode
		{
			Stuff::Point3D location;
			RailSubNode (void)
			{ location = Stuff::Point3D (0,0,0); }
			RailSubNode (const Stuff::Point3D& loc)
			{ location = loc; }
			RailSubNode (Stuff::Scalar p1,Stuff::Scalar p2,Stuff::Scalar p3);
			RailSubNode (const RailSubNode& p1)
			{ location = p1.location; }
			RailSubNode& operator= (const RailSubNode& p1);
		};

		unsigned int m_ID;
		bool m_Dirty;
		bool m_DistanceValid;
		Stuff::Point3D m_Location;
		stlport::vector<CRailLink *> m_Links;
		stlport::vector<RailSubNode> m_SubNodes;
		stlport::vector<float> m_EditorDistance;			// only allocated in the editor
		
		float m_PathWeight;					// used in the path finding code	weight to get to this node
		float m_PathEstimate;				// used in the path finding code  weight from this node to the dest
		int m_PathType;							// used in the path finding code	type of movement to get to this node

		Stuff::Scalar m_Radius,m_RadiusSquared,m_MaxRadius,m_SubNodeRadiusMult;
		void SubNodeRadiusMult(Stuff::Scalar mult)
		{ m_SubNodeRadiusMult = mult;}

		void ID (unsigned int id)
		{ m_ID = id; }

		~CRailNode (void);
	public:

		// Draw a circle for the radius


		static void ConstructNodeObjectStream(int id,Stuff::MemoryStream *stream,Stuff::NotationFile *model_file);
		void DumpNotationFile (Stuff::NotationFile *file);
		CRailNode (const Stuff::Point3D& loc,Stuff::Scalar rad);
		CRailNode (Stuff::MemoryStream *stream,CRailGraph *parent);

		CRailLink *LinkTo (CRailNode *dest);
		float LinkLength (CRailLink *link);				// only length for non intersecting parts, negative if overlap with abs = to dist center to center
		bool PtInNode (const Stuff::Point3D& pt);

		Stuff::Point3D Location (void) const
		{ return m_Location; }

		void Location (const Stuff::Point3D& newloc);
		
		unsigned int ID (void) const
		{ return m_ID; }

		Stuff::Scalar Radius (void) const
		{ return m_Radius; }
		Stuff::Scalar RadiusSquared (void) const
		{ return m_RadiusSquared; }
		void Radius (Stuff::Scalar newrad);

		void SetRadiusToMax (void);
		void CheckRadius();
		
		int NumLinks (void) const
		{ return m_Links.size (); }

		CRailLink *Link (unsigned int id) const;
		void ClearLinks (void);
		RailSubNode SubNode (unsigned int id);
		RailSubNode SubNode (CRailLink *link);
		unsigned int LinkID (unsigned int index);
		void AddLink (CRailLink *link);
		void DeleteLink (CRailLink *link);
		float EditorDistance (CRailNode *dest) const;
		float EditorDistance (unsigned int id) const;

	// Path finding support
		float PathWeight (void) const
		{ return m_PathWeight; }
		float PathEstimate (void) const
		{ return m_PathEstimate; }
		int PathType (void) const
		{ return m_PathType; }
		bool PathWeight (float newvalue,float estimate,int type);					// true if changed
		void ClearPathWeight (float newvalue,float newestimate,int type);

		void TestInstance (void) const
		{}
	};
	
	struct NodeDist
	{
 		CRailNode *src;
		CRailNode *dest;
		NodeDist (void)
		{
			src = dest = NULL;
		}
		NodeDist (const NodeDist& p1)
		{
			src = p1.src;
			dest = p1.dest;
		}
		NodeDist (CRailNode *p1,CRailNode *p2)
		{
			src = p1;
			dest = p2;
		}
	};

struct raildistcmp : binary_function<NodeDist,NodeDist, bool>
{
	bool operator()(const NodeDist& _X, const NodeDist& _Y) const
		{return _X.src->EditorDistance (_X.dest) < _Y.src->EditorDistance (_Y.dest); }
};


	class CRailSquare
	{
		public:
			Stuff::Scalar height;
			BYTE material;
      Stuff::Normal3D normal;
			int waterlevel;
			int objectid;
			int bridge;				// id of bridge object
			bool walkthruflag;
			Stuff::Scalar objectheight;

			CRailSquare (void);
			void Construct (Stuff::Scalar x,Stuff::Scalar z);
	};

	class CRailWorkGrid
	{
		protected:
			QuadTree<int> m_QuadTree;

			bool workarray[2048][2048];
			stlport::vector<stlport::vector <CRailSquare> > m_Grid;
			float CheckSquare (int cx,int cy,int movetype);
			void MarkBuilding (Stuff::ExtentBox& box,int id,bool bridge,CMoveGrid *movegrid,CAirMoveGrid *airmovegrid,bool walkthruflag);

		public:
			CRailWorkGrid (void);
			void Construct (WorkCallBack callback,float maxpercent,CMoveGrid *movegrid,CAirMoveGrid *airmovegrid);
			Stuff::Scalar CalcWeight (Stuff::Point3D src, Stuff::Point3D dest,int movetype);
			Stuff::Scalar MaterialMode (int x,int y,int movetype);
			Stuff::Scalar CalcRadius (const Stuff::Point3D& center,Stuff::Scalar maxrad);
			bool BuildingAt (const Stuff::Point3D&);
			Stuff::Scalar Slope (const Stuff::Point3D& loc);
			Stuff::Scalar Slope (int x,int y);
			int CalcBridgeLink (Stuff::Point3D src, Stuff::Point3D dest);
			bool AnalyzeNode (QuadTreeNode<int> *node);
	};

	class CAirMoveGrid
	{
	private:
		DWORD m_Width,m_Height;					// in meters
		unsigned char **m_Data;					// two dimensional array for width and height.  AIR_PASS_FLAG flags at top

		DWORD m_AllocWidth,m_AllocHeight;

	public:
		CAirMoveGrid (Stuff::MemoryStream *stream);
		CAirMoveGrid (void);
		~CAirMoveGrid (void)
		{ Destroy (); }
		void Destroy (void);
		void SaveData (const char *filename);
		static void ConstructStream (Stuff::MemoryStream *stream,const char *filename);
		void Construct (int width,int height);
		void Clear (void);

		void Passable (Stuff::Scalar x,Stuff::Scalar z,unsigned char canpass,bool override = false);		// in meters
		void PassableLocal (int x,int z,unsigned char canpass,bool override=false);																// in local

		unsigned char Passable (Stuff::Scalar x,Stuff::Scalar z) const;						// in meters
		unsigned char PassableLocal (int x,int z) const;																// in local
	};

	class CMoveGrid
	{
	private:
		DWORD m_Width,m_Height;					// in meters
		unsigned short *m_Data;				// two dimensional array for width and height.  PASS_FLAG flags at top
//		unsigned short **m_Data;				// two dimensional array for width and height.  PASS_FLAG flags at top
		unsigned char  **m_MacroData;		// 40 meter grid for whether a cell is open, same size in width and height at m_Data
																		// 0 is totatlly open 1 is some form of blocking

		DWORD m_AllocWidth,m_AllocHeight;
		DWORD m_MacroAllocWidth,m_MacroAllocHeight;

		static void ConvertOldStyle (Stuff::MemoryStream *stream,DWORD *data,DWORD filesize);
		static void ConvertOldStyle2 (Stuff::MemoryStream *stream,DWORD *data,DWORD filesize);

		void CreateMacroData (void);
		void DeleteMacroData (void);

	public:
		CMoveGrid (Stuff::MemoryStream *stream);
		CMoveGrid (void);
		~CMoveGrid (void)
		{ Destroy (); }
		void Destroy (void);
		void SaveData (const char *filename);
		static bool ConstructStream (Stuff::MemoryStream *stream,const char *filename);
		void Construct (int width,int height);
		void Clear (void);

		void Passable (Stuff::Scalar x,Stuff::Scalar z,unsigned short canpass);		// in meters
		void PassableLocal (int x,int z,unsigned short canpass);																// in local
		void PassableOverride (Stuff::Scalar x,Stuff::Scalar z,unsigned short canpass);		// in meters
		void PassableLocalOverride (int x,int z,unsigned short canpass);																// in local

		unsigned short Passable (Stuff::Scalar x,Stuff::Scalar z) const;						// in meters
		unsigned short PassableLocal (int x,int z) const;														// in local
		
		unsigned char MacroPassable (Stuff::Scalar x,Stuff::Scalar z) const;				// in meters
		unsigned char MacroPassableLocal (int x,int z) const;												// in local
	};

	typedef CRailNode *CRailNodePtr;

	typedef Adept::Receiver__ClassData			CRailGraph__ClassData;
	typedef Adept::Receiver__Message				CRailGraph__Message;

	class CRailGraph  : public Adept::Receiver
	{
	private:
		stlport::vector<CRailLink *> m_Links;
		stlport::vector<CRailNode *> m_Nodes;
		stlport::vector<Stuff::Point3D> m_BlockedLinks;
		bool m_Dirty;
		CRailWorkGrid *m_WorkGrid;
    CMoveGrid *m_MoveGrid;
    CAirMoveGrid *m_AirMoveGrid;
		int m_WorkGridRefCount;
		CMoveRectList *m_RectList;

		void CalcEditorDistances (void);
		void AnalyzePaths (void);
		void AddBridgeLinks (void);
		int CalcBridgeLink (Stuff::Point3D src, Stuff::Point3D dest);
		bool TestBridge (int id,int node1,int node2);
		bool LinkWeight (CRailLink *link);

	public:
		typedef CRailGraph__ClassData		ClassData;
		typedef CRailGraph__Message			Message;

		bool BridgeNear (Stuff::Point3D& start,Stuff::Point3D& end);
		bool m_SaveLineElementMemory;

		Stuff::Point3D PullPointElement (Stuff::Point3D& start,Stuff::Point3D& end,int usage);
		Stuff::Point3D PullPointElementMask (Stuff::Point3D& start,Stuff::Point3D& end,int mask);
		bool PointOpen (Stuff::Scalar x,Stuff::Scalar y,int pass);
		unsigned short Passable (Stuff::Scalar x,Stuff::Scalar z) const;
		unsigned short PassableLocal (int x,int z) const;																// in local
		void Passable (Stuff::Scalar x,Stuff::Scalar z,unsigned short canpass);		// in meters
		void PassableLocal (int x,int z,unsigned short canpass);																// in local
		void PassableOverride (Stuff::Scalar x,Stuff::Scalar z,unsigned short canpass);		// in meters
		void PassableLocalOverride (int x,int z,unsigned short canpass);																// in local
		unsigned char MacroPassable (Stuff::Scalar x,Stuff::Scalar z) const;				// in meters
		unsigned char MacroPassableLocal (int x,int z) const;												// in local
		
		unsigned char AirPassable (Stuff::Scalar x,Stuff::Scalar z) const;
		unsigned char AirPassableLocal (int x,int z) const;																// in local
		void AirPassable (Stuff::Scalar x,Stuff::Scalar z,unsigned char canpass,bool override = false);		// in meters
		void AirPassableLocal (int x,int z,unsigned char canpass,bool override=false);																// in local


		CRailGraph (ClassData *class_data);
		CRailGraph (ClassData *class_data,Stuff::MemoryStream *stream);
		~CRailGraph (void);

		void CreateGrid (WorkCallBack callback,float maxpercent);
		void KillGrid (void);

		void ClearLinks (int *start,int numnodes);
		void ClearLinks (void);

		static ClassData *DefaultData;
		static void ConstructGraphObjectStream(Stuff::MemoryStream *stream,Stuff::NotationFile *model_file);

		bool QuickCheck (int x1,int y1,int x2,int y2,unsigned short mask,bool widthvalid=true);
		bool AirQuickCheck (int x1,int y1,int x2,int y2);
		bool MoveTo (int x,int y,int dir,int mask);			// in local coordinates  dir is from mask list
		int UpDownTo (int x,int y,int dir,int mask);			// in local coordinates  dir is from mask list

		static void InitializeClass();
		static void TerminateClass();

		void BlockLink (int node1,int node2);
		void RemoveBlock (int node);

		int AddNode (CRailNode *node);
		int AddLink (CRailLink *link);
		int AddLink (unsigned int n1,unsigned int n2,float weight[NUM_MOVE_TYPES][2],int moveflags[2] = twomax);
		int AddLink (CRailNode *n1,CRailNode *n2,float weight[NUM_MOVE_TYPES][2],int moveflags[2] = twomax);


		void ClearPathFlags (void);
		CRailNode *FindClosestNode (const Stuff::Point3D& loc,bool strict=true,CRailNode *firstcheck = NULL);
		void FindBestNode (const Stuff::Point3D& start,const Stuff::Point3D& end,bool strict,CRailNodePtr& startnode,CRailNodePtr& endnode);
		float Connect (CRailNode *src,CRailNode *dest,int usagetype) const;
		int Connect (CRailNode *src,CRailNode *dest) const;


		int NumNodes(void) const
		{ return m_Nodes.size(); }
		int NumLinks(void) const
		{ return m_Links.size(); }
		int CountNodes(void) const;
		int CountLinks(void) const;
		CRailLink *Link (unsigned int id);
		CRailNode *Node (unsigned int id);
		void DeleteNode (unsigned int id);
		void DeleteLink (unsigned int id);
		void DeleteLink (unsigned int node1,unsigned int node2);

		void TestInstance (void) const;
		const CMoveRectList *RectList (void) const
		{	return m_RectList; }

	// editor support
		void DumpNotationFile (Stuff::NotationFile *file,const char *passfile,const char *rectfile,const char *airpassfile);
		void CalcLinks (int min = MINLINKCALC,int max = MAXLINKCALC,int range = LINKDIST,WorkCallBack callback = NULL);
		void CalcLinks (int *start,int numnodes,int min = MINLINKCALC,int max = MAXLINKCALC,int range = LINKDIST,WorkCallBack callback= NULL);
		void UpdateNodes (WorkCallBack callback,float percentstart);
		void CreateBasicNodes (int number,WorkCallBack callback);
		void CreateRectData (WorkCallBack callback);

		Stuff::Scalar m_SubNodeRadiusMult;
	};


	
	
	
	
	
	
struct railnodecmp : binary_function<CRailNode *,CRailNode *, bool>
{
	bool operator()(const CRailNode *_X, const CRailNode *_Y) const
		{
			float c1,c2;

			c1 = _X->PathWeight () + _X->PathEstimate ();
			c2 = _Y->PathWeight () + _Y->PathEstimate ();
			return c1 < c2;
		}
};


	class CRailPath
	{
	public:
		struct NodePathElement
		{
			CRailLink *link;
			CRailNode *destnode;
			int 			usage;
			NodePathElement (void)
			{ link = NULL; destnode = NULL; usage = 0; }
			NodePathElement (CRailLink *p1,CRailNode *p2,int p3)
			{ link = p1; destnode = p2; usage = p3; }
			void Save (MemoryStream *stream);
			void Load (MemoryStream *stream);
		};
		struct PathElement
		{
			Stuff::Point3D 	loc;
			int 						usage;
			bool 						onrail;
			int							linkid;
			PathElement (void);
			PathElement (const Stuff::Point3D& p1,int p2,bool p3,int p4);
			bool operator== (const PathElement& p1);
			void Save (MemoryStream *stream);
			void Load (MemoryStream *stream);
		};
	private:
		Stuff::Point3D m_Start;
		Stuff::Point3D m_End;
		Stuff::Point3D m_HeadPoint;
		MechWarrior4::MoverAI *m_AI;
		int m_UsageAllowed;
		CRailNode *m_StartNode,*m_EndNode;
		CRailGraph *m_Graph;
		CPathRequest *m_SubPathRequest;
		bool m_Calced;
		bool m_Strict;
		bool m_TenMeterAllowed;
		bool m_QuickPath;
		bool m_NearLastFrame;


		stlport::vector<NodePathElement> m_NodePath;
		stlport::vector<PathElement> m_Path;
		int m_InNodePath;
		stlport::vector<PathElement>::iterator m_InPath;

		CGridPath *m_SubPath;

		bool NewSubPath (const Stuff::Point3D& loc);

		float CostGuess (CRailNode *src);

		//-------------------
		// following support
	public:

		enum PATHSTATES
		{
			RAIL_START_PATH,
			RAIL_MOVE_NO_RAIL,
			RAIL_NEXT_STEP,
			RAIL_HEAD_EXIT_SUB,
			RAIL_MOVE_RAIL,
			RAIL_MOVE_ENDPOINT,
			RAIL_MOVE_WAITING,			// waiting for a subpath calc to end
			RAIL_FINISH
		};
	private:
		PATHSTATES m_State;

		void CalcOutVec (Stuff::Point3D& outvec);
		void ConvertNodeToPath (void);
		void ReverseList (void);
		void DumpPath (void);
		void CreatePathRequests (void);
		bool PointBehind (const Stuff::Point3D& loc,const Stuff::Point3D& dest);
		void AddStartPoint (Stuff::Point3D& loc,bool& startbrid,stlport::vector<NodePathElement>::iterator& iter);
		void AddBridgeToPath (stlport::vector<NodePathElement>::iterator iter,Stuff::Point3D& loc,const OBRect *bridge,bool startbrid);
		void AddPointToPath (stlport::vector<NodePathElement>::iterator iter,Stuff::Point3D& loc);
		void AddJumpPoint (stlport::vector<NodePathElement>::iterator iter,Stuff::Point3D& loc);
		void AddEndPoint (Stuff::Point3D& loc);
		void HandleOneNodePath (void);


	public:
		CRailPath (CRailGraph *graph,const Stuff::Point3D& start,const Stuff::Point3D& end,bool strict,MechWarrior4::MoverAI *ai,bool tenmeter);
		CRailPath (CRailGraph *graph,CRailNode *start,CRailNode *end,MechWarrior4::MoverAI *ai,bool tenmeter);
		CRailPath (CRailGraph *graph,MechWarrior4::MoverAI *ai);
		~CRailPath (void);
		void Save (MemoryStream *stream);
		void Load (MemoryStream *stream);

		bool Calced (void) const
		{ return m_Calced; }
		bool QuickPath (void) const
		{ return m_QuickPath;  }
		void Reverify (int usage);

		bool JumpSoon (void) const;

		void CalcPath (int usage);
		int CurLink (void) const;
		Stuff::Point3D CurrentPoint (void) const;				// next link in path
		Stuff::Point3D NextPoint (void) const;				// next link in path
		bool Next (const Stuff::Point3D& loc);

		Stuff::Point3D Heading (void) const
		{ return CurrentPoint (); }
		PATHSTATES State (void) const
		{ return m_State; }
		void Tick (const Stuff::Point3D& loc,Stuff::Time till,Stuff::Scalar speed,Stuff::Point3D& outvec,bool& jump,bool& prejump);
		void TestInstance (void) const {Verify (m_State>=RAIL_START_PATH); Verify (m_State <=RAIL_FINISH);}
		Stuff::Point3D Start (void) const
		{ return m_Start; }
		Stuff::Point3D End (void) const
		{ return m_End; }

		void UpdateSrcDest (CRailNode *src,CRailNode *dest);
		void UpdateSrcDest (const Stuff::Point3D& src,const Stuff::Point3D& dest);

		void PointList (stlport::vector<Stuff::Point3D>& dest);
	};
	

	class CGridPath
	{
		friend struct gridpathcmp;
	public:
		struct GridPathElement
		{
			int locX,locY;
			GridPathElement (void)
			{ locX = 0; locY = 0;}
			GridPathElement (int p1,int p2)
			{
				locX = p1;
				locY = p2;
			}
			bool operator== (const GridPathElement& p1)
			{ return (p1.locX == locX) && (p1.locY == locY); }
		};
		struct DirElement
		{
			int locX,locY;											
			DirElement (void)
			{ locX = -1; locY = -1;}
			DirElement (int p1,int p2)
			{
				locX = p1;
				locY = p2;
			}
		};

		bool DirPathValid() const
		{
			return (m_InDirPath != m_DirList.end());
		}

	private:
		stlport::vector<DirElement>::iterator m_InDirPath;
		stlport::vector<DirElement> m_DirList;
		int m_StartX,m_StartY,m_EndX,m_EndY;
		bool m_Calced;
		bool m_Working;
		bool m_QuickValid;
		bool m_TenMeterAllowed;
		int m_WorkCount;
		unsigned short m_Mask;
		CRailGraph *m_Graph;
		my_heap<GridPathElement,true,gridpathcmp> calc;

		static CGridPath *m_WorkingPath;
		static int m_BlockOriginX,m_BlockOriginY;
		static unsigned int m_BlockGrid[BLOCK_GRID_SIZE][BLOCK_GRID_SIZE][2];		// lower number is current cost, upper is estimate

		static unsigned int Cost (int sx,int sy);
		static unsigned int Estimate (int sx,int sy);
		static bool Cost (int sx,int sy,unsigned int cost,unsigned int estimate);
		static unsigned int Cost (const GridPathElement& p1)
		{ return Cost (p1.locX,p1.locY); }
		static unsigned int Estimate (const GridPathElement& p1)
		{ return Estimate (p1.locX,p1.locY); }
		static bool Cost (const GridPathElement& p1,unsigned int cost,unsigned int estimate)
		{ return Cost (p1.locX,p1.locY,cost,estimate); }
		
		int CostGuess (int sx,int sy);

		int AdjustCost (int cx,int cy);			// will adjust the cost based on locality to blocked terrain

		void ReverseList (void);
//		bool QuickCheck (int x1,int y1,int x2,int y2);
		void ConstructQuickPath (void);
		void DumpPath (void);
		void SmoothList (void);
		void SmoothListHelper (stlport::vector<DirElement>& vec,int s,int e);

		void Calc30Path (void);
		void Calc10Path (void);
		void StartCalcPath (void);
		void ContinueCalcPath (void);

	public:
		virtual void Save (MemoryStream *stream);
		virtual void Load (MemoryStream *stream);
		CGridPath (CRailGraph *graph);
		CGridPath (CRailGraph *graph,unsigned short mask,int sx,int sy,int dx,int dy,bool tenmeter);
		CGridPath (CRailGraph *graph,unsigned short mask,Stuff::Scalar sx,Stuff::Scalar sy,Stuff::Scalar dx,Stuff::Scalar dy,bool tenmeter);
		~CGridPath (void);

		void DoCalcPath (void);
		bool Working (void)
		{ return m_Working; }

		bool Calced (void) const
		{ return m_Calced; }

		bool QuickValid (void) const
		{ return m_QuickValid; }
		bool Next (void);							// true if path still exists
		Stuff::Point3D NextPoint (void) const;				// next link in path
		bool OneFromEnd (void) const;			// at end is also good
		Stuff::Point3D CurrentPoint (void) const;
//		int size (void)
//		{ return m_Path.size (); }
		DirElement direlement (int index);
		int dirsize (void)
		{ return m_DirList.size (); }
		void UpdateSrcDest (int sx,int sy,int dx,int dy);
		void UpdateSrcDest (Stuff::Scalar sx,Stuff::Scalar sy,Stuff::Scalar dx,Stuff::Scalar dy);
		void PointList (stlport::vector<Stuff::Point3D>& dest);
		Stuff::Point3D End (void)
		{ return Point3D ((Scalar) m_EndX,0.0f,(Scalar) m_EndY); }
	};

struct gridpathcmp : binary_function<CGridPath::GridPathElement *,CGridPath::GridPathElement *, bool>
{
	bool operator()(const CGridPath::GridPathElement& _X, const CGridPath::GridPathElement& _Y) const
		{
		int c1,c2;

		c1 = CGridPath::Cost (_X) + CGridPath::Estimate (_X);
		c2 = CGridPath::Cost (_Y) + CGridPath::Estimate (_Y);
		return c1<c2;
		}
};




	class CPathRequest
	{
		friend class CPathManager;

	private:
		Stuff::Time m_NeedBy;
		bool m_Done;
		CRailPath *m_NodePath;
    CGridPath *m_GridPath;
		int m_UsageAllowed;
		bool m_Strict;
		bool m_Working;
		CPathRequest *m_Next,*m_Prev;
		MechWarrior4::MoverAI *m_Who;
		
		void Done (bool done)
		{ m_Done = done; }

	public:
		virtual void Save (MemoryStream *stream);
		virtual void Load (MemoryStream *stream);

		CPathRequest (CRailGraph *graph);

		CPathRequest (Stuff::Time needby,CRailGraph *graph,CRailNode *start,CRailNode *end,int usageallowed,MechWarrior4::MoverAI *who,bool tenmeter);
		CPathRequest (Stuff::Time needby,CRailGraph *graph,Stuff::Point3D start,Stuff::Point3D end,int usageallowed,MechWarrior4::MoverAI *who,bool tenmeter);
		CPathRequest (Stuff::Time needby,CRailGraph *graph,unsigned short mask,int sx,int sy,int dx,int dy,MechWarrior4::MoverAI *who,bool tenmeter);
		CPathRequest (Stuff::Time needby,CRailGraph *graph,unsigned short mask,Stuff::Scalar sx,Stuff::Scalar sy,Stuff::Scalar dx,Stuff::Scalar dy,MechWarrior4::MoverAI *who,bool tenmeter);
		~CPathRequest (void);

		bool Working (void) const
		{ return m_Working; }
		bool Done (void) const
		{ return m_Done; }
		CRailPath *NodePath (void)
		{ return m_NodePath; }
		CGridPath *GridPath (void)
		{ return m_GridPath; }
		int UsageAllowed (void) const
		{ return m_UsageAllowed; }
		bool PathTypeIsNode (void)
		{ return (m_NodePath != NULL); }
		CRailPath *DetachNodePath (void);
		CGridPath *DetachGridPath (void);

		bool UpdateSrcDest (CRailNode *src,CRailNode *end);
		bool UpdateSrcDest (const Stuff::Point3D& src,const Stuff::Point3D& end);
		bool UpdateSrcDest (int sx,int sy,int dx,int dy);
		Stuff::Point3D GetEndPoint (void);
		void Unlock (void);
		void Lock (void);
	};

	class CPathManager : public Adept::ApplicationTask
	{
	private:
		CPathRequest *m_Root;

		void InsertRequest (CPathRequest *req);

	protected:

	public:
		bool m_FailedCalcFrame;

		void Save (MemoryStream *stream);
		void Load (MemoryStream *stream);
		static void InitializeClass();
		static void TerminateClass();

		CPathManager (void);
		~CPathManager (void);
		CPathRequest *AddRequest (Stuff::Time needby,CRailGraph *graph,CRailNode *start,CRailNode *end,int usageallowed,MechWarrior4::MoverAI *who,bool tenmeter);
		CPathRequest *AddRequest (Stuff::Time needby,CRailGraph *graph,Stuff::Point3D start,Stuff::Point3D end,int usageallowed,MechWarrior4::MoverAI *who,bool tenmeter);
		CPathRequest *AddRequest (Stuff::Time needby,CRailGraph *graph,unsigned short mask,int sx,int sy,int dx,int dy,MechWarrior4::MoverAI *who,bool tenmeter);
		CPathRequest *AddRequest (Stuff::Time needby,CRailGraph *graph,unsigned short mask,Stuff::Scalar sx,Stuff::Scalar sy,Stuff::Scalar dx,Stuff::Scalar dy,MechWarrior4::MoverAI *who,bool tenmeter);
		void RemoveRequest (CPathRequest *req);

		void CleanRequests (void);
		
		unsigned int GetNumPathRequests() const;
		virtual bool Execute();
	};


	extern CPathManager *g_PathManager;

	extern CRailGraph *g_MissionGraph;


/*
	inline void CRailLink::UpdateLinkPointData()
	{
		m_RailLinkPointData[0] = m_Loc[0]->Location();
		m_RailLinkPointData[0].y += 0.5f;
		m_RailLinkPointData[1] = m_Loc[1]->Location();
		m_RailLinkPointData[1].y += 0.5f;
	}
*/
}

#include "rail_move.inl"

#endif
