// file: ht_lattice_0.cc
//
// isip include files
//
#include "hmm_train.h"
#include "hmm_train_constants.h"

// method: build_lattice_cc 
//
// arguments:
//
//  Train_Trace** array: (input) array of sentence-end traces
//  int_4 num_hyp: (input) number of sentence end traces
//  float_4 lmscale: (input) the desired language model scale factor
//  float_4 wdpenalty: (input) the desired word insertion penalty
//  Train_Lattice*& lattice: (output) the lattice built from these hyps
//
// return: a logical_1 indicating status
//
// this method backtracks all word end traces for the given hypotheses
// and writes them into a lattice structure
//
logical_1 build_lattice_cc(Train_Trace** array_a, int_4 num_hyp_a,
			   float_4 lmscale_a, float_4 wdpenalty_a,
			   Train_Lattice*& lattice_a) {

  // memory manager
  //
  Train_Memory_manager* manager = Train_Link_list::get_manager_cc();
  
  // dummy variables
  //
  int_4 num_nodes = (int_4)0; 
  int_4 num_arcs = (int_4)0; 

  // set up a hash table to temporarily hold the lattice nodes
  //
  Train_Hash_table* lathash = new Train_Hash_table(TRAIN_HASH_TABLE_SIZE);
  
  // create the lattice start node
  //
  Train_Lattice_node* latn = manager->new_lat_cc();
  latn->set_frame_index_cc((int_4)0);
  latn->set_node_index_cc(num_nodes++);

  // insert it in the hash table
  //
  Train_Hash_cell* hcell = manager->new_hash_cc();
  char_1* str = new char_1[TRAIN_LATTICE_KEYSTR_LENGTH];
  sprintf((char*)str, "%p", (Train_Trace*)NULL);
  hcell->set_cc(str, latn);
  lathash->hash_insert_cc(hcell);
  
  // loop over all sentence end traces
  //
  for (int_4 i = 0; i < num_hyp_a; i++) {

    // for each sentence end trace back-track over all paths merging
    // here and construct lattice
    //
    construct_lattice_cc(array_a[i], (Train_Lattice_node*)NULL, (float_8)0,
			 lmscale_a, wdpenalty_a, num_nodes, num_arcs,
			 lathash);
  }
  
  // create a new lattice, if the lattice is already created free memory
  //
  if (lattice_a != (Train_Lattice*)NULL) {
    delete lattice_a;
  }
  lattice_a = new Train_Lattice();

  // set the lattice properties
  //
  if (lmscale_a == (float_4)0) {
    lmscale_a = (float_4)1.0;
  }
  lattice_a->set_lm_scale_cc(lmscale_a);
  lattice_a->set_word_penalty_cc(wdpenalty_a);

  // set the lattice start node
  //
  lattice_a->set_start_node_cc(latn);
  
  // set the correct numbers of nodes and arcs
  // 
  lattice_a->set_num_nodes_cc(num_nodes);
  lattice_a->set_num_arcs_cc(num_arcs);
  
  // insert the lattice nodes in the lattice
  //
  Train_Hash_cell* ncell = (Train_Hash_cell*)NULL;
  Train_Hash_cell** hcells = lathash->get_cells_cc();
  int_4 hsize = lathash->get_size_cc();
  for (int_4 i = 0; i < hsize; i++) {
    for (Train_Hash_cell* cell = hcells[i]; cell != (Train_Hash_cell*)NULL;
	 cell = ncell) {
      latn = (Train_Lattice_node*)(cell->get_item_cc());
      lattice_a->set_lat_node_cc(latn);
      ncell = cell->get_next_cc();
      manager->delete_cc(cell);
    }
    hcells[i] = (Train_Hash_cell*)NULL;
  }

  // free memory
  //
  delete lathash;

  // reorder the lattice
  //
  lattice_a->index_nodes_cc();

  // exit gracefully
  //
  return ISIP_TRUE;
}
