// file: dec_write_2.cc
//

// system include files
//
#include <memory.h>
#include <string.h>

// isip include files
//
#include "decoder.h"
#include "decoder_constants.h"
 
// method: write_output_cc
//
// arguments:
//  FILE* fp: (input) output file pointer
//  Path_list* final_plist: (input) final partial path list
//
// return: logical_1 indicating status
//
// this method writes the decoder output hypothesis to file
//
logical_1 Decoder::write_nbest_cc(FILE* fp_a, Path_list* final_plist_a) {

  // check file
  //
  if (fp_a == (FILE*)NULL) {
    error_handler_cc((char_1*)"write_nbest_cc",
                     (char_1*)"NULL input file pointer");
  }

  // dummy variables
  //
  int_4 num_paths = (int_4)0;
  int_4 frame_index = (int_4)0;
  static char_1* hypothesis = new char_1[ISIP_MAX_STRING_LENGTH];
  static char_1* temp_string = new char_1[ISIP_MAX_STRING_LENGTH];
  Lattice_node* lat_node = (Lattice_node*)NULL;
  Link_node* next_pnode = (Link_node*)NULL;
  Nbest_node* nnode = (Nbest_node*)NULL;
  Nbest_node* prev_node = (Nbest_node*)NULL;
  Word* word = (Word*)NULL;
  Hash_table* hyp_table = new Hash_table((int_4)ISIP_2EXP16);
  Hash_cell* hyp_cell = (Hash_cell*)NULL;
  Memory_manager* manager = Link_list::get_manager_cc();
  
  // get the partial paths list
  //
  Link_list* path_list = final_plist_a->get_paths_cc();

  // loop through this list and get unique nbest hypothesis
  //
  if (path_list != (Link_list*)NULL) {
    for (Link_node* node = path_list->get_head_cc();
	 node != (Link_node*)NULL; node = next_pnode) {
      
      // get the nbest node and the lattice node corresponding to this
      // partial path
      //
      nnode = (Nbest_node*)(node->get_item_cc());
      lat_node = nnode->get_lnode_cc();
      frame_index = lat_node->get_frame_index_cc();	      
      word = lat_node->get_word_cc();
      prev_node = nnode;
      
      // back track through the nbest nodes corresponding to this
      // partial path and populate the hypothesis
      //
      while(word != (Word*)NULL) {

	// add word to hypothesis
	//
	sprintf((char*)temp_string, "%s %s", (char*)word->get_name_cc(),
		(char*)hypothesis);
	strcpy((char*)hypothesis, (char*)temp_string);
	
	// get the previous node/word
	//
	prev_node = prev_node->get_prev_cc();
	lat_node = prev_node->get_lnode_cc();
	frame_index = lat_node->get_frame_index_cc();
	word = lat_node->get_word_cc();
      }

      // get next partial hypothesis in the final list
      //
      next_pnode=node->get_next_cc();
      
      // see if this hypothesis exists in the hash table
      //
      hyp_cell = hyp_table->hash_lookup_cc(hypothesis);
      
      // if the hypothesis already exists, remove this node from the path list
      // this can be done because the list already ordered
      //
      if (hyp_cell != (Hash_cell*)NULL) {

	// remove the nbest node form the final list
	//
	delete nnode;

	// free the corresponding link node
	//
	path_list->remove_cc(node);
      }

      // else add to the hypothesis table
      //
      else {
	hyp_cell = manager->new_hash_cc();
	hyp_cell->set_cc(hypothesis, (void_p)nnode);
	hyp_table->hash_insert_cc(hyp_cell);
      }
	
      // print the hypothesis and reset the string
      //
      memset(hypothesis, (int_4)0, strlen((char*)hypothesis));
      memset(temp_string, (int_4)0, strlen((char*)temp_string));
    }
  }

  // get the partial paths list
  //
  path_list = final_plist_a->get_paths_cc();
  
  // loop through this list and print the unique nbest hypothesis
  //
  if (path_list != (Link_list*)NULL) {
    for (Link_node* node = path_list->get_head_cc();
	 node != (Link_node*)NULL && num_paths < num_nbest_d;
	 node = next_pnode) {
      
      // get the nbest node and the lattice node corresponding to this
      // partial path
      //
      nnode = (Nbest_node*)(node->get_item_cc());
      lat_node = nnode->get_lnode_cc();
      frame_index = lat_node->get_frame_index_cc();	      
      word = lat_node->get_word_cc();
      prev_node = nnode;
      
      // get the utterance score
      //
      sprintf((char*)hypothesis, "%f", nnode->get_score_cc());
      
      // back track through the nbest nodes corresponding to this
      // partial path and populate the hypothesis
      //
      while(word != (Word*)NULL) {

	// add word to hypothesis
	//
	sprintf((char*)temp_string, "%s %s", (char*)word->get_name_cc(),
		(char*)hypothesis);
	strcpy((char*)hypothesis, (char*)temp_string);
			  
	// get the previous node/word
	//
	prev_node = prev_node->get_prev_cc();
	lat_node = prev_node->get_lnode_cc();
	frame_index = lat_node->get_frame_index_cc();
	word = lat_node->get_word_cc();
      }

      // get next partial hypothesis in the final list
      //
      next_pnode=node->get_next_cc();

      // print the hypothesis
      //
      fprintf(fp_a, "%s\n", (char_1*)hypothesis);

      // increment number of paths hypothesized so far
      //
      num_paths++;
      
      // print the hypothesis and reset the string
      //
      memset(hypothesis, (int_4)0, strlen((char*)hypothesis));
      memset(temp_string, (int_4)0, strlen((char*)temp_string));
    }
  }

  // clean up the hash table
  //

  // remove the hash table of nbest nodes
  //
  Hash_cell** hcells = hyp_table->get_cells_cc();
  Hash_cell* hcell = (Hash_cell*)NULL;
  int_4 hsize = hyp_table->get_size_cc();
  for (int_4 k = 0; k < hsize; k++) {
    for (Hash_cell* cell = hcells[k]; cell != (Hash_cell*)NULL;
         cell = hcell) {
      hcell = cell->get_next_cc();
      manager_d->delete_cc(cell);
    }
    hcells[k] = (Hash_cell*)NULL;
  }
  delete hyp_table;
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
