/* itgparse.h
 *
 * Contains class and code for viterbi parsing. 
 *
 * $Id: itgparse.h,v 1.2 2011/10/16 21:39:05 gildea Exp $
 */

#include "itgchart.h"
#include "itg.h"

#ifndef PARSE_H
#define PARSE_H

namespace viterbi {

  using namespace std;

  struct ITGVCell;

  struct backpointer {
    Rule* rule;
    ITGVCell* lchild;
    ITGVCell* rchild;
    double prob;
    backpointer(){};
    backpointer(Rule* irule, ITGVCell* ilchild, ITGVCell* irchild, double iprob) {
      rule = irule;
      lchild = ilchild;
      rchild = irchild;
      prob = iprob;
    }
  };

  /* typedef TopK<backpointer> backptrs_t; */
  typedef vector<backpointer> backptr_v;

  struct ITGVCell {
    int N, s, t;
    double prob;

    // backpointers
    backptr_v backptrs;

    // redundant backpointer (for best)
    Rule *rule;
    ITGVCell* lchild, *rchild;

    // cloning
    int uses_clone;
    int clone_start;//start of cloned portion of L2
    int clone_stop;//end of cloned portion of L2

    // deprecated backpointers
/*     int S; */
/*     int U;//splitting point */
/*     int inv;//inversion rule? */
/*     int l;//rhs.l */
/*     int r;//rhs.r */

  };

  struct ITGViterbiCloneCell {
    double prob;  // probability
    int u;        // start index of clone in L2
    int v;        // stop index of clone in L2
    int N;        // nonterminal over span

    ITGViterbiCloneCell()  {
      prob = 0.0;
      u = -1;
      v = -1;
      N = -1;
    }
    ITGViterbiCloneCell(int _u, int _v, int _N0, double _prob)  {
      u = _u;
      v = _v;
      N = _N0;
      prob = _prob;
    }
  };

  struct ViterbiNode {
    int lhs, s, t, u, v;
    ViterbiNode(int lhs, int s, int t, int u, int v) {
      this->lhs = lhs;
      this->s = s;
      this->t = t;
      this->u = u;
      this->v = v;
    }
    ViterbiNode(int lhs) {
      this->lhs = lhs;
      s = t = u = v = -1;
    }
  };


  class ITGVChart {
  public:
    ITGVCell *cells;
    int totalDimen;
    int MAXT, MAXV;
    int dimenT, dimenV;

    ITGVChart(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 ITGVCell[MAXN*dimenT*dimenV];
#ifdef DEBUG
      printf("ITGVChart::ITGVChart(): %d cells (%d*%d*%d)\n",
             MAXN*dimenT*dimenV, MAXN, dimenT, dimenV);
#endif
    
    }

    ITGVCell *cell(int lhs, int s, int t, int u, int v) {
      //TODO: error checking
      //#define vcell(s, t, u, v, n) (&(vchart->cells[(s*(vchart->MAXT+1)-s*(s+1)/2+t)*vchart->dimenV*MAXN+(u*(vchart->MAXV+1)-u*(u+1)/2+v)*MAXN+n]))
      int offset1 = (s*(MAXT+1)-s*(s+1)/2+t) * dimenV * MAXN;
      int offset2 = (u*(MAXV+1)-u*(u+1)/2+v) * MAXN;
      return &(cells[offset1 + offset2 + lhs]);
    }

    double prob(int lhs, int s, int t, int u, int v) {
      return cell(lhs, s, t, u, v)->prob;
    }

    ~ITGVChart() { 
      delete[] cells;
    }
  
    void clean(int T, int V);
  };



  class ITGViterbiCloneChart  {
  public:
    ITGViterbiCloneCell * cells;
    int MAXT, MAXV; //max sentence lengths in L1, L2
    int st_size;    //size of the space needed to store the cells

    /* mt and mv are the MAXIMUM permissible sentence lengths */
    ITGViterbiCloneChart(int mt, int mv)  {
      MAXT = mt;
      MAXV = mv;
      // this is the real size, figure out offsets given that t > s
      /*     st_size = MAXT * (MAXT + 1) / 2; */
      // cheating because it's quicker
      // this wastes memory in the square of MAXT
      st_size = MAXT * (MAXT + 1);
      //assuming s < t
      cells = new ITGViterbiCloneCell[st_size];
      /*
      //multiply by MAXV since we have a best clone for each null position
      //cells = new ITGViterbiCloneCell[st_size * MAXV];
      */
    }

    ITGViterbiCloneCell *get(int s, int t)  {
      if (! checkargs(s,t))  {
        fprintf(stderr, "ITGViterbiCloneChart::get() -- invalid args (s=%d, t=%d)\n", s, t);
        exit(-1);
      }

      return &(cells[loc(s,t)]);
    }

    /* returns the probability of the requested chart entry */
    double prob(int s, int t) {
      return get(s,t)->prob;
    }

    void put(int s, int t, ITGViterbiCloneCell &cell)  {
      if (! checkargs(s,t))  {
        fprintf(stderr, "ITGViterbiCloneChart::put() -- invalid args (s=%d, t=%d)\n", s, t);
        exit(-1);
      }

      // TODO: this might be a memory leak
      cells[loc(s,t)] = cell;
    }

    void clean()  {
      int space = sizeof(ITGViterbiCloneCell) * st_size;
#ifdef DEBUG
      printf("ITGViterbiCloneChart::clean(): zeroing %d bytes\n", space);
#endif
      memset(cells, 0, space);
    }

    ~ITGViterbiCloneChart()  {
      delete[] cells;
    }

  private:
    /* makes sure s and t are valid values */
    bool checkargs(int s, int t)  {
      if (s > t || s > MAXT || t > MAXT || s < 0 || t < 0)
        /*     if (s >= t || s > MAXT - 1 || t > MAXT || s < 0 || t < 1) */
        return false;
      return true;
    }

    int loc(int s, int t)  {
      /*     return v * st_size + s + t; */
      return s * MAXT + t;
    }
  };

  class Parser : public ITG {
  public:
    Parser(ITGGrammar*,ITGCorp*);
    virtual ~Parser();

    void vinit();   // initialize gama, before viterbi selection
    void viterbi(); // get the viterbi parse

    string reconstruct(ITGVCell*);

    void dump_chart(const char *, int); //writes the chart to disk

    void run(); 

  protected:
    /* PARSING */
    ITGVChart *vchart;
    ITGViterbiCloneChart *clonechart; //for clones in viterbi parses
    int viterbi_phrase_count; //num phrases used in best parse
    int viterbi_clone_cnt; //num clones seen
    bool CLONING;

    ITGVCell* topcell_;

    FILE *pfviterbi; // file of viterbi parses
    FILE *pfafile;   // file of viterbi alignments
    FILE *pfinfo;    // file of viterbi parse information

    string viterbi_file; // name of the file of viterbi parses
    string afile_file;   // name of the file of viterbi alignments
    string info_file;    // name of the file of viterbi parse information
  };

}

#endif
