#ifndef MODEL_H_
#define MODEL_H_

#include <graph/Graph.h>

#include <vector>
#include <list>

class Sampler;
class TraceMonitor;
class SamplerFactory;

/**
 * @short Graphical model 
 *
 * The purpose of the model class is to collect together all the
 * elements necessary to run a MCMC sampler on a graphical model.
 */
class Model {
  Graph _graph;
  long _iteration;
  std::vector<Node*> _nodes;
  std::set<Node*> _extra_nodes;
  std::vector<Node*> _sampled_extra;
  std::vector<Sampler*> _samplers;
  std::set<Node*>  _monitored_nodes;
  std::list<TraceMonitor*> _monitors;
  bool _initialized;
  bool _cansample;
public:
  Model();
  virtual ~Model();

  Graph &graph();
  /**
   * Checks that the graph is closed and acyclic. A runtime_error
   * is thrown if it is not
   */
  void checkGraph();
  /**
   * Returns true if the graph has been checked
   */
  bool isGraphChecked();
  /**
   * Initializes the model.  Nodes that have not had their values set
   * are initialized by a call to the Node::initialize function (which
   * typically will do forward sampling).  
   */
  void initialize();
  /** Returns true if the model has been initialized */
  bool isInitialized();
  /** Selects samplers for each stochastic node in the graph 
   *
   * @param samplers Vector of Sampler factories. Each factory is
   * tried in turn. If there are any informative stochastic nodes left
   * without samplers after all factories have been tried, then a
   * runtime error is thrown
   */
  void chooseSamplers(std::vector<SamplerFactory const*> const &samplers);
  /** 
   * Updates the model by niter iterations. A logic_error is thrown if
   * the model is uninitialized.
   *
   * @param niter Number of iterations to run
   */
  void update(long niter);
  /**
   * Returns the current iteration number
   */
  long iteration() const;
  /**
   * Creates a monitor for the given node, with given thinning interval
   * If the node is already being monitored, a NodeError is thrown.
   * A side effect is to turn off burnin mode for all samplers in the model.
   */
  TraceMonitor const * setMonitor(Node *node, int thin);
  /**
   * Clears the monitor associated with the given node. If there is
   * no such monitor, then the function has no effect.
   */
  void clearMonitor(Node const *node);
  /**
   * Returns the list of monitors
   */
  std::list<TraceMonitor*> const &monitors() const;
  /**
   * After the model is initialized, extra uninformative nodes may be
   * added to the graph (For example, you may wish to add a node that
   * calculates the deviance of the model).  The model takes
   * responsibility for the extra node.
   *
   * The extra node cannot be observed, it must not already be in the
   * model graph, it may not have any children, and all of its parents
   * must be in the graph.
   */
  void addExtraNode(Node *node);
};

#endif /* MODEL_H_ */


syntax highlighted by Code2HTML, v. 0.9.1