/* itgchart.h
 *
 * $Id: itgchart.h,v 1.10 2008/05/08 15:12:52 post Exp $
 */

#ifndef ITGCHART_H
#define ITGCHART_H

#include <queue>
#include <functional>
#include <stack>
#include <list>
#include <unistd.h>

#include "globals.h"
#include "itggrmr.h"
#include "cell.h"

using namespace std;

/** TRAINING ****************************************************/

struct ITGCell {
  double alpha;
  double beta;
};


class ITGChart {
 public:
  ITGCell *cells;//the cells

  int MAXT, MAXV;//the limits of length
  int dimenT, dimenV;//the dimension of the chart
  int totalDimen;//the product of the above two

  double *clones;//stores mass for (s,t) pairs
  double clone_mass;//total clone mass
  double total_mass;//stores total mass
  int cloneDimen;//space used by clone values

  /* returns the outside probability of the given region */
  double outside(int s, int t, int u, int v, int lhs)  {
    ITGCell *cell = get_cell(lhs,s,t,u,v);
    return cell->alpha;
  }

  /* returns the inside probabilty of the given region */
  double inside(int s, int t, int u, int v, int lhs)  {
    ITGCell *cell = get_cell(lhs,s,t,u,v);
    return cell->beta;
  }

  /* adds to the inside probability mass, as well as to the clone mass */
  double incr_inside(int s, int t, int u, int v, int lhs, double mass,
                     bool cloning = false, bool from_clone = false)  {

    if (cloning) {
      total_mass += mass;
      if (from_clone) 
        clone_mass += mass;
    }

    ITGCell *cell = get_cell(lhs,s,t,u,v);
    return cell->beta += mass;
  }

  /* adds to the outside probability mass */
  double incr_outside(int s, int t, int u, int v, int lhs, double mass)  {
    ITGCell *cell = get_cell(lhs,s,t,u,v);
    return cell->alpha += mass;
  }

  /* returns the clone mass for the L1 span */
  double clone(int s, int t)  {
    //TODO: write this function
    double *dub = get_clone(s,t);
    return *dub;
  }

  /* adds to the outside probability mass */
  double incr_clone(int s, int t, double mass)  {
    //TODO: write this function
    double *dub = get_clone(s,t);
    return *dub += mass;
  }

  ITGCell *cell(int lhs, int s, int t, int u, int v) {
    return get_cell(lhs,s,t,u,v);
  }

  ITGChart(int mt, int mv){
    MAXT = mt; 
    MAXV = mv; 

    dimenT = MAXT * (MAXT + 3) / 2 + 1;
    dimenV = MAXV * (MAXV + 3) / 2 + 1;
    totalDimen = dimenT * dimenV;
    cells = new ITGCell[MAXN * dimenT * dimenV];

    cloneDimen = MAXT * (MAXT + 1) / 2;
    clones = new double[cloneDimen];

    clone_mass = total_mass = 0.0;
  }

  ~ITGChart(){
    delete[] cells;
    delete[] clones;
  }

  void clean(int T, int V);//clean the protion specified by T, V

 private:
  // gets the cell from our data structure
  ITGCell * get_cell(int lhs, int s, int t, int u, int v)  {
    //TODO: error checking
    return &(cells[(s*(MAXT+1)-s*(s+1)/2+t)*dimenV*MAXN+(u*(MAXV+1)-u*(u+1)/2+v)*MAXN+lhs]);
  }

  /* get_clone(s,t)
   * Returns the accumulated mass for the specified range.
   * Restriction on indices: t > s
   */
  double * get_clone(int s, int t)  {
    //TODO: error/bounds checking
    if (t <= s)  {
      fprintf(stderr, "ITGChart::get_clone(%d,%d): invalid arguments\n",s,t);
      abort();
    }
    return &(clones[(s*MAXT-s*(s+1)/2+t)]);
  }
};



#endif
