// file: plist_grow_0.cc
//

// isip include files
//
#include "path_list.h"
#include "path_list_constants.h"
#include <word.h>
#include <nbest_node.h>

// method: grow_paths_cc
//
// arguments:
//  Path_list**& path_lists: (input) set of path lists
//  float_8 lm_scale_a: (input) lm scale
//  float_8 ac_scale_a: (input) word insertion penalty
//  int_4 max_paths_a: (input) maximum number of partial paths in a list
//  float_8 beam: (input) beam for pruning
//
// return: a logical_1 indicating status
//
// this method grow the current path list based on the nodes the
// lattice nodes in the list can transition to
//
logical_1 Path_list::grow_paths_cc(Path_list**& path_lists_a,
				   float_8 lm_scale_a,
				   float_8 wd_penalty_a,
				   int_4 max_paths_a,
				   float_8 beam_a) {
  
  // define local variables
  //
  Lattice_node* lat_node = (Lattice_node*)NULL;
  Lattice_node* next_latnode = (Lattice_node*)NULL;
  Nbest_node* nnode = (Nbest_node*)NULL;
  Nbest_node* new_nbest_node = (Nbest_node*)NULL;
  Link_list* next_latnodes = (Link_list*)NULL;
  Link_node* next_pnode = (Link_node*)NULL;
  Link_node* next_lnode = (Link_node*)NULL;
  float_8 ac_score = (float_8)0;
  float_8 lm_score = (float_8)0;
  float_8 score = (float_8)0;
  int_4 frame_index = (int_4)0;

  // loop through the partial path list
  //
  if (paths_d != (Link_list*)NULL) {
    for (Link_node* node = paths_d->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();

      // get the next lattice nodes and acoustic scores
      //
      next_latnodes = lat_node->get_next_nodes_cc();

      // loop through the possible next lattice nodes
      //      
      if (next_latnodes != (Link_list*)NULL) {
	for (Link_node* lnode = next_latnodes->get_head_cc(); 
	     lnode != (Link_node*)NULL;
	     lnode = next_lnode) {

	  // get the next lattice node, create a corresponding nbest node
	  //
	  next_latnode = (Lattice_node*)(lnode->get_item_cc());
	  ac_score = lat_node->get_acscore_cc(next_latnode);
	  lm_score = lat_node->get_lmscore_cc(next_latnode);
	  frame_index = next_latnode->get_frame_index_cc();
	  score = nnode->get_score_cc() + ac_score +
	    (lm_scale_a*lm_score) + wd_penalty_a;

	  // create and add this partial list to the path list only
	  // if it falls within the beam at this time
	  //
	  if (score > (path_lists_a[frame_index]->max_score_d - beam_a)) {
	    
	    // create the partial path
	    //
	    new_nbest_node = new Nbest_node(next_latnode, nnode, score);
	    
	    // and add it to the appropriate path list
	    //
	    path_lists_a[frame_index]->add_path_cc(new_nbest_node);
	    
	    // set the max score
	    //
	    if (score > path_lists_a[frame_index]->max_score_d) {
	      path_lists_a[frame_index]->max_score_d = score;
	    }
	  }
	  
	  // get next node in the link list
	  //
	  next_lnode = lnode->get_next_cc();
	}
      }

      // get next node in the link list
      //
      next_pnode = node->get_next_cc();
    }
  }

  // exit gracefully
  //
  return ISIP_TRUE;
}
