// file: ht_project_4.cc
//

// isip include files
//
#include "hmm_train.h"
#include "hmm_train_constants.h"

static int_4* trans_states = (int_4*)NULL;
static float_4* trans_scores = (float_4*)NULL;
static int_4 trans_states_size = 0;

// method: grow_trace_cc
//
// arguments:
//  Train_Trace* trace : (input) the input trace to be projected
//  Train_Link_list*& tok_list : (input) linked list of active tokens for this phone
//  Train_Lex_node* lexnode : (input) the lexical node for the new trace
//  Train_Lattice_node* latnode : (input) the lattice node for the new trace
//  float_8 lmscore : (input) the language model score for this trace
//  Train_Phone** phones : (input) phone models
//  int_4 phn : (input) the triphone index of the new trace
//  int_4*& wd_active : (output) list of active words
//  int_4& wd_numact : (output) number of active words
//  int_4*& ph_active : (output) list of active phones
//  int_4& ph_numact : (output) number of active phones
//  int_4*& ngen : (output) number of traces generated
//  float_8& max_score : (output) maximum path score so far
//
// return: a logical_1 indicating status
//
// this method projects the given trace onto all traces for the given
// next phone
//
logical_1 grow_trace_cc(Train_Trace* trace_a, Train_Link_list*& tok_list_a,
			Train_Lex_node* lexnode_a, Train_Lattice_node* latnode_a,
			float_8 lmscore_a, Train_Phone** phones_a, int_4 phn_a,
			int_4*& wd_active_a, int_4& wd_numact_a,
			int_4*& ph_active_a, int_4& ph_numact_a,
			int_4*& ngen_a, float_8& max_score_a) {

  // dummy variables
  //
  int_4 num_trans = (int_4)0;

  // new trace
  //
  Train_Trace* new_trace = (Train_Trace*)NULL;

  // model params
  //
  int_4 num_st = (int_4)0;
  Train_Model* model = (Train_Model*)NULL;  
  
  // memory manager
  //
  Train_Memory_manager* manager = Train_Link_list::get_manager_cc();

  // current lattice node
  //
  Train_Lattice_node* curr_lat = trace_a->get_lat_node_cc();
  
  // add the current word to the list of active words
  //
  Train_Word* word = latnode_a->get_word_cc();
  int_4 ind = word->get_index_cc();
  if (word->get_active_cc() == ISIP_FALSE) {
    word->set_active_cc(ISIP_TRUE);
    wd_active_a[wd_numact_a++] = ind;
  }

  // add the current phone to the list of active phones
  //
  if (phones_a[phn_a]->get_active_cc() == ISIP_FALSE) {
    phones_a[phn_a]->set_active_cc(ISIP_TRUE);
    ph_active_a[ph_numact_a++] = phn_a;
  }

  // get the triphone model params
  //
  model = phones_a[phn_a]->get_model_cc();
  num_st = model->get_num_states_cc();
  
  // find all possible start states for this phone
  //
  model->get_next_states_cc((int_4)0, num_trans, trans_states, trans_scores,
			    trans_states_size);
  
  // loop over all of the possible next states and
  // pass traces to each
  //
  for (int_4 kk = 0; kk < num_trans; kk++) {
    
    // check for phones in their stop state
    //
    if (trans_states[kk] < num_st - (int_4)1) {
      
      // create a new trace with the transitioned state
      //
      new_trace = manager->new_trace_cc();
      new_trace->project_trace_cc(trace_a, (float_8)trans_scores[kk] +
				  lmscore_a);
      
      // update the new lexical node
      //
      new_trace->set_lex_node_cc(lexnode_a);

      // set the level to state and state index
      //
      new_trace->set_level_cc(HT_STATE_LEVEL);
      new_trace->set_state_ind_cc(trans_states[kk]);
      
      // set the back-pointer
      //
      new_trace->set_back_size_cc(HT_STATE_BACKPTR);
      new_trace->add_back_ptr_cc(trace_a);      
      
      // update the lattice node if necessary
      //
      if (latnode_a != curr_lat) {
	new_trace->set_lat_node_cc(latnode_a);
      }
      
      // set the phone index
      //
      new_trace->set_phone_ind_cc(phn_a);
      
      // insert this in the corresponding state list
      //
      insert_token_cc(tok_list_a, new_trace, trans_states[kk],
		      ngen_a[HT_STATE_LEVEL], max_score_a);
    }
  } // end loop over all transitions
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
