/// @file behavior.hh
/// @author Joshua Petitt <petitj01@tartarus.uwa.edu.au>
/// @author Stefan Schmitt <sschmitt@ee.uwa.edu.au>
/// @version 1.0
/// @date 2003
///
/// Declares the abstract Behavior class.

#ifndef BEHAVIOR_HH
#define BEHAVIOR_HH

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

namespace EyeMind {

class Behavior; //forward decl
class State; //forward decl


/// Connects Behaviors.
///
/// A SignalLink connects two Behaviors and has an input Behavior and an output
/// Behavior on its two terminals. SignalLinks come in two "flavors": generic
/// and non-generic. Generic SignalLinks can be used to connect any Behaviors
/// and carry signal data. Non-generic SignalLinks are
/// subclasses of SignalLink and have to set the generic attribute to false in
/// their constructor. These non-generic SignalLinks can carry any data, modify
/// their data using functions, you name it. These non-generic SignalLinks
/// cannot be connected to any Behavior, but only to certain Behaviors that can
/// use these non-generic SignalLinks at their inputs resp. outputs. This
/// non-generic SignalLink/Behavior relation is declared by the operator
/// functions for << and >> (see example.hh).
/// The data contained in the SignalLinks is buffered, i.e. the data is fed by
/// the respective functions, then buffered and propagated by the Update()
/// functions to the output and can then be read by the counterparts of theZZ
/// feeding functions. The feeding functions are declared virtual to enable
/// processing of this data (e.g. a step function) in derived classes.
/// 
/// Note: The signal link only carries a single signal value, used for the
/// excite signal, instead of two values, signal and excitation.  JP Jul 12 2003

class SignalLink : public Updatable
{
// Connections to Behavior
friend Behavior& SignalLinkOutputToBehavior(SignalLink& l, Behavior& o);
friend Behavior& SignalLinkInputToBehavior(SignalLink& l, Behavior& i);
friend SignalLink& BehaviorOutputToSignalLink(Behavior& n, SignalLink& o);
friend SignalLink& BehaviorInputToSignalLink(Behavior& n, SignalLink& i);
friend SignalLink* DisconnectBehaviors(Behavior& s, Behavior& t);

// Connections to State
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:
	int signal; 		///< Current signal ( used by Excite() ).
	int next_signal;	///< Next signal value
	int Ks;    		///< Signal gain
	int Bs;			///< Signal bias
	int decay; 		///< Exponential decay term

	/// Should values only propagated by explicit Update() ?
	bool buffered;
	bool excite_on_update; ///< Excite out Behavior on Update?

protected:
	Behavior *in; ///< Input Behavior of SignalLink.
	Behavior *out; ///< Output Behavior of SignalLink.

	bool updated; ///< Has new data been put into SignalLink?
	bool generic; ///< Is this a generic SignalLink?

	/// Reset in, out and internal data.
	void Null();

public:
	/// Default constructor; initalizes data members.
	SignalLink();
	
	/// Virtual destructor.
	virtual ~SignalLink();


	/// Propagates the data in the input buffers to the outputs. If a
	/// Behavior is attached at the out of the link, it is excited. If you
	/// want to call this function from the Update() function of derived
	/// classes, call it at the end of your function.

	virtual bool Update();

	/// Reset the signal on the link back to zero
	void Reset();

	/// Decay the signal on the link
	void Decay();

	/// @name Data feeding functions; set update attribute to \c true
	//@{
	virtual void Signal(int s); ///< Feeds a excitation signal.
	//@}

	/// @name Attribute manipulation functions
	//@{
	Behavior* In(){ return in; } 		///< Returns input Behavior.
	Behavior* Out(){ return out; } 		///< Returns output Behavior.
	bool Updated(){ return updated; } 	///< Has new data been fed?
	bool Generic(){ return generic; } 	///< Is this Signal Link generic?
	int Signal(){ return signal+Bs; }	///< Returns current signal plus bias.
	void Invert(bool b){ Ks*=-1; } 		///< Invert the signal
	void Gain(int k){ Ks = k; }		///< Set gain
	void Bias(int b){ Bs = b; }		///< Set bias
	void Decay(int d){ decay = d; }		///< Set decay
	//@}
};


class Id; //forward declaration



/// Number of input links in Behavior.
const unsigned IN_SIGNAL_LIST_SIZE = 16;
/// Number of output links in Behavior.
const unsigned OUT_SIGNAL_LIST_SIZE = 16;

/// Behavior abstract base class. Base class for deriving specific behavior
/// objects. Each derived behavior must define its own virtual Execute()
/// function and must be fully default-constructible.
///
/// The behavior object is modeled like the Node class, which
/// allows behaviors to be linked together in a list as well as have
/// attached behaviors. The linked objects used for connecting behavior objects
/// are of class SignalLink. These come in different "flavors" (see their
/// declarations). Each behavior can use non-generic (i.e. specialized links
/// carrying more data than excitation) as inputs and outputs, according to
/// these rules:
///  1. Every Behavior must be able to do something with generic links
///  2. Only one type of non-generic link is allowed on either input or output
///
/// The Behavior class Excite() function follows a simple set of rules:
///
/// When the behavior is excited, the suppression value is subtracted
/// from the excitation value.  If the result is greater than the
/// threshold value, then the Execute() function is executed.  Each time the
/// Execute() function is executed, the excitation value is decremented by
/// an exaustion parameter and the suppression parameter is decreased by
/// an emergence parameter.
///
/// A Behavior also has an unsigned error flag and virtual OnError()
/// procedure.  By default the OnError() procedure clears the error flag.

class Behavior : public Tagged
{
friend Behavior& SignalLinkOutputToBehavior(SignalLink& l, Behavior& o);
friend Behavior& SignalLinkInputToBehavior(SignalLink& l, Behavior& i);
friend SignalLink& BehaviorOutputToSignalLink(Behavior& n, SignalLink& o);
friend SignalLink& BehaviorInputToSignalLink(Behavior& n, SignalLink& i);
friend SignalLink* DisconnectBehaviors(Behavior& s, Behavior& t);
friend Behavior& operator>>(Id& id, Behavior& b);
private:
	bool active; ///< Denotes if the behavior is active.
	bool root;   ///< Denotes if behavior is a 'root' behavior.
	bool excite_lock; ///< Locks Excite() function against recursion.
	int threshold;      ///< Threshold value of the behavior.
	int feed_signal;    ///< Signal to be fed to outlinks.
	float timebase;///< Timebase for exciting; 0 for explicit-only exciting.

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

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

	/// Error reference number.
	unsigned error;

	/// Function executed when behavior fires; returns an excitation
	/// signal value.
	virtual int Execute() = 0;


	/// Feed the SignalLink l with the appropriate data. To be called from
	/// the FeedAttached member function. Overload this function if you use
	/// non-generic links in your derived class and call this function as
	/// last instruction in the derived class's Feed function.
	virtual void Feed(SignalLink& l);

	/// Returns the sum of all the input signals
	int SumInputSignals();

	/// Reset the incoming signal links
	void DecayInputSignals();

	/// Returns the SignalLink with the highest excitation signal.
	SignalLink* FindMaxInputSignal();

	/// Returns the SignalLink with the highest excitation signal among
	/// non-generic SignalLinks.
	SignalLink* FindMaxNonGenericInputSignal();

	/// Classifies the excitation of the SignalLink.
	unsigned SignalRange(SignalLink& l);

	/// Is the excitation of the SignalLink in arbitrary range?
	bool InSignalRange(SignalLink& l, unsigned range);

	/// Reset the incoming signal links
	void ResetInputSignals();

	/// Reset the outgoing signal links
	void ResetOutputSignals();

public:
	/// Default constructor; initializes data members.
	Behavior();

	/// Virtual destructor.
	virtual ~Behavior();


	/// Excite the behavior. Each time the behavior is excited it will add
	/// the excitation value to the current level of excitation.Then the
	/// suppression value is subtracted from the excitation value and if
	/// the total is greater than the threshold value, the behavior
	/// 'fires'. When firing the first thing that is done is execution of
	/// the Execute member function Then the excitation value is decreased
	/// by an exaustion parameter and the suppression is decreased by an
	/// emergence parameter. Finally the attached Behaviors on the
	/// excite_links list are excited and all the suppress_links are
	/// suppressed.
	///
	/// @param signal Signal to be added to excitation.

	virtual void Excite(int signal);


	/// Loop through the outlinks and call Feed() for each.
	void FeedAttached();

	/// @name Attribute manipulation functions
	/// For details on the parameters read and understand the Execite()
	/// functions's source.
	//@{
	bool Active(){ return active; } ///< Is the behavior active?
	void Active(bool a){active = a; } ///< Activate/Deactivate behavior.

	/// Is the behavior attached directly to the Id?
	bool Root(){ return root; }

	/// Returns the execution treshold.
	int Threshold(){ return threshold; }

	/// Sets the execution treshold.
	void Threshold(int t){ threshold = t; }
	
	/// Return the excitation timebase.
	float Timebase(){ return timebase; }

	/// Sets the excitation timebase (call only once).
	void Timebase(float t);
	//@}

	int Error(){return error;}
	virtual void OnError(){error = 0;};
};


/// Connect SignalLink output with target Behavior.
Behavior& operator>>(SignalLink& l, Behavior& o);

/// Connect SignalLink input with source Behavior.
Behavior& operator<<(SignalLink& l, Behavior& i);

/// Add output SignalLink to Behavior.
SignalLink& operator>>(Behavior& n, SignalLink& o);

/// Add input SignalLink to Behavior.
SignalLink& operator<<(Behavior& n, SignalLink& i);

/// A synonym for DisconnectBehaviors().
SignalLink* operator|(Behavior& s, Behavior& t);



/// Connect SignalLink output with target Behavior.
/// @warning: Use this only if you exactly know what you are doing and for
/// links that are already approved by some type-checking mechanism.

Behavior& SignalLinkOutputToBehavior(SignalLink& l, Behavior& o);


/// Connect SignalLink input with source Behavior.
/// @warning: Use this only if you exactly know what you are doing and for
/// links that are already approved by some type-checking mechanism.

Behavior& SignalLinkInputToBehavior(SignalLink& l, Behavior& i);


/// Add output SignalLink to Behavior.
/// @warning: Use this only if you exactly know what you are doing and for
/// links that are already approved by some type-checking mechanism.

SignalLink& BehaviorOutputToSignalLink(Behavior& n, SignalLink& o);


/// Add input SignalLink to Behavior.
/// @warning: Use this only if you exactly know what you are doing and for
/// links that are already approved by some type-checking mechanism.

SignalLink& BehaviorInputToSignalLink(Behavior& n, SignalLink& i);


/// Disconnect this Behavior from other Behavior.
/// Note: The SignalLink object is not destroyed.
/// @param s Source Behavior
/// @param t Target Behavior to disconnect
/// @returns Lingering SignalLink* on success, NULL else
/// @warning Uses iteration, so not thread safe (see warning in templates.h)

SignalLink* DisconnectBehaviors(Behavior& s, Behavior& t);



/// @name Constants for excitation signal ranges
//@{
const unsigned EXCITE_LOW_MIN = 1;
const unsigned EXCITE_LOW_AVG = 4;
const unsigned EXCITE_LOW_MAX = 16;

const unsigned EXCITE_MED_MIN =  1001;
const unsigned EXCITE_MED_AVG =  5000;
const unsigned EXCITE_MED_MAX = 10000;

const unsigned EXCITE_HI_MIN =  100001;
const unsigned EXCITE_HI_AVG =  500000;
const unsigned EXCITE_HI_MAX = 1000000;

const unsigned EXCITE_NONE = 0;
const unsigned EXCITE_IDLE = 1;
const unsigned EXCITE_EXT = 1000000000;
//@}


/// @name Range classifiers for SignalRange()
//@{
const unsigned EXCITE_RANGE_NONE = 0;
const unsigned EXCITE_RANGE_LOW = 1;
const unsigned EXCITE_RANGE_MED = 2;
const unsigned EXCITE_RANGE_HI = 3;
//@}

/// Default Excite() signal for root behaviors, usually issued by Id.
const int ROOT_DEFAULT_EXCITE = 1;


}; // namespace EyeMind

#endif // BEHAVIOR_HH

