/// @file state.hh
/// @author Joshua Petitt <petitj01@tartarus.uwa.edu.au>
/// @author Stefan Schmitt <sschmitt@ee.uwa.edu.au>
/// @date 2003-07
/// 
/// Declares tristate, LocigalNode, LogicalLink and State class.

#ifndef STATE_HH
#define STATE_HH

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

namespace EyeMind {

/// @name Definitions for tristate logic
/// @note Do not evaluate tristate types with boolean expressions,
/// since it does not lead to correct results.
//@{
/// Tristate logic type.
typedef signed char tristate;

const signed char TRISTATE_TRUE = 1;    ///< .
const signed char TRISTATE_FALSE = -1;  ///< .
const signed char TRISTATE_UNKNOWN = 0; ///< .
//@}


static const unsigned DEPENDENCY_LIST_SIZE=8;

class LogicalNode; // forward declaration

class LogicalNodeBase : Tagged
{
private:
protected:
	tristate value;

public:
	LogicalNodeBase();
	virtual ~LogicalNodeBase(){}
	
	///@name Attribute manipulation functions
	//@{
	void Value(tristate v); ///< Sets logical value.
	tristate Value(){ return value; } ///< Returns current logical value.
	//@}

	/// Evaluate the node.
	virtual tristate Evaluate() = 0;

	/// Resolve the state of the node (if possible).
	virtual tristate Resolve(){ return value; }
};

/// LogicalLink connects two logical nodes.
/// The link holds no data, only serves as a connection.

class LogicalLink : public Tagged
{
protected:
	LogicalNodeBase *up;   ///< Upward LogicalNodeBase of LogicalLink.
	LogicalNodeBase *down; ///< Downward LogicalNodeBase of LogicalLink.

	/// Reset in and out.
	void Null(){ up = NULL; down = NULL; }

public:
	/// Default constructor; initalizes data members.
	LogicalLink(){Null();}

	/// @name Attribute manipulation functions
	//@{
	/// Returns upward LogicalNodeBase.
	LogicalNodeBase* Up(){ return up; }
	/// Returns downward LogicalNodeBase.
	LogicalNodeBase* Down(){ return down; }
	//@}

	/// Returns value of input LogicalNodeBase.
	tristate Value();
};



/// Abstract base class for specific tristate logic operations.

class LogicalNode : public LogicalNodeBase
{
friend LogicalNode& LogicalLinkDownToLogicalNode(LogicalLink& l, LogicalNode& d);
friend LogicalNode& LogicalLinkUpToLogicalNode(LogicalLink& l, LogicalNode& u);
friend LogicalLink& LogicalNodeDownToLogicalLink(LogicalNode& n, LogicalLink& d);
friend LogicalLink& LogicalNodeUpToLogicalLink(LogicalNode& n, LogicalLink& u);
protected:
	/// Upward LogicalLinks collection.
	Array<LogicalLink, DEPENDENCY_LIST_SIZE> uplinks;

	/// Downward LogicalLinks collection.
	Array<LogicalLink, DEPENDENCY_LIST_SIZE> downlinks;

public:
	/// Default constructor; sets value TRISTATE_UNKNOWN.
	LogicalNode();

	/// Virtual destructor
	virtual ~LogicalNode(){}

};

/// Tristate AND logical node.
/// The truth-table for the AND node is:
/// 
/// T AND T = T
/// T AND F = F
/// F AND F = F
/// T AND ? = ?
/// F AND ? = F
/// ? AND ? = ?
/// 
class ANDNode : public LogicalNode
{
private:
	void AND(tristate b);

public:
	ANDNode(){}
	~ANDNode(){}

	virtual tristate Evaluate();
};



/// Tristate OR logical node.
/// The truth-table for the OR node is:
/// 
/// T OR T = T
/// T OR F = T
/// F OR F = F
/// T OR ? = T
/// F OR ? = ?
/// ? OR ? = ?

class ORNode : public LogicalNode
{
private:
	void OR(tristate b);

public:
	ORNode(){}
	~ORNode(){}

	virtual tristate Evaluate();
};


class LogicalBranch : public LogicalNodeBase
{
friend LogicalBranch& LogicalLinkDownToLogicalNode(LogicalBranch& l, LogicalNode& d);
friend LogicalBranch& LogicalLinkUpToLogicalNode(LogicalBranch& l, LogicalNode& u);
friend LogicalLink& LogicalBranchDownToLogicalBranch(LogicalNode& n, LogicalBranch& d);
friend LogicalLink& LogicalBranchUpToLogicalBranch(LogicalNode& n, LogicalBranch& u);
protected:
	/// Upward LogicalLinks collection.
	Array<LogicalLink, DEPENDENCY_LIST_SIZE> uplinks;

	LogicalLink* left;
	LogicalLink* right;
	// Not sure about that, e.g. for 'else':
	// LogicalLink* alternate;

public:
	LogicalBranch();

	/// Virtual destructor
	virtual ~LogicalBranch(){}

	/// Returns abitrary branch.
	virtual LogicalLink& Branch() = 0;
};



/// A State is a tri-state logical node which can be connected to behaviors
/// via SignalLinks. A State can both receive and send signals from behaviors.

class State : public LogicalNodeBase
{
friend State& SignalLinkOutputToState(SignalLink& l, State& o);
friend State& SignalLinkInputToState(SignalLink& l, State& i);
friend SignalLink& StateOutputToSignalLink(State& n, SignalLink& o);
friend SignalLink& StateInputToSignalLink(State& n, SignalLink& i);
private:
protected:
	LogicalLink* up;

	///List of attached incoming SignalLinks.
	Array<SignalLink, IN_SIGNAL_LIST_SIZE> inlinks;

	///List of attached outgoing SignalLinks.
	Array<SignalLink, OUT_SIGNAL_LIST_SIZE> outlinks;

public:
	/// Default constructor.
	State();

	//THESE FUNCTIONS ARE HERE FOR FUTURE DEVELOPMENT
	//virtual int LearnGood(SuperEgo *superego) = 0;
	//virtual int LearnBad(SuperEgo  *superego) = 0;
	//virtual int Criticise(Id *id) = 0;
};



///////////////////////////////////////////////////////////////////////////
// Dependencies attachment + Link creation
// u: upward node
// d: downward node
// return right operand

// LogicalNode and LogicalNode:
LogicalNode& operator>>(LogicalNode& u, LogicalNode& d);
LogicalNode& operator<<(LogicalNode& d, LogicalNode& u);

// LogicalBranch and LogicalBranch:
LogicalBranch& operator>>(LogicalBranch& u, LogicalBranch& d);
LogicalBranch& operator<<(LogicalBranch& d, LogicalBranch& u);

// LogicalNode and LogicalBranch:
LogicalNode& operator>>(LogicalBranch& u, LogicalNode& d);
LogicalBranch& operator<<(LogicalNode& d, LogicalBranch& u);
LogicalBranch& operator>>(LogicalNode& u, LogicalBranch& d);
LogicalNode& operator<<(LogicalBranch& d, LogicalNode& u);

// LogicalNode and State:
State& operator>>(LogicalNode& u, State& d);
LogicalNode& operator<<(State& d, LogicalNode& u);

// LogicalBranch and State:
State& operator>>(LogicalBranch& u, State& d);
LogicalBranch& operator<<(State& d, LogicalBranch& u);



///////////////////////////////////////////////////////////////////////////
// Dependencies detachment + Link destruction
// u: upward node
// d: downward node
// return d
LogicalNode& operator|(LogicalNode& u, LogicalNode& d);
LogicalBranch& operator|(LogicalBranch& u, LogicalBranch& d);
LogicalNode& operator|(LogicalBranch& u, LogicalNode& d);
LogicalBranch& operator|(LogicalNode& u, LogicalBranch& d);
State& operator|(LogicalNode& u, State& d);
State& operator|(LogicalBranch& u, State& d);



// State attachment to SignalLinks
State& operator>>(SignalLink& l, State& o);
State& operator<<(SignalLink& l, State& i);
SignalLink& operator>>(State& n, SignalLink& o);
SignalLink& operator<<(State& n, SignalLink& i);





/// @bug This declaration should NOT be made here, but is needed in both
///      the mind.hh and the memorymap.hh files
///Number of states in the Ego class lists.
const unsigned STATE_LIST_SIZE=16;
typedef Array<State, STATE_LIST_SIZE> States;


}; // namespace EyeMind

#endif //STATE_HH
