// file: $isip/class/search/SearchNode/snod_06.cc
// version: $Id: snod_09.cc 9340 2003-11-12 15:38:03Z alphonso $
//

// isip include files
//
#include "SearchNode.h"
#include <Trace.h>
#include <Instance.h>

// method: insertInstance
//
// arguments:
//  Instance* instance: (input) the instance to insert to the instance list.
//                      we do Viterbi pruning at this point
//  long timestamp: (input) the timestamp for the incoming instance
//  Instance*& ptr: (input) pointer to existing instance with the same history
//
// return: a boolean indicating status
//
// this method inserts the instance to the instance list if it is the highest
// scoring instance at that point
//
boolean SearchNode::insertInstance(Instance* instance_a,
				long timestamp_a, Instance*& ptr_a) {

  // declare local variables
  //
  boolean status = true;
  
  if (this == &DiGraph<SearchNode>::TERM_OBJ ||
      this == &DiGraph<SearchNode>::START_OBJ) {    
    return status;
  }
  
  // check the timestamp
  //
  if (timestamp_a != timestamp_d) {
    instances_d.clear();
    score_d = Instance::INACTIVE_SCORE;
    timestamp_d = timestamp_a;
  }

  // do Viterbi pruning - at this time, we only handle one-best Viterbi
  //
  if (instance_a->getInstanceMode() == Instance::TRAIN) {
    status = addWithBaumWelch(instance_a, ptr_a);
  }
  else {
    status = insertWithViterbi(instance_a, ptr_a);
  }
  return status;
}

// method: insertWithViterbi
//
// arguments:
//  Instance* instance: (input) the instance to insert to the instance list.
//                      we do Viterbi pruning at this point
//  Instance*& ptr: (input) pointer to existing instance with the same history
//
// return: a boolean indicating status
//
// this method inserts the instance to the instance list if it is the highest
// scoring instance at that point
//
boolean SearchNode::insertWithViterbi(Instance* instance_a,
				      Instance*& ptr_a) {

  // if there are no instances here, then just insert this one
  //
  if (instances_d.isEmpty()) {
    instances_d.insertFirst(instance_a);
    return true;
  }

  // a flag showing that if need to insert a instance
  //
  boolean add_flag = false;
  ulong input_instance_frame_index = instance_a->getFrame();
  
  // see if any other instance with the same history exists at this point
  // right now we loop over all instances at this point and compare histories
  //
  for (boolean more_instances = instances_d.gotoFirst(); more_instances;
       more_instances = instances_d.gotoNext()) {

    Instance* tmp = instances_d.getCurr();
   
    if (instance_a == tmp) {
      
      return Error::handle(name(), L"addWithViterbi-- address same", SearchNode::ERR, __FILE__, __LINE__);
    }
    
    // make sure the timestamps match even before we compare them
    //
    if (input_instance_frame_index == tmp->getFrame()) {
      if (instance_a->match(*tmp)) {
	
	add_flag = true;

	// set the pointer of the trace that already exists
	//
	ptr_a = tmp;
	
	if (instance_a->getScore() > tmp->getScore()) {
	  instances_d.remove(tmp);
	  
	  // delete the bad instance if possible
	  //
	  if (tmp->getRefCount() < 1) {
	    tmp->setActive(false);
	  }
	  
	  // add the new instance
	  //
	  instances_d.insertFirst(instance_a);
	  return true;
	}
	else {
	  instance_a->setActive(false);
	  return false;
	}
      }
    }
    else {
      return Error::handle(name(), L"addWithViterbi-- oldtime instance in node", Error::ARG, __FILE__, __LINE__, Error::WARNING);
    }
  }

  // no instance is the same as the one to be added, add this one
  //
  if (!add_flag) {
    instances_d.insert(instance_a);
  }
  
  // exit gracefully
  //
  return true;  
}
