#ifndef NODE_H_
#define NODE_H_

#include <set>
#include <string>
#include <sarray/SArray.h>

class NodeNameTab;

/**
 * Abstract base class for nodes in a directed graphical model.
 *
 * Nodes are reference managed and will delete themselves when the
 * reference count reaches zero.  Referencing and dereferencing
 * takes place automatically when a node is inserted into/removed
 * from a graph, but can also be done by calling the ref() and
 * unref() member functions.
 *
 * Nodes should be dynamically allocated, and should be inserted
 * into a Graph as soon as they are created.  
 *
 * @see Graph
 * @short Node in a directed graphical model
 */
class Node {
  std::set<Node*> _parents;
  std::set<Node*> _children;
  unsigned int _ref;
  
  /* Forbid copying of Node objects */
  Node(Node const &orig);
  Node &operator=(Node const &rhs);
public:
  /**
   * Numerical value of the node.
   */
  SArray data;
  /**
   * Constructor. Creates a node whose data member has dimension
   * dim
   */
  Node(Index const &dim);
  /**
   * Destructor. The node is unlinked before being deleted.
   */
  virtual ~Node();
  /**
   * Increments the reference count.
   */
  void ref();
  /**
   * Decrements reference count. The node deletes itself when the
   * reference count is zero.
   */
  void unref();
  /**
   * Shows the current reference count.
   */
  unsigned int refCount();
  /**
   * Set of parents.
   */
  std::set<Node*> const &parents() const;
  /** 
   * Set of children.
   */
  std::set<Node*> const &children() const;
  /**
   * Adds parent.  The parent node is modified so that this node is
   * added to its set of children.  It is an error to attempt to add a
   * node as a parent of itself.
   *
   * There is no corresponding addChild member function since, in a
   * directed graphical model, a node is defined in terms of its parents.
   *
   * @exceptions NodeError
   */
  void addParent(Node *node);
  /** 
   * Remove parent. The parent node is modified so that this node is
   * remove from its set of children.  If node is not a parent
   * of this node, then nothing happens.
   */
  void removeParent(Node *node);
  /**
   * Removes all parent and child connections.  This is a necessary
   * preliminary to deletion. Hence unlink is called by the destructor.
   */
  void unlink();
  /**
   * Sample a value for the node based only on its parent's values.
   */
  virtual void forwardSample() = 0;
  /**
   * Initializes the node.  The default behaviour is to call
   * forwardSample() but this can be overloaded by any subclass. It
   * is an error to attempt to initialize a node before its
   * parents. Call canInitialize() first to test this. It is also an
   * error to attempt to re-initialize a node. Call isInitialized()
   * first to test this.  
   * @exceptions NodeError
   */
  virtual void initialize();
  /**
   * Shows whether a node is already initialized.
   */
  bool isInitialized();
  /**
   * A node can be initialized only if all of its parents are initialized.
   */
  virtual bool canInitialize();
  /**
   * Returns the name of the node.  The default implementation looks up
   * the node in the supplied name table and returns an empty string if it
   * is not found. Subclasses can overload this function and try to calculate
   * the Node name based on the names of it's parents.
   *
   * @param name_table Lookup table for node names.
   */
  virtual std::string name(NodeNameTab const &name_table) const;
  /**
   * Returns true if the node is a stochastic node.
   */
  virtual bool isStochastic() const = 0;
};

/**
 * Returns true if the Node's data is fixed 
 */ 
bool isObserved(Node const *node);

#endif /* NODE_H_ */


syntax highlighted by Code2HTML, v. 0.9.1