/// @file node.hh
/// @author Joshua Petitt <petitj01@tartarus.uwa.edu.au>
/// @author Stefan Schmitt <sschmitt@ee.uwa.edu.au>
/// @version 1.0
/// @date 2003-07
/// 
/// This file defines the Link and Node base classes. The classes hold no data,
/// but allow the connection of nodes in a net structure.
/// 
/// These classes are not really useful. They are just a kind of agenda for how
/// to declare and implement other classes that interact in means of nodes and
/// links, too. These examples, being sort of a "semantic" template, is for
/// human brain use in opposition to a "syntactic" template for compiler use
/// (the latter refering to the \c template keyword of C++). It is definitely
/// possible to implement this as a syntactiv template, but it would be
/// difficult to write and very ugly; just have a look at the STL source code
/// and you'll know how ugly.
/// 
/// The Node and Link classes could indeed be used as abstract base classes for
/// other classes that interact using this scheme. But this would almost
/// totally remove compile-time type checking, leading to some kind of
/// Smalltalk-like dynamic typing and would thus involve excessive runtime type
/// checking, which is costly in speed, memory, typing and programmer's brains.
/// 
/// Remember: This is C++. Inheritance is \b not for code reuse.

#ifndef NODE_HH
#define NODE_HH

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

/// THE NAMESPACE.
namespace EyeMind {

const unsigned LINK_LIST_SIZE = 4; ///< Number of Link in Links collection.

class Node;  // forward declaration


/// Link Base Class.
/// 
/// Each link, when created, is given a unique tag which can be used to
/// identify a link.
/// 
/// The Link also contains two pointers to Node objects, thus this class is a
/// "link" between two end points, i.e. Nodes.
/// 
/// To establish the link, use the operators:
/// <tt>SourceNode >> Link >> TargetNode;</tt>
/// or
/// <tt>TargetNode << Link << SourceNode;</tt>
/// 
/// @warning: This is just an example. Don't derive anything from this class,
/// just copy the code you find useful into your own class.

class Link : public Updatable
{
friend Node& LinkOutputToNode(Link& l, Node& o);
friend Node& LinkInputToNode(Link& l, Node& i);
friend Link& NodeOutputToLink(Node& n, Link& o);
friend Link& NodeInputToLink(Node& n, Link& i);
friend Link* DisconnectNodes(Node& s, Node& t);
private:
	Node *in; ///< Input Node of Link.
	Node *out; ///< Output Node of Link.

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

public:
	/// Default constructor; end points are NULLed.
	Link();

	/// @name Attribute manipulation functions
	//@{
	Node* In(){ return in; } ///< Returns input Node.
	Node* Out(){ return out; } ///< Returns output Node.
	//@}
};



/// Links collection.
typedef Array<Link, LINK_LIST_SIZE> Links;



/// Node Base Class.
/// 
/// The Node is given a unique tag which can be used to identify the
/// object in a collection.
/// 
/// @warning: This is just an example. Don't derive anything from this class,
/// just copy the code you find useful into your own class.

class Node : public Tagged
{
friend Node& LinkOutputToNode(Link& l, Node& o);
friend Node& LinkInputToNode(Link& l, Node& i);
friend Link& NodeOutputToLink(Node& n, Link& o);
friend Link& NodeInputToLink(Node& n, Link& i);
friend Link* DisconnectNodes(Node& s, Node& t);
protected:
	Links inlinks;  ///< Input Links collection.
	Links outlinks; ///< Output Links collection.
};



/// Connect Link output with target Node.
Node& operator>>(Link& l, Node& o);


/// Connect Link input with source Node.
Node& operator<<(Link& l, Node& i);


/// Add output Link to Node.
Link& operator>>(Node& n, Link& o);


/// Add input Link to Node.
Link& operator<<(Node& n, Link& i);


/// Disconnect this Node from other Node.
Link* operator|(Node& s, Node& t);



/// Connect Link output with target Node.
Node& LinkOutputToNode(Link& l, Node& o);


/// Connect Link input with source Node.
Node& LinkInputToNode(Link& l, Node& i);


/// Add output Link to Node.
Link& NodeOutputToLink(Node& n, Link& o);


/// Add input Link to Node.
Link& NodeInputToLink(Node& n, Link& i);


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

Link* DisconnectNodes(Node& s, Node& t);


}; // namespace EyeMind

#endif //NODE_HH

