// file: dec_cstr_0.cc
//

// isip include files
//
#include "decoder.h"
#include "decoder_constants.h"
 
// method: destructor
//
// arguments: none
//
// return: none
//
// this is the destructor for the class
//
Decoder::~Decoder() {

  // local variables
  //
  Link_node* nd = (Link_node*)NULL;
  Link_node* pd = (Link_node*)NULL;
  
  Lex_tree* tree = (Lex_tree*)NULL;

  // make sure free lattice-related memory first
  //
  if(lextree_list_d != NULL) {
    for (nd = lextree_list_d->get_head_cc(); nd != (Link_node*)NULL;
	 nd = pd) {
      pd = nd->get_next_cc();
      tree = (Lex_tree*)(nd->get_item_cc());
      lextree_list_d->remove_cc(nd);
      if (tree != (Lex_tree*)NULL) {
	delete tree;
      }
    }
    delete lextree_list_d;
    lextree_list_d = (Link_list*)NULL;
  }
    
  // free memory
  //
  delete lattice_d;
  lattice_d = (Lattice*)NULL;

  Hash_cell* hcell = (Hash_cell*)NULL;
  Hash_cell** hcells = (Hash_cell**)NULL;
  int_4 hsize = (int_4)0;

  Instance* inst = (Instance*)NULL;
  Word* word = (Word*)NULL;

  // reset function and align modes
  //
  function_mode_d = DEC_DEFAULT_INDEX;
  context_mode_d = DEC_DEFAULT_INDEX;
  align_mode_d = DEC_DEFAULT_INDEX;
  input_format_d = DEC_DEFAULT_INDEX;
  input_feature_format_d = DEC_ISIP_PROTO_FORMAT;
  demo_mode_d = ISIP_FALSE;

  // reset delta and acceleration computaional modes
  //
  delta_win_d = DEC_DEFAULT_DELTA_WIN;
  delta_d = DEC_DEFAULT_DELTA;
  acc_d = DEC_DEFAULT_ACC;
  
  // number of utterances decoded
  //
  num_utt_d = DEC_DEFAULT_INDEX;
  
  // levels in the search hierarchy
  //
  num_levels_d = DEC_DEFAULT_INDEX;

  // timing information
  //
  frame_d = DEC_DEFAULT_INDEX;
  frame_dur_d = DEC_DEFAULT_VALUE;

  // input feature data information
  //
  num_feat_d = DEC_DEFAULT_INDEX;
  if (features_d != (float_4*)NULL) {
    delete [] features_d;
    features_d = (float_4*)NULL;
  }
  
  // acoustic model information
  //
  // context independent models
  //
  for (int_4 i = 0; i < num_ci_d; i++) {
    delete [] ci_models_d[i];
    ci_models_d[i] = (char_1*)NULL;
  }
  delete [] ci_models_d;
  ci_models_d = (char_1**)NULL;
  num_ci_d = DEC_DEFAULT_INDEX;

  // context dependent models
  //
  for (int_4 i = 0; i < num_cd_d; i++) {
    delete cd_models_d[i];
    cd_models_d[i] = (Phone*)NULL;
  }
  delete [] cd_models_d;
  cd_models_d = (Phone**)NULL;
  delete [] cdmap_d;
  cdmap_d = (int_4*)NULL;
  cd_size_d = DEC_DEFAULT_INDEX;
  num_cd_d = DEC_DEFAULT_INDEX;
  
  // Hidden Markov models
  //
  for (int_4 i = 0; i < num_models_d; i++) {
    delete models_d[i];
    models_d[i] = (Model*)NULL;
  }
  delete [] models_d;
  models_d = (Model**)NULL;
  num_models_d = DEC_DEFAULT_INDEX;
  
  // state transition matrices
  //
  for (int_4 i = 0; i < num_trans_d; i++) {
    delete [] transitions_d[i];
    transitions_d[i] = (float_4*)NULL;
  }
  delete [] transitions_d;
  transitions_d = (float_4**)NULL;
  num_trans_d = DEC_DEFAULT_INDEX;

  // model states
  //
  for (int_4 i = 0; i < num_states_d; i++) {
    delete states_d[i];
    states_d[i] = (State*)NULL;
  }
  delete [] states_d;
  states_d = (State**)NULL;
  num_states_d = DEC_DEFAULT_INDEX;

  // lexicon
  //
  hcells = lexicon_d->get_cells_cc();
  hsize = lexicon_d->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();
      word = (Word*)(cell->get_item_cc());
      delete word;
      manager_d->delete_cc(cell);
    }
    hcells[k] = (Hash_cell*)NULL;
  }
  delete lexicon_d;
  lexicon_d = (Hash_table*)NULL;
  num_words_d = DEC_DEFAULT_INDEX;
  
  // lm related parameters
  //
  lmscale_d = DEC_LM_SCALE;
  wdpenalty_d = DEC_DEFAULT_VALUE;
  ngram_order_d = DEC_DEFAULT_INDEX;
  if (ngram_d != (Ngram*)NULL) {
    delete ngram_d;
    ngram_d = (Ngram*)NULL;
  }
  if (lattice_d != (Lattice*)NULL) {
    delete lattice_d;
    lattice_d = (Lattice*)NULL;
  }
  
  // path information
  //
  // cleanup active model instances table and linked list
  //
  inst_count_d = DEC_DEFAULT_INDEX;
  if (inst_table_d != (Hash_table*)NULL) {

    // deallocate the instance hash-table
    //
    hcells = inst_table_d->get_cells_cc();
    hsize = inst_table_d->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();
	inst = (Instance*)(cell->get_item_cc());
	manager_d->delete_cc(inst);
	manager_d->delete_cc(cell);
      }
      hcells[k] = (Hash_cell*)NULL;
    }
    delete inst_table_d;
    inst_table_d = (Hash_table*)NULL;
  }

  if (inst_list_d != (Link_list*)NULL) {
    delete inst_list_d;
    inst_list_d = (Link_list*)NULL;
  }

  // hypotheses information
  //
  if (nbest_d != (Trace**)NULL) {
    delete [] nbest_d;
    nbest_d = (Trace**)NULL;
  }
  num_hyps_d = DEC_DEFAULT_INDEX;
  num_nbest_d = DEC_DEFAULT_INDEX;
  
  // path history information
  //
  if (history_list_d != (Link_list*)NULL) {
    delete history_list_d;
    history_list_d = (Link_list*)NULL;
  }
  num_hist_d = DEC_DEFAULT_INDEX;

  // lexical tree information
  //
  if (lextree_list_d != (Link_list*)NULL) {
    for (nd = lextree_list_d->get_head_cc(); nd != (Link_node*)NULL;
	 nd = pd) {
      pd = nd->get_next_cc();
      tree = (Lex_tree*)(nd->get_item_cc());
      lextree_list_d->remove_cc(nd);
      if (tree != (Lex_tree*)NULL) {
	delete tree;
      }
    }
    delete lextree_list_d;
    lextree_list_d = (Link_list*)NULL;
  }
  if (proto_tree_d != (Lex_tree*)NULL) {
    delete proto_tree_d;
    proto_tree_d = (Lex_tree*)NULL;
  }
  
  // list of lattices corresponding to the grammars
  //
  Lattice* gram = (Lattice*)NULL;
  if (gram_list_d != (Link_list*)NULL) {
    for (nd = gram_list_d->get_head_cc(); nd != (Link_node*)NULL;
	 nd = pd) {
      pd = nd->get_next_cc();
      gram = (Lattice*)(nd->get_item_cc());
      gram_list_d->remove_cc(nd);
      if (gram != (Lattice*)NULL) {
	delete gram;
      }
    }
    delete gram_list_d;
    gram_list_d = (Link_list*)NULL;
  }

  // list of traces at model level
  //
  if (active_models_d != (int_4*)NULL) {
    delete [] active_models_d;
    active_models_d = (int_4*)NULL;
  }
  if (model_trlist_d != (Link_list**)NULL) {
    delete [] model_trlist_d;
    model_trlist_d = (Link_list**)NULL;
  }
  num_active_models_d = DEC_DEFAULT_INDEX;

  // list of traces at word level
  //
  if (active_words_d != (int_4*)NULL) {
    delete [] active_words_d;
    active_words_d = (int_4*)NULL;
  }
  if (word_scores_d != (float_4*)NULL) {
    delete [] word_scores_d;
    word_scores_d = (float_4*)NULL;
  }
  if (word_trlist_d != (Link_list**)NULL) {
    delete [] word_trlist_d;
    word_trlist_d = (Link_list**)NULL;
  }
  num_active_words_d = DEC_DEFAULT_INDEX;  

  // pruning-related information
  //
  // beam pruning information
  //
  if (max_score_d != (float_4*)NULL) {
    delete [] max_score_d;
    max_score_d = (float_4*)NULL;
  }
  if (beam_d != (float_4*)NULL) {
    delete [] beam_d;
    beam_d = (float_4*)NULL;
  }
  if (beam_thresh_d != (float_4*)NULL) {
    delete [] beam_thresh_d;
    beam_thresh_d = (float_4*)NULL;
  }

  // instance pruning information
  //
  mapmi_limit_d = DEC_DEFAULT_INDEX;
  mapmi_thresh_d = DEC_DEFAULT_SCORE;

  // word-end pruning information
  //
  num_wordends_d = DEC_DEFAULT_INDEX;
  wordend_thresh_d = DEC_DEFAULT_SCORE;

  // demo information
  //
  num_steps_d = DEC_DEFAULT_INDEX;

  // trace generation and other statistics
  //
  if (num_traces_total_d != (int_4*)NULL) {
    delete [] num_traces_total_d;
    num_traces_total_d = (int_4*)NULL;
  }
  if (num_traces_gen_d != (int_4*)NULL) {
    delete [] num_traces_gen_d;
    num_traces_gen_d = (int_4*)NULL;
  }
  if (num_traces_del_d != (int_4*)NULL) {
    delete [] num_traces_del_d;
    num_traces_del_d = (int_4*)NULL;
  }
  if (total_gen_d != (int_4*)NULL) {
    delete [] total_gen_d;
    total_gen_d = (int_4*)NULL;
  }
  if (total_del_d != (int_4*)NULL) {
    delete [] total_del_d;
    total_del_d = (int_4*)NULL;
  }

  // release memory for model-level segments (alignments)
  //
  int_4* ele = (int_4*)NULL;
  if (segment_mode_d == DEC_MODEL_SEGMENT_MODE) {
    for (nd = model_seglist_d->get_head_cc();
	 nd != (Link_node*)NULL; nd = pd) {
      	pd = nd->get_next_cc();
	ele = (int_4*)(nd->get_item_cc());
	if (ele != (int_4*)NULL) {
	  delete ele;
	}
	model_seglist_d->remove_cc(nd);
    }
    if (model_seglist_d != (Link_list*)NULL) {
      delete model_seglist_d;
      model_seglist_d = (Link_list*)NULL;
    }    
  }

  // special models
  //
  sil_model_d = DEC_DEFAULT_INDEX;
  sp_model_d = DEC_DEFAULT_INDEX;
  sp_score_d = DEC_DEFAULT_SCORE;
  
  // memory manager
  //
  if (manager_d != (Memory_manager*)NULL) {
    delete manager_d;
    manager_d = (Memory_manager*)NULL;
  }
  
  // exit gracefully
  //
}
