#pragma once
#ifndef __STATEMACHINEHPP__
	#define __STATEMACHINEHPP__

namespace MW4AI
{

template<typename T>
class CStateNode
{
protected:
	T m_Data;

public:
	CStateNode (void)
	{
	}
	explicit CStateNode (const CStateNode<T>& p1)
	{
		m_Data = p1;
	}
	CStateNode<T>& operator= (const CStateNode<T>& p)
	{
		m_Data = p.m_Data;
		return *this;
	}
	CStateNode (T p1)
	{
		m_Data = p1;
	}
	~CStateNode (void)
	{
	}

	virtual void EnterState (void)
	{
	}
	virtual void Tick (void)
	{
	}
	virtual void ExitState (void)
	{
	}

	T& operator() (void)
	{
		return m_Data;
	}
	const T& operator() (void) const
	{
		return m_Data;
	}
};














template<class _Ty,typename TransParam>
struct TranslateState : binary_function<CStateNode<_Ty> * , TransParam , CStateNode<_Ty> *>
{
	CStateNode<_Ty> *operator()(CStateNode<_Ty> *_X,TransParam _Y) const
	{
		return _X;
	}
};

template<typename T,typename TransParam = int , class _Trans = TranslateState<T,TransParam> >
class CStateRoot
{
	struct NodeData
	{
		CStateNode<T> *data;
		Stuff::Point3D loc;
		bool owner;
		unsigned int *m_RefCount;

		NodeData (void)
		{
			data = NULL;
			owner = false;
			loc = Stuff::Point3D (0,0,0);
			m_RefCount = new unsigned int;
			*m_RefCount = 1;
		}
		NodeData (const NodeData& p1)
		{
			Verify (p1.m_RefCount);
			data = p1.data;
			owner = p1.owner;
			loc = p1.loc;
			m_RefCount = p1.m_RefCount;
			AddRef ();
		}
		NodeData& operator= (const NodeData& p)
		{
			Verify (p.m_RefCount);
			if (m_RefCount)
			{
				Release ();
			}
			m_RefCount = p.m_RefCount;
			data = p.data;
			owner = p.owner;
			loc = p.loc;
			AddRef ();

			return *this;
		}

		NodeData (CStateNode<T> *p1,bool p2=true,const Stuff::Point3D& p3=Stuff::Point3D (0,0,0))
		{
			if (m_RefCount)
			{
				Release ();
			}
			m_RefCount = new unsigned int;
			*m_RefCount = 1;
			data = p1;
			owner = p2;
			loc = p3;
		}
		~NodeData (void)
		{
			if (m_RefCount)
			{
				Release ();
			}
			data = NULL;
			owner = false;
		}
		void AddRef (void)
		{
			Verify (m_RefCount);
			(*m_RefCount)++;
		}

		bool Release (void)
		{
			Verify (m_RefCount);
			Verify (*m_RefCount);
			(*m_RefCount)--;
			if (!(*m_RefCount))
			{
				delete m_RefCount;
				if (owner)
					delete data;
				m_RefCount = NULL;
				data = NULL;
				return false;
			}
			return true;
		}

	};
protected:
	CStateNode<T> *m_CurState;
	my_vector<NodeData> m_Nodes;

public:
	CStateRoot (void)
	{
	}
	~CStateRoot (void)
	{
	}

	void AddNode (CStateNode<T> *newnode,bool owner = true)
	{
		Check_Pointer (newnode);
		m_Nodes.push_back (NodeData (newnode,owner));
	}
	void RemoveNode (CStateNode<T> *oldnode);

	void ChangeState (CStateNode<T> *newstate)
	{
		if (m_CurState != newstate)
		{
			m_CurState->ExitState ();
			m_CurState = newstate;
			m_CurState->EnterState ();
		}
	}
	void Translate (TransParam p1)
	{
		ChangeState (_Trans (m_CurState,p1));
	}

	CStateNode<T>& operator() (void)
	{
		return *m_CurState;
	}
	const CStateNode<T>& operator () (void) const
	{
		return *m_CurState;
	}
};

}

#endif



