// file: ht_insert_2.cc
//
// isip include files
//
#include "hmm_train.h"
#include "hmm_train_constants.h"

// method: insert_trace_cc
//
// arguments:
//  Train_Link_list*& tr_list : (input) the trace linked list
//  Train_Trace* trace : (input) the trace to insert
//  Train_Link_node* marker : (input) the trace position marker
//  int_4& ngen : (output) the number of new traces generated
//  float_8& max_score : (output) the max path score so far
//
// return: a logical_1 to indicate status
//
// this method inserts the given word-level trace in the active trace
// list after merging with other traces. the better trace gets all the
// back-pointers added and the inferior trace is removed. if the trace
// needs to create a node, return true. if the trace gets pruned or
// prunes another trace, returns false to indicate no growth in number
// of traces
//
logical_1 insert_trace_cc(Train_Link_list*& tr_list_a, Train_Trace* trace_a,
			  Train_Link_node* marker_a, int_4& ngen_a,
			  float_8& max_score_a) {

  // dummy variables
  //
  Train_Trace* tr = (Train_Trace*)NULL;
  Train_Trace* betr = (Train_Trace*)NULL;
  Train_Trace** back = (Train_Trace**)NULL;

  logical_1 flag = ISIP_TRUE;
  int_4 num = (int_4)0;
  float_8 score = (float_8)0;

  // memory manager
  //
  Train_Memory_manager* manager = Train_Link_list::get_manager_cc();

  // loop over all active traces for this frame
  //
  for (Train_Link_node* nd = marker_a; nd != (Train_Link_node*)NULL;
       nd = nd->get_next_cc()) {
    
    // get the trace in this node
    //
    tr = (Train_Trace*)(nd->get_item_cc());
    
    // compare this trace with the input trace and determine which is
    // better
    //
    betr = trace_a->compare_cc(tr);
    
    // if this was a valid comparison
    //
    if (betr != (Train_Trace*)NULL) {

      // update maximum score
      //
      score = betr->get_score_cc();
      if (score > max_score_a) {
	max_score_a = score;
      }
      
      // if the input trace is the better path
      //
      if (betr == trace_a) {
	
	// substitute input trace
	//
	nd->set_item_cc(trace_a);

	// get backpointers of the other trace and add them to the
	// better trace
	//
	back = tr->get_back_ptr_cc();
	num = tr->get_back_size_cc();
	for (int_4 i = 0; (i < num) && (back[i] != (Train_Trace*)NULL); i++) {
	  trace_a->add_back_ptr_cc(back[i]);
	  back[i] = (Train_Trace*)NULL;
	}
	  
	// delete old trace
	//
	manager->delete_cc(tr);
      }
      
      // if the other trace is the better path
      //
      else {
	
	// get backpointers of the other trace and add them to the
	// better trace
	//
	back = trace_a->get_back_ptr_cc();
	num = trace_a->get_back_size_cc();
	for (int_4 i = 0; (i < num) && (back[i] != (Train_Trace*)NULL); i++) {
	  tr->add_back_ptr_cc(back[i]);
	  back[i] = (Train_Trace*)NULL;
	}
	  
	// remove new trace
	//
	manager->delete_cc(trace_a);
      }
      
      // mark flag
      //
      flag = ISIP_FALSE;
      break;
    }
  }
  
  // insert trace if okay
  //
  if (flag == ISIP_TRUE) {
    
    // allocate trace list if one doesn't exist yet
    //
    if (tr_list_a == (Train_Link_list*)NULL) {
      tr_list_a = new Train_Link_list();
    }
    
    // insert the trace and update counts
    //
    tr_list_a->insert_cc(trace_a);
    ngen_a++;
    
    // update score
    //
    score = trace_a->get_score_cc();
    if (score > max_score_a) {
      max_score_a = score;
    }
  }

  // exit gracefully
  //
  return ISIP_TRUE;
}
