#include <config.h>
#include <sampler/FiniteSampler.h>
#include <distributions/DistDiscrete.h>
#include <graph/StochasticNode.h>
#include <graph/Graph.h>

#include <cmath>
#include <string>
#include <stdexcept>

#include <Rmath.h>

using std::logic_error;
using std::string;

FiniteSampler::FiniteSampler(StochasticNode *node, Graph const &graph)
  : GibbsSampler(node, graph)
{
  if (!canSample(node, graph))
    throw logic_error("Attempt to construct invalid FiniteSampler");
}

FiniteSampler::~FiniteSampler()
{}

void FiniteSampler::update()
{
  Distribution const *dist = node()->distribution();

  long lower = static_cast<long>(dist->lowerSupport(0, node()->parameters()));
  long upper = static_cast<long>(dist->upperSupport(0, node()->parameters()));

  long size = upper - lower + 1;
  double *lik = new double[size];
  double liksum = 0.0;
  for (long i = 0; i < size; i++) {
    double ivalue = lower + i;
    setValue(&ivalue, 1);
    lik[i] = exp(logFullConditional());
    liksum += lik[i];
  }

  /* Sample */
  double urand = runif(0.0, liksum);
  long i;
  liksum = 0.0;
  for (i = 0; i < size - 1; i++) {
    liksum += lik[i];
    if (liksum > urand) {
      break;
    }
  }
  double ivalue = lower + i;
  setValue(&ivalue, 1);
  delete [] lik;
}

bool FiniteSampler::canSample(StochasticNode const *node,
			      Graph const &graph)
{
  //Node must be scalar with discrete-valued distribution of full rank
  Distribution const *dist = node->distribution();
  if (!dist->isDiscreteValued())
    return false;

  if (node->data.length() != 1)
    return false;

  if (dist->df(node->parameters()) != 1)
    return false;
  
  //Distribution cannot be unbounded
  if (dist->upperSupport(0, node->parameters()) == DBL_MAX ||
      dist->lowerSupport(0, node->parameters()) == -DBL_MAX) {
    return false;
  }
  else {
    double n = dist->upperSupport(0, node->parameters()) -
      dist->lowerSupport(0, node->parameters()) + 1;
    return (n > 0 && n <= 20); //fixme: totally arbitrary
    //fixme: should add condition that discrete-valued parents are fixed
  }
}

void FiniteSampler::burninOff()
{}


syntax highlighted by Code2HTML, v. 0.9.1