/// @file mind.hh
/// @author Joshua Petitt <petitj01@mech.uwa.edu.au>
/// @author Stefan Schmitt <sschmitt@ee.uwa.edu.au>
/// @version 1.0
/// @date 2003-07
///
/// Declares Id, Ego and SuperEgo base classes and Mind, a container for global
/// data and functions and communication backbone for Id, Ego, SuperEgo.

#ifndef MIND_HH
#define MIND_HH

#include "base/base.hh"
#include "base/templates.hh"
#include "behavior/behavior.hh"
#include "semantic/dictionary.hh"

///@bug Workaround if using mc-5.2
#ifndef MAX_IRQ
# define MAX_IRQ 16
#endif

namespace EyeMind {

/// Saves much typing in Mind declaration, use it in derived Minds.
#define REGISTER_WITH_MIND(type, pointer) \
private: static class type* pointer; \
public: static void Register(type& r){ NullCheck(pointer, #type); pointer = &r; } \
static type* Active##type(){ return pointer; }


#ifndef REACT
#include "state/state.hh"
/// Depth of state stack
static const unsigned STATE_STACK_SIZE=1;

/// A simple stack implementation based on fixed size array
class MindStack
{
private:
	typedef Array<State*, STATE_STACK_SIZE> StateStack;
	StateStack stack;

public:
	MindStack()
	{
	}

	~MindStack()
	{
	}


	int Push(State* s)
	{
		if(stack.Append(s)!=NULL)
			return -1;
	}

	State* Pop()
	{
		if(stack.Pos()>0)
		{
			return *stack--;
		}
	}
};
#endif


/// Container class for global data and functions; purely static, not
/// instantiable.
class Mind
{
private:
	NO_COPYING(Mind); ///< Prevent copying.

protected:
	/// Default constructor; initializes data members.
	Mind();

	/// If variable p is not NULL, panic.
	static void NullCheck(void* p, const char* who);

public:
	REGISTER_WITH_MIND(Id, id);
	REGISTER_WITH_MIND(Ego, ego);
	REGISTER_WITH_MIND(SuperEgo, superego);
	REGISTER_WITH_MIND(VWMove, vwmove);
	REGISTER_WITH_MIND(VWDrive, vwdrive);
	REGISTER_WITH_MIND(FeelPsds, feelpsds);
	REGISTER_WITH_MIND(Odometry, odometry);
	REGISTER_WITH_MIND(Dictionary, dictionary);

	#ifndef REACT
	REGISTER_WITH_MIND(MindStack, stack);
	#endif
};


/// Number of inputs/outputs in Id class lists.
static const unsigned INTERFACE_LIST_SIZE=16;

/// Number Behaviors in Id class lists.
static const unsigned BEHAVIOR_LIST_SIZE=16;



/// The "nerve system" of the agent.
class Id
{
friend Updatable& operator<<(Id& id, Updatable& i);
friend Updatable& operator>>(Id& id, Updatable& o);
friend Behavior& operator>>(Id& id, Behavior& b);
private:
	bool active; ///< Active flag.

	/// Contains handles for attached IRQ functions.
	static TimerHandle timer_handles[MAX_IRQ];

	/// Counts attached IRQ functions.
	static unsigned timer_count;

	/// Attaches a function to the TPU.
	void AttachToTimer(void (*function)(), float timebase);

protected:
	/// Array of Updatables.
	typedef Array<Updatable, INTERFACE_LIST_SIZE> Updatables;

	/// Array of Behaviors.
	typedef Array<Behavior, BEHAVIOR_LIST_SIZE> Behaviors;

	Updatables inputs; ///< All inputs of the id.
	Updatables outputs; ///< All outputs of the id.

	/// All root behaviors.
	Behaviors behaviors;

public:
	/// Default constructor; registers with Mind.
	Id();

	/// Virtual destructor; unregisters all IRQ functions.
	virtual ~Id();

	/// Make the id "clear for action"; must set Active(true).
	/// The behavior tree should be build in this function.
	virtual void Ready() = 0;

	/// @name Attribute manipulation functions
	//@{
	bool Active(){ return active; }    ///< Set active flag;
	void Active(bool b){ active = b; } ///< Returns active flag;
	//@}

	/// Excite all Behaviors in behaviors list by signal.
	void ExciteBehaviors(int signal = ROOT_DEFAULT_EXCITE);
};


/// Attach an Updatable as Input to the Id. i.Update() will be called with its
/// Timebase value. Handles multiple attachment of the same object by not
/// attaching it a second time.

Updatable& operator<<(Id& id, Updatable& i);


/// Attach an Updatable as Output to the Id. o.Update() will be called with its
/// Timebase value. Handles multiple attachment of the same object by not
/// attaching it a second time.

Updatable& operator>>(Id& id, Updatable& o);

/// Attach an Behavior to the Id. b.Excite() will be called with its
/// Timebase value. Handles multiple attachment of the same object by not
/// attaching it a second time.

Behavior& operator>>(Id& id, Behavior& b);


#ifndef REACT
/// Middle layer arbitration between Id and SuperEgo.
/// The Ego class contains a FIFO queue of states to achieve.
/// The queue of states is dictated primarily by the SuperEgo,
/// but the Ego can also modify the state list.

class Ego
{
private:
	bool active; ///< Active flag.

protected:

	States task; 	///< Desired states.
	States past; 	///< Past states.
	States states; 	///< Current states.

public:
	///< Default constructor, registers with Mind.
	Ego();

	///< Virtual destructor.
	virtual ~Ego(){}

	/// Make the ego "clear for action"; must set Active(true).
	virtual void Ready() = 0;

	/// Main processing function.	
	virtual void Think();

	/// @name Attribute manipulation functions
	//@{
	bool Active(){ return active; }    ///< Set active flag;
	void Active(bool b){ active = b; } ///< Returns active flag;
	States& CurrentStates(){ return states; } ///< Returns current states.

	/// @bug This actually does nothing.
	void AddState(State *state){}
	//@}

};



/// Container for high-level planning type algorithms. The SuperEgo has one
/// pure virtual function, Plan().  This function should create state lists
/// for the Ego to accomplish a task.

class SuperEgo
{
private:
	bool active; ///< Active flag.

protected:
	StateMemoryMap statemap; ///< Map of available states.

public:
	///< Default constructor, registers with Mind.
	SuperEgo();

	///< Virtual destructor.
	virtual ~SuperEgo(){}

	/// Make the super-ego "clear for action"; must set Active(true).
	virtual void Ready() = 0;
	
	/// Main processing function.
	virtual void Plan();

	/// @name Attribute manipulation functions
	//@{
	bool Active(){ return active; }    ///< Set active flag;
	void Active(bool b){ active = b; } ///< Returns active flag;
	//@}
};

#endif //REACT

}; // namespace EyeMind

#endif //MIND_HH
