/* main.cpp   Entry point for ITG parsing, training, and decoding.
 *
 * $Id: main.cpp,v 1.2 2008/05/08 15:12:53 post Exp $
 */

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <math.h>
#include <iostream>
#include <sys/time.h>
#include <cassert>

#include "array.h"
#include "globals.h"
#include "itgtrain.h"
#include "itgparse.h"
#include "itgdec-cyk.h"

using namespace std;
using viterbi::Parser;

int main(int argc, char** argv) {

  // load the parameters
  try {
    Globals::Load(argc, argv);
  } catch (Globals::load_error err) {
    cerr << "* FATAL: error processing parameters\n";
    cerr << "error message: " << err.text << endl;
    exit(1);
  }

  // used to access command-line and config-file parameters
  Globals* globals = Globals::Instance();

  LMWEIGHT = globals->get<double>("lm_weight");
  LOGRATIOBEAM = globals->get<double>("logratiobeam");
  MAXKBUFSIZE = globals->get<int>("maxkbufsize");

  string rundir = globals->get<string>("rundir");
  string l1c = globals->get<string>("l1corpus");
  string l2c = globals->get<string>("l2corpus");
  string runid = globals->get<string>("runid");
  char runmode = globals->get<char>("runmode");

  if (chdir(rundir.data()))  {
    printf("* FATAL: couldn't chdir(%s)\n", rundir.data());
    exit(1);
  }

  int from = Globals::Get<int>("sentence_from");
  int to = Globals::Get<int>("sentence_to");
  if (from != 0 || to != 0)
    runid += "." + Xtos(from) + "-" + Xtos(to);

  if (Globals::Get<int>("verbosity") >= 1) {
    printf("Changed directory to %s\n", rundir.data());
    print_header("Parameters");
    cout << *globals << endl;
  }

  //log file
  string namebuf = string(runid) + ".log";
  logfile = fopen(namebuf.data(), "w");
  if (NULL == logfile) {
    printf("* Fatal error: couldn't open logfile '%s'\n", namebuf.data());
    exit(-1);
  }
  setvbuf(logfile, (char *)NULL, _IONBF, 0);
//   printf("Logging to file %s\n", namebuf.data());

  // write a log of the config file used
  ofstream out( (namebuf + ".config").data() );
  if (! out.is_open()) {
    cerr << "* WARNING: couldn't log configuration used" << endl;
  } else {
    out << "# This file contains the parameters and values used in\n";
    out << "# the run contained in this directory\n";
    out << *globals << endl;
    out.close();
  }

  // load the vocabularies
  l1vocab.load(globals->get<string>("l1vocabfile"));
  l2vocab.load(globals->get<string>("l2vocabfile"));

  // load the grammar
  string gramf   = Globals::Get<string>("grammarfile");
  string probs   = Globals::Get<string>("probfile");
  grammar = new ITGGrammar(gramf, probs);
  grammar->load();

  // initialize the corpus
  ITGCorp* corpus;
  corpus = new ITGCorp((char *)l1c.data(), (char *)l2c.data(), runmode);

  ITG* itg;
  switch(runmode) {
  case 't':
    itg = new Trainer(grammar,corpus);
    break;
  case 'v':
    itg = new Parser(grammar,corpus);
    break;
  case 'd':
    {
      int N = Globals::Get<int>("ngram_n");
      string decoder = Globals::Get<string>("decoder");

      ngram = new NGram(N);
      if (N >= 2 || decoder == "cyk") // all situations requiring ngram model
        ngram->load(Globals::Get<string>("ngrammodel"));

      if (decoder == "cyk")
        itg = new CYKDecoder(grammar,corpus);
      else if (decoder == "baseline")
        itg = new CYKDecoder(grammar,corpus);
      else {
        cout << "* FATAL: unknown decoder '" << decoder << "'\n";
        exit(1);
      }
    }
    break;
  default:
    cerr << "* FATAL: no such runmode '" << runmode << "'\n";
    exit(1);
  }

  itg->run();

  delete itg;
  delete corpus;
  delete grammar;
  if (runmode == 'd')  delete ngram;

  fclose(logfile);

  return 0;
}
