#include <config.h>
#include <model/TraceMonitor.h>
#include <graph/Node.h>

#include <stdexcept>
#include <algorithm>

using std::max;
using std::min;
using std::runtime_error;
using std::invalid_argument;
using std::logic_error;

static void align(long &start, long &end, int thin)
{
    /* Ensure that (start % thin == 0) and (end % thin == 0) */

    if (start <= 0)
	start = 1;

    if (end < start)
	end = start;
	
    start = (1 + (start - 1) / thin) * thin;
    end = (end / thin) * thin;
  
    if ((end - start) % thin != 0) {
        throw logic_error("Unable to align start end and thin");
    }
}

TraceMonitor::TraceMonitor(Node const *node, long start, long end, int thin)
{
  _node = node;
  if (thin <= 0) {
    throw invalid_argument("Illegal thinning interval");
  }
  _thin = thin;
  align (start, end, thin);
  _start = start;
  _end = end;
  _size =  (end - start) / thin + 1;
  _values = (double*) calloc(_node->data.length() * _size, 
			     sizeof(double));
  _maxsize = _size;    
  _current = 0;
}

TraceMonitor::TraceMonitor(Node const *node, long start,  int thin)
{
    const long initsize = 128;

    _node = node;
    if (thin <= 0) {
      throw invalid_argument("Illegal thinning interval");
    }
    _thin = thin;
    _size = initsize;
    _start = start;
    _end = start + thin * (_size - 1);
    _values = (double*) calloc (node->data.length() * _size, 
				sizeof(double));
    _maxsize = -1;
    _current = 0;
}

TraceMonitor::~TraceMonitor ()
{
  free (_values);
}

long TraceMonitor::start() const
{
    return _start;
}

long TraceMonitor::end() const
{
    return _end;
}

long TraceMonitor::thin() const
{
    return _thin;
}

long TraceMonitor::size() const
{
    /* current sample size */
    return _current;
}

long TraceMonitor::size(long start, long end) const
{
  /* sample size between start and end */
  if (end < start)
    return 0;

  if (_current == 0)
    return 0;

  long last_monitored = _start + (_current - 1) * _thin;    
  align (start, end, _thin);

  if (start <= last_monitored && end >= _start) {
    start = max (start, _start);
    end = min (end, last_monitored);
    return (end - start) / _thin + 1;
  }
  else {
    return 0;
  }
}

void TraceMonitor::update(long iteration)
{
    if (iteration != _start + _thin * _current)
	return;

    long node_length = _node->data.length();

    /* Reallocate vector _values if it is full */
    if (_current == _size && _maxsize == -1) {
      /* Fixme: what do we do if _maxsize != -1 */
      _size = _size * 2;
      _values = (double*) 
	realloc(_values,  node_length * _size * sizeof(double));
      _end = _start + _thin * (_size - 1);
    }
    for (long i = 0; i < node_length; i++) {
      _values[node_length * _current + i] = _node->data.value()[i];
    }
    _current++;
}

double const *TraceMonitor::values() const
{
  return _values;
}

/*
//FIXME: This belongs somewhere else
void TraceMonitor::dump (ostream &str, long start, long end) const
{
    if (size(start, end) == 0)
	return;

    start = max(start, _start);
    end = min(end, _end);

    if (_node->name().empty()) {
      throw runtime_error("Can't dump nameless node");
    }
    // Write output as an S struct 

    str << "\"" << _node->name() << "\" = structure(c(";
    long node_length = _node->data.length();
    long iter_length = size(start, end);
    for (long j = 0; j < node_length; j++) {
      for (long i = 0; i < iter_length; i++) {
	double v = _values[j + i * node_length];
	if (v == JAGS_NA) {
	  str << "NA";
	}
	else {
	  str << v;
	}
	if (i < iter_length - 1 || j < node_length - 1)
	  str << ",";
      }
    }
    str << "), mcpar = c(" << start << "," << end << "," << _thin << "),";
    if (node_length > 1) {
      // For multivariate nodes, add .Dim attribute 
      str << ".Dim = c(" << iter_length;
      int ndim = _node->data.ndim(false);
      for (long k = 0; k < ndim; k++) {
	str << ",";
	str << _node->data.upper()[k] - _node->data.lower()[k] + 1;
      }
      str << "), ";
    }
    str << "class = \"mcarray\")";
    //str << "Names = \"" << _node->name() << "\")\n";
}
*/

Node const *TraceMonitor::node() const
{
  return _node;
}





syntax highlighted by Code2HTML, v. 0.9.1