// file: dec_project_0.cc
//
 
// isip include files
//
#include "decoder.h"
#include "decoder_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: project_states_cc
//
// arguments: none
//  
// return: a logical_1 indicating status
//
// this method projects state level traces within models and activates
// instances wherever necessary
//
logical_1 Decoder::project_states_cc() {

  // dummy variables
  //
  Link_list* toklist = (Link_list*)NULL;

  Trace* mark = (Trace*)NULL;
  Trace* new_trace = (Trace*)NULL;

  History* hist = (History*)NULL;
  History* new_hist = (History*)NULL;

  Instance* inst = (Instance*)NULL;

  Token* tok = (Token*)NULL;
  Model* model = (Model*)NULL;

  Lex_node* lexnode = (Lex_node*)NULL;
  Lex_node* lexnext = (Lex_node*)NULL;
  
  // state transition parameters
  //
  int_4 num_trans = (int_4)0;

  // position flags and other params
  //
  float_4 new_score = (float_4)0;
  float_4 score = (float_4)0;
  int_4 num_st = (int_4)0;
  int_4 st = (int_4)0;

  // index params
  //
  int_4 stn = (int_4)0;
  int_4 phn = (int_4)0;

  // reset state level max score
  //
  max_score_d[DEC_STATE_LEVEL] = DEC_DEFAULT_SCORE;

  // reset the number of active models
  //
  num_active_models_d = (int_4)0;
  
  // set up flag for align mode
  //
  logical_1 flag = ISIP_FALSE;
  if (align_mode_d == DEC_STATE_ALIGN_MODE) {
    flag = ISIP_TRUE;
  }

  // check if the current frame is the same as any of the model-level
  // endpoints (alignments) if segmental-mode is ON
  //
  logical_1 segment = ISIP_FALSE;
  if (segment_mode_d == DEC_MODEL_SEGMENT_MODE) {
    segment = is_curframe_mendpt_cc();
  }
  
  // loop over all instances in the instance list
  //
  for (Link_node* ninst = inst_list_d->get_head_cc();
       ninst != (Link_node*)NULL; ninst = ninst->get_next_cc()) {
    
    // get the instance here and mark active frame
    //
    inst = (Instance*)(ninst->get_item_cc());

    // get the token list
    //
    toklist = inst->get_toklist_cc();
    
    // process only if this is valid
    //
    if (toklist != (Link_list*)NULL) {
      
      // get the lexical node for this instance
      //
      lexnode = inst->get_lex_node_cc();
    
      // loop over all the active tokens --- each corresponds to an
      // active state for this phone
      //
      for (Link_node* tnode = toklist->get_head_cc();
	   tnode != (Link_node*)NULL; tnode = tnode->get_next_cc()) {
	
	// get the corresponding token
	//
	tok = (Token*)(tnode->get_item_cc());
	
	// find the marker trace
	//
	mark = tok->get_marker_cc();
	
	// check if we need to evaluate this state here
	//
	if (mark != (Trace*)NULL) {
	  
	  // perform beam pruning if required
	  //
	  if (beam_thresh_d[DEC_STATE_LEVEL] > mark->get_score_cc()) {
	    
	    // update reference counts
	    //
	    if (align_mode_d == DEC_STATE_ALIGN_MODE) {
	      mark->decr_ref_cc();
	    }
	  } // end if beam pruning is needed
	  
	  // otherwise propagate this trace
	  //
	  else {

	    // get the model index
	    //
	    stn = inst->get_phone_ind_cc();
	    phn = mark->get_phone_ind_cc();
	    
	    // get the model params for this model
	    //
	    model = cd_models_d[phn]->get_model_cc();
	    num_st = model->get_num_states_cc();
      
	    // evaluate this state --- the Gaussian eval happens only once
	    //
	    st = tok->get_state_cc();
	    score = model->get_output_prob_cc(st, features_d, frame_d);
		
	    // find the possible transition states from here
	    //
	    model->get_next_states_cc(st, num_trans, trans_states,
				      trans_scores, trans_states_size);
	    
	    // update the score
	    //
	    mark->incr_score_cc(score);
	    
	    // get the current path history
	    //
	    hist = mark->get_hist_cc();
	    
	    // update history
	    //
	    if (align_mode_d == DEC_STATE_ALIGN_MODE) {
	      hist->incr_score_cc(score);
	      hist->incr_frame_ind_cc();
	    }
	    
	    // loop over all of the possible next states and pass traces
	    // to each
	    //
	    for (int_4 kk = 0; kk < num_trans; kk++) {
	      
	      // create a new trace with the transitioned state and
	      // the same history
	      //
	      new_trace = manager_d->new_trace_cc();
	      new_trace->project_trace_cc(mark, (float_4)trans_scores[kk]);
	      new_trace->set_state_ind_cc(trans_states[kk]);
	      
	      // update instance score
	      //
	      new_score = new_trace->get_score_cc();
	      inst->compare_score_cc(new_score);
	      
	      // if this transition is at the end of phone i.e. goes
	      // to the exit state pass it to the active traces list
	      //
	      if (trans_states[kk] == num_st - (int_4)1) {

		// add new model-level trace only if either
		// segmental-mode is not set or it segmental model is
		// set the current frame belongs to one of the
		// model-level endpoints
		//
		if ((segment_mode_d != DEC_MODEL_SEGMENT_MODE) ||
		    ((segment_mode_d == DEC_MODEL_SEGMENT_MODE)
		     && segment)) {
		  
		  // set the history parameters
		  //
		  new_trace->set_level_cc(DEC_MODEL_LEVEL);
		  new_trace->set_max_hist_cc(DEC_PHONE_BACKPTR);
		  
		  // if the alignment mode is phone-level or state-level
		  //
		  if ((align_mode_d == DEC_STATE_ALIGN_MODE) ||
		      (align_mode_d == DEC_MODEL_ALIGN_MODE)) {
		    
		    // create a new history node here
		    //
		    new_hist = manager_d->new_hist_cc();
		    
		    // copy the histwords
		    //
		    void_p* prev_words = hist->get_histwords_cc();
		    
		    int_4 hist_len = History::get_hist_len_cc();
		    
		    // initialize history words to NULL
		    //
		    void_p* newhist_words = (void_p*)NULL;
		    
		    if (prev_words != (void_p*)NULL) {
		      newhist_words = new void_p[hist_len];
		    }
		    
		    for (int_4 i = 0; i<hist_len; i++) {
		      if (prev_words != (void_p*)NULL) {
			newhist_words[i] = prev_words[i];
		      }
		    }
		    
		    new_hist->init_cc(newhist_words, DEC_MODEL_LEVEL,
				      phn, trans_states[kk], frame_d,
				      new_score);
		    history_list_d->insert_cc(new_hist);
		  
		    // set the correct history node
		    //
		    new_trace->set_hist_cc(new_hist);
		    new_trace->add_path_cc(hist, new_score);
		  }
		  
		  // add the current phone to the list of active phones
		  //
		  if (cd_models_d[stn]->get_active_cc() == ISIP_FALSE) {
		    cd_models_d[stn]->set_active_cc(ISIP_TRUE);
		    active_models_d[num_active_models_d++] = stn;
		  }
		  
		  // for end of phone update the phone-level score and
		  // put this in the active traces list
		  //
		  if (insert_model_cc(model_trlist_d[stn], new_trace)
		      == ISIP_TRUE) {		  
		    
		    // if this is a context dependent mode
		    //
		    if (context_mode_d != DEC_MONO_PHONE_MODE) {
		      
		      // if this is a word end
		      //
		      if (lexnode->get_phone_cc() == LXN_SP_PHONE) {
			
			// add the sp skip transition and create traces
			//
			project_sp_word_cc(new_trace, lexnode, stn);
			
		      } // end if this is a word-end phone with sp skip
		    } // end if context-dependent mode
		    
		    // otherwise in monophone mode, need to check if
		    // next phone could be sp
		    //
		    else {
		      
		      // check the next lex nodes for an sp
		      //
		      lexnext = lexnode->get_node_cc(LXN_SP_PHONE);
		      
		      // if this exists, create sp skip traces with
		      // word-end lex nodes
		      //
		      if (lexnext != (Lex_node*)NULL) {
			project_sp_word_cc(new_trace, lexnext, stn);
		      }
		    } // end else monophone mode		  
		  } // end if the previous phone trace got added
		} // end if segmental pruning
	      } // end if phone-end loop
	      
	      // otherwise this is a model-internal transition
	      //
	      else {
		
		// set the state level and backpointer
		//
		new_trace->set_level_cc(DEC_STATE_LEVEL);
		new_trace->set_max_hist_cc(DEC_STATE_BACKPTR);
		
		// if the alignment mode state-level
		//
		if (align_mode_d == DEC_STATE_ALIGN_MODE) {
		  
		  // create a new history node here
		  //
		  new_hist = manager_d->new_hist_cc();

		  // copy the histwords
		  //
		  void_p* prev_words = hist->get_histwords_cc();

		  int_4 hist_len = History::get_hist_len_cc();
		  void_p* newhist_words = new void_p[hist_len];

		  for (int_4 i = 0; i<hist_len; i++) {
		    newhist_words[i] = prev_words[i];
		  }
		  
		  new_hist->init_cc(newhist_words, DEC_STATE_LEVEL,
				    phn, trans_states[kk], frame_d,
				    new_score);
		  history_list_d->insert_cc(new_hist);
		  
		  // set the correct history node
		  //
		  new_trace->set_hist_cc(new_hist);
		  new_trace->add_path_cc(hist, new_score);
		}
		
		// put the trace in the appropriate token updating the
		// state level max score
		//
		if (inst->insert_trace_cc(new_trace, trans_states[kk], flag,
					  max_score_d[DEC_STATE_LEVEL]) ==
		    ISIP_TRUE) {
		  num_traces_gen_d[DEC_STATE_LEVEL]++;
		}
	      } // end else state level
	    } // end for state transitions loop
	  } // end else propagate trace
	    
	  // delete the marker trace
	  //
	  manager_d->delete_cc(mark);
	  num_traces_del_d[DEC_STATE_LEVEL]++;
	  
	  // reset the marker for this token
	  //
	  tok->set_marker_cc((Trace*)NULL);
	  
	} // end if token needs to be eval loop
      } // end all tokens loop
    } // end if token list is not null
  } // end loop over all instances
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
