// file: dec_project_4.cc
//
 
// isip include files
//
#include "decoder.h"
#include "decoder_constants.h"
 
// method: grow_models_cc
//
// arguments:
//  Trace* trace: (input) the input trace to project
//  Lex_node* lexch: (input) the next lexical node
//  int_4* phn: (input) the ci phone symbols that make up the cd model
//  
// return: a logical_1 indicating status
//
// this method creates the next model trace parameters and handles
// path projection at word-boundary
//
logical_1 Decoder::grow_models_cc(Trace* trace_a, Lex_node* lexch_a,
				  int_4* phn_a) {

  // dummy variables
  //
  int_4 phone = LXN_NULL_PHONE;
  int_4 phtmp = LXN_NULL_PHONE;
  Lex_node* lexnext = (Lex_node*)NULL;
  Lex_node* lexnode = (Lex_node*)NULL;
  
  int_4 phn_ind = LXN_NULL_PHONE;
  Lex_node* head = (Lex_node*)NULL;
  Link_list* wrd_list = (Link_list*)NULL;
  Link_list* nlx_list = (Link_list*)NULL;

  logical_1 lextype = LXN_WORDGRAPH;
  
  // define lattice mode specific variables
  //
  Lattice_node* latnode = (Lattice_node*)NULL;

  // lexical tree (default for lattice modes, correct for ngram modes)
  //
  Lex_tree* lextree = proto_tree_d;
  
  // history related variables
  //
  History* hist = trace_a->get_hist_cc();

  // instance parameters
  //
  Instance* inst = (Instance*)NULL;

  // if this is a context-dependent mode i.e. not monophones
  //
  if (context_mode_d != DEC_MONO_PHONE_MODE) {
    
    // if this is cross-word mode
    //
    if (context_mode_d == DEC_CROSS_WORD_MODE) {
      
      // if the next phone is sp then grow crosswords
      //
      if (phn_a[2] == LXN_SP_PHONE) {
	
	// get the list of all possible next phones
	//
	nlx_list = lexch_a->get_child_cc();
	
	// loop over all next phones and create traces
	//
	for (Link_node* lxn = nlx_list->get_head_cc();
	     lxn != (Link_node*)NULL; lxn = lxn->get_next_cc()) {
	  
	  // get the child lexical node
	  //
	  lexnode = (Lex_node*)(lxn->get_item_cc());
	  
	  // complete the triphone with the last phone
	  //
	  phn_a[2] = lexnode->get_phone_cc();
	  
	  // grow triphones and project traces
	  //
	  grow_models_cc(trace_a, lexnode, phn_a);
	  
	} // end for loop
	
	// exit gracefully
	//
	return ISIP_TRUE;
	
      } // end if sp phone in cross-word mode
      
      // otherwise if this is an sp phone to be created, grow but
      // do not add lm scores
      //
      else if ((phn_a[2] == LXN_STOP_PHONE) && (phn_a[1] == LXN_SP_PHONE)) {
	
	// get the phone index
	//
	phn_ind = get_model_index_cc(phn_a);
	
	// modify the phone index and next lex node pointer
	//
	phone = trace_a->get_inst_cc()->get_phone_ind_cc();
	lexnext = trace_a->get_lex_next_cc();
	
	// get the instance for this trace
	//
	get_instance_cc(inst, hist, lexch_a, phone);
	
	// grow trace
	//
	grow_trace_cc(trace_a, inst, phn_ind, lexnext);
	
	// exit gracefully
	//
	return ISIP_TRUE;
	
      } // end else this is sp
    } // end if cross-word context mode
    
    // if we are approaching an end of word
    //
    if (phn_a[2] == LXN_STOP_PHONE) {
      
      // list of words that end at this point
      //
      wrd_list = lexch_a->get_words_cc();
      lextype = lexch_a->get_type_cc();
      
      // find the nodes corresponding to the words that end here
      //
      for (Link_node* lln = wrd_list->get_head_cc();
	   lln != (Link_node*)NULL; lln = lln->get_next_cc()) {
	
	// see if this is the silence phone
	//
	if (phn_a[1] == DEC_SILENCE_PHONE) {
	  
	  // get the phone index
	  //
	  phn_ind = get_model_index_cc(phn_a);
	  
	  // get the instance for this trace
	  //
	  get_instance_cc(inst, hist, lexch_a, phn_ind);
	  
	  // grow new trace for this phone
	  //
	  grow_trace_cc(trace_a, inst, phn_ind, lexch_a);
	}
	
	// otherwise if this is word-internal context mode
	//
	else if (context_mode_d != DEC_CROSS_WORD_MODE) {
	  
	  // see if this is sp phone
	  //
	  if (phn_a[1] == DEC_SP_PHONE) {
	    
	    // get the phone index
	    //
	    phn_ind = get_model_index_cc(phn_a);
	    
	    // modify the phone index and next lex node pointer
	    //
	    phone = trace_a->get_inst_cc()->get_phone_ind_cc();
	    lexnext = trace_a->get_lex_next_cc();
	    
	    // get the instance for this trace
	    //
	    get_instance_cc(inst, hist, lexch_a, phone);
	    
	    // grow the trace
	    //
	    grow_trace_cc(trace_a, inst, phn_ind, lexnext);
	  }
	  
	  // otherwise grow regular traces 
	  //
	  else {
	    
	    // complete the triphone with the last phone
	    //
	    phn_a[2] = (int_4)0;
	    
	    // get the phone index
	    //
	    phn_ind = get_model_index_cc(phn_a);
	    
	    // get the instance for this trace
	    //
	    get_instance_cc(inst, hist, lexch_a, phn_ind);
	    
	    // grow new traces for this phone
	    //
	    grow_trace_cc(trace_a, inst, phn_ind, lexch_a);
	  }
	} // end if word internal context mode
	
	// otherwise grow cross-word triphones
	//
	else {
	  
	  // if this is a lattice-related mode
	  //
	  /*---
	    if ((function_mode_d == DEC_LATTICE_RESCORE_FUNCTION) ||
	    (function_mode_d == DEC_LATTICE_VERIFY_FUNCTION) ||
	    (function_mode_d == DEC_LATTICE_LATTICE_FUNCTION) ||
	    (function_mode_d == DEC_FORCE_ALIGN_FUNCTION)) {
	    ---*/
	  if (lextype == LXN_WORDGRAPH) {
	  
	    // get the lattice node
	    //
	    latnode = (Lattice_node*)(lln->get_item_cc());
	    
	    // build the lexical tree for the end of the current word
	    //
	    lextree = latnode->get_lex_tree_cc();
	    if (lextree == (Lex_tree*)NULL) {
	      lextree = new Lex_tree(latnode);
	      latnode->set_lex_tree_cc(lextree);
	      lextree_list_d->insert_cc(lextree);
	    }
	  }
	  
	  // get the head of the next lexical tree
	  //
	  head = lextree->get_head_cc();
	  
	  // get the list of all possible next phones
	  //
	  nlx_list = head->get_child_cc();

	  // check if this is a word boundary that requires
	  // transcending the LM to generate the triphone
	  //
	  if (nlx_list == (Link_list*)NULL) {

	    // use the ngram tree
	    //
	    lextree = proto_tree_d;
	    head = lextree->get_head_cc();
	    nlx_list = head->get_child_cc();
	  }
	  
	  // loop over all next phones and create traces
	  //
	  for (Link_node* lxn = nlx_list->get_head_cc();
	       lxn != (Link_node*)NULL; lxn = lxn->get_next_cc()) {
	    
	    // get the child lexical node and the phone there
	    //
	    lexnext = (Lex_node*)(lxn->get_item_cc());
	    phtmp = lexnext->get_phone_cc();
	    
	    // complete the triphone with the last phone
	    //
	    phn_a[2] = phtmp;

	    // if this is not a word end
	    //
	    if (phn_a[2] != LXN_STOP_PHONE) {
	      
	      // get the phone index
	      //
	      phn_ind = get_model_index_cc(phn_a);
	      
	      // get the instance for this trace
	      //
	      get_instance_cc(inst, hist, lexch_a, phn_ind);
	      
	      // grow new trace for this phone as word end
	      //
	      grow_trace_cc(trace_a, inst, phn_ind, lexnext);

	    } // end if the last phone is not a word end

	    // otherwise need to get last phone from a new LM
	    //
	    else {

	      // get the network LM corresponding to this word
	      //
	      latnode = (Lattice_node*)get_newhist_cc(lexnext);

	      // get the lexical tree and the start lex node for this
	      // network
	      //
	      lextree = latnode->get_lex_tree_cc();
	      if (lextree == (Lex_tree*)NULL) {	  
		lextree = new Lex_tree(latnode);
		latnode->set_lex_tree_cc(lextree);
		lextree_list_d->insert_cc(lextree);
	      }
	      head = lextree->get_head_cc();
	      
	      // get the list of all possible next phones
	      //
	      Link_list* start_list = head->get_child_cc();
	      
	      // loop over all next phones
	      //
	      for (Link_node* stx = start_list->get_head_cc();
		   stx != (Link_node*)NULL; stx = stx->get_next_cc()) {
		
		// get the child lexical node
		//
		lexnext = (Lex_node*)(stx->get_item_cc());
		phtmp = lexnext->get_phone_cc();
		phn_a[2] = phtmp;

		// get the phone index
		//
		phn_ind = get_model_index_cc(phn_a);
		
		// get the instance for this trace
		//
		get_instance_cc(inst, hist, lexch_a, phn_ind);
		
		// grow new trace for this phone as word end
		//
		grow_trace_cc(trace_a, inst, phn_ind, lexnext);

	      } // end for loop over all nodes
	    } // end else look across LMs for next phone
	  } // end loop over all next phones
	} // end else grow crossword triphones
      } // end loop over all lattice nodes
    } // end if this is a word end
    
    // otherwise this is not an end of word
    //
    else {
      
      // get the phone index
      //
      phn_ind = get_model_index_cc(phn_a);
      
      // get the instance for this trace
      //
      get_instance_cc(inst, hist, lexch_a, phn_ind);
      
      // grow new traces for this phone
      //
      grow_trace_cc(trace_a, inst, phn_ind, lexch_a);
      
    } // end else if not end of word
  } // end if context dependent mode

  // otherwise this is a monophone mode
  //
  else {
    
    // see if this is sp phone
    //
    if (phn_a[0] == DEC_SP_PHONE) {
      
      // get the phone index
      //
      phn_ind = get_model_index_cc(phn_a);
      
      // modify the phone index and next lex node pointer
      //
      phone = trace_a->get_inst_cc()->get_phone_ind_cc();
      
      // get the instance for this trace
      //
      get_instance_cc(inst, hist, lexch_a, phone);
      
      // grow the trace
      //
      grow_trace_cc(trace_a, inst, phn_ind, lexch_a);
    }
    
    // otherwise grow regular traces 
    //
    else {
      
      // get the phone index
      //
      phn_ind = get_model_index_cc(phn_a);
      
      // get the instance for this trace
      //
      get_instance_cc(inst, hist, lexch_a, phn_ind);
      
      // grow new traces for this phone
      //
      grow_trace_cc(trace_a, inst, phn_ind, lexch_a);
    }
  } // end else monophone mode
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
