#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cstdlib>

#include "libphprng.h"
#include "util.h"

using namespace std;

AphGen::AphGen(char* filename) {

  string line;
  ifstream file (filename);

  if (! file.is_open()) {
    cerr << "APHGen::init(): Unable to open file `" << filename << "'" << endl;
    exit(EXIT_FAILURE);
  }

  /* Format:
   * Number of phases
   * Initial probabilities (one per line)
   * Rates (one per line)
   */

  // Read number of phases.
  getline(file, line);
  n = strtol(line.c_str(), NULL, 10);

  initialProbabilities = new double[n];
  sojournTimes = new double[n];

  // Read initial probabilities.
  int i = 0;
  while (i < n && !file.eof()) {
    getline(file, line);
    initialProbabilities[i] = strtod(line.c_str(), NULL);

    i++;
  }
  if (i < n) {
    cerr << "APHGen::init(): Could not read " << n << " initial probabilities."
	 << endl;
    delete this;
    exit(EXIT_FAILURE);
  }

  cerr<<"libphprng: Input assumed to be in ms, will be scaled to s!"<<endl;

  // Read transition rates.
  i = 0;
  while (i < n && !file.eof()) {
    getline(file, line);
    sojournTimes[i] = 1 / strtod(line.c_str(), NULL);
    sojournTimes[i] /= 1000; // Convert from milliseconds to seconds
    i++;
  }
  if (i < n) {
    cerr << "APHGen::init(): Could not read " << n << " transition rates."
	 << endl;
    delete this;
    exit(EXIT_FAILURE);
  }

#ifdef DEBUG
   cerr << "Initial probabilities: " << endl;
   for (int i = 0; i < n; i++)
     cerr << initialProbabilities[i] << endl;
   cerr << "Sojourn times rates: " << endl;
   for (int i = 0; i < n; i++)
     cerr << sojournTimes[i] << endl;
#endif

}

AphGen::~AphGen() {
  delete[] initialProbabilities;
  delete[] sojournTimes;
}

void AphGen::setUniformRandomSource(RandomSourceWrapper * randomSource) {

  rsw = randomSource;

}


/* Draw a state with probabilities as given in initialProbabilities[].
 * This comes from Levente's phnepa.cc.
 */
inline int AphGen::drawState() {

  double
    r = rsw->uni(),
    x = initialProbabilities[0];

  int i = 0;

  while (x <= r && i < n) {
    i++;
    x = x + initialProbabilities[i];
  }

  return i;
}

/* Generate and return a random variate from the distribution stored in
 * this AphGen object. This method uses the SimplePlay algorithm for APH
 * in CF-1 form. The absorbing state is supposed to be n+1. */
double AphGen::getVariate() {

  int i = drawState();
  double r = 0;

  for ( ; i < n; i++) {
    r = r - sojournTimes[i] * log(rsw->uni());
  }

  return r;
}
