// file: $isip/class/pr/HiddenMarkovModel/hmm_08.cc
// version: $Id: hmm_08.cc 9449 2004-04-13 19:27:00Z gao $
//

// isip include files
//
#include "HiddenMarkovModel.h"
#include <CommandLine.h>
#include <AnnotationGraph.h>

// method: createAnnotationGraph
//
// arguments:
//  AnnotationGraph& angr: (output) the output AnnotationGraph
//  DoubleLinkedList<Trace>& trace_path: (input) best hypothesis trace path
//
// return: boolean value
//
// build a AnnotationGraph representing the hypotheses and return it
//
boolean HiddenMarkovModel::createAnnotationGraph(AnnotationGraph& angr_a,
						 DoubleLinkedList<Trace>& trace_path_a) {
  // declare local variables
  //
  Trace* tmp_trace = (Trace*)NULL;
  SearchNode*  tmp_node = (SearchNode*)NULL;
  
  long curr_level = 0;
  long frame_ind = 0;
  long prev_frame_ind = -1;
  float score = 0.0;
  float frame_duration = vector_fe_d((long)0).getFrameDuration();
  
  SearchSymbol sym;

  // get id and type of the AnnotationGraph
  //
  String name_00;
  name_00 = angr_a.getId();

  String gtype_00;
  gtype_00 = angr_a.getType();
  
  String newid_00;
  
  Anchor* ancr_00 = (Anchor*)NULL;
  Anchor* ancr_01 = (Anchor*)NULL;
  
  String unit_00;
  unit_00.assign(L"seconds");
  
  String feat_00;
  feat_00.assign(AnnotationGraph::PARAM_SEARCH_LEVEL);

  String feat_01;
  feat_01.assign(AnnotationGraph::PARAM_SEARCH_LEVEL_INDEX);

  String feat_02;
  feat_02.assign(AnnotationGraph::PARAM_SCORE);
  
  String pre_level;
  String arc_score;
  
  Long numLevel = search_engine_d.getNumLevels();

  Vector <String> level_tag(numLevel);

  for (long j = 0; j < numLevel; j++) {
    SearchLevel& search_level = search_engine_d.getSearchLevel(j);
    level_tag(j).assign(search_level.getLevelTag());
  }
      

  Vector <String> vlevel(numLevel);
  Vector <Boolean> vflag(numLevel);
  Vector <String> vstart(numLevel);
  Vector <String> vend(numLevel);
  Vector <Float> start_score(numLevel);
  Vector <Float> end_score(numLevel);  
  
  for (long i = 0; i < numLevel; i++) {
    vflag(i) = true;
  }
  
  // use the best hypothesis trace path to generate the AnnotationGraph
  //
  for (boolean more_traces = trace_path_a.gotoFirst(); more_traces;
       more_traces = trace_path_a.gotoNext()) {
    
    tmp_trace = trace_path_a.getCurr();
    frame_ind = tmp_trace->getFrame();
    
    // get the central vertex from the top of the history stack
    //
    GraphVertex<SearchNode>* tmp_vertex = (GraphVertex<SearchNode>*)NULL;
    tmp_vertex = tmp_trace->getSymbol()->getCentralVertex();
    
    // check for a NULL vertex
    //
    if (tmp_vertex == (GraphVertex<SearchNode>*)NULL) {
      return Error::handle(name(), L"createAnnotationGraph - NULL VERTEX", Error::ARG, __FILE__, __LINE__);
    }

    // make sure the vertex is neither the dummy
    // start nor terminating node
    //
    if ((!tmp_vertex->isStart()) &&
	(!tmp_vertex->isTerm())) {

      tmp_node = tmp_vertex->getItem();
      curr_level = tmp_node->getSearchLevel()->getLevelIndex();
      
      tmp_node->getSymbol(sym);

      if (tmp_node->isDummyNode()) {
	continue;
      }
      
      String level = tmp_node->getSearchLevel()->getLevelTag();
      score = tmp_trace->getScore();
      
      String context;
      tmp_trace->getSymbol()->print(context);
      sym.assign(context);

      String level_index;

      for (long j = 0; j < numLevel; j++) {
	
	if (j != (long)numLevel - 1 && level.eq(level_tag(j))) {

	  // insert word to AG
	  //
	  if (vflag(j)) {  // starting level mark
	    if (frame_ind == 0) {
	      if ( j == 0) {
		vstart(j) = angr_a.createAnchor(name_00,
						frame_ind * frame_duration,
						unit_00);
		start_score(j) = score;
	      }
	      else {
		vstart(j) = vstart(j - 1);
		start_score(j) = start_score(j - 1);
	      }
	    }
	    else {
	      vstart(j) = vend(j);
	      start_score(j) = end_score(j);
	    }
	  }
	  else {  // ending level mark

	    if (pre_level.eq(level)) {  // no expansin to next level
	      vend(j) = angr_a.createAnchor(name_00,
					    (frame_ind + 1) * frame_duration,
					    unit_00);
	      end_score(j) = score;

	      // add the connection for all levels below current level
	      //
	      for (long k = j + 1; k < (long)numLevel; k++) {
		
		ancr_00 = angr_a.getAnchorById(vstart(j));
		ancr_01 = angr_a.getAnchorById(vend(j));
		
		newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
						   context);
		
		
		if (!angr_a.setFeature(newid_00, feat_00, level_tag(k))) {
		  return Error::handle(name(), L"create AG", ERR, __FILE__,
				       __LINE__);
		}
		
		level_index.assign(k);
		
		if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
		  return Error::handle(name(), L"create AG", ERR, __FILE__,
				       __LINE__);
		}	    
		
		float temp_score = end_score(j) - start_score(j);
		arc_score.assign(temp_score);
		if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {
		  return Error::handle(name(), L"create AG", ERR, __FILE__,
				       __LINE__);
		}
		start_score(k) = end_score(j);
		vstart(k) = vend(j);
		
	      }
	      
	    }
	    else {
	      vend(j) = vstart(j + 1);
	      end_score(j) = start_score(j + 1);
	    }
	    
	    ancr_00 = angr_a.getAnchorById(vstart(j));
	    ancr_01 = angr_a.getAnchorById(vend(j));
	    
	    newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
					       context);
	    
	    if (!angr_a.setFeature(newid_00, feat_00, level)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }

	    level_index.assign(j);
	    
	    if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }	    

	    float temp_score = end_score(j) - start_score(j);
	    arc_score.assign(temp_score);
	    if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }

	    start_score(j) = end_score(j);
  
	  }
	  
	  vflag(j) = !vflag(j);
	  if ( frame_ind != 0)
	    vstart(j) = vend(j);
	  	  
	  break;
	}
	
	else if (j == (long)numLevel - 1 && level.eq(level_tag(j))) {
	  
	  // insert state to AG
	  //
	  if (frame_ind == prev_frame_ind) {
	    vstart(j) = vstart(j - 1);
	    if (frame_ind == 0) {
	      start_score(j) = 0;
	    }
	    else {
	      start_score(j) = end_score(j);
	    }
	    vend(j) = angr_a.createAnchor(name_00,
					  (frame_ind + 1) * frame_duration,
					  unit_00);
	    end_score(j) = score;
	    
	    ancr_00 = angr_a.getAnchorById(vstart(j));
	    ancr_01 = angr_a.getAnchorById(vend(j));
	    
	    newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
					       context);
	    
	    if (!angr_a.setFeature(newid_00, feat_00, level)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    level_index.assign(j);
	    
	    if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    float temp_score = end_score(j) - start_score(j);
	    arc_score.assign(temp_score);
	    if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {	    
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    vflag(j) = !vflag(j);
	    vstart(j) = vend(j);
	    start_score(j) = end_score(j);
	  }
	  else {
	    vend(j) = angr_a.createAnchor(name_00,
					  (frame_ind + 1) * frame_duration,
					  unit_00);
	    end_score(j) = score;
	    
	    ancr_00 = angr_a.getAnchorById(vstart(j));
	    ancr_01 = angr_a.getAnchorById(vend(j));
	    
	    newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
					       context);
	    
	    if (!angr_a.setFeature(newid_00, feat_00, level)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    level_index.assign(j);
	    
	    if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }

	    float temp_score = end_score(j) - start_score(j);
	    arc_score.assign(temp_score);
	    if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {	    
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    vflag(j) = !vflag(j);
	    vstart(j) = vend(j);
	    start_score(j) = end_score(j);
	  }
	  break;
	}
      }
      prev_frame_ind = frame_ind;
      pre_level = level;
    }
  }

  // exit gracefully
  //
  return true;
  
}

// method: createAnnotationGraph
//
// arguments:
//  AnnotationGraph& angr: (output) the output AnnotationGraph
//  DoubleLinkedList<Instance>& instance_path: (input) best hypothesis instance path
//
// return: boolean value
//
// build a AnnotationGraph representing the hypotheses and return it
//
boolean HiddenMarkovModel::createAnnotationGraph(AnnotationGraph& angr_a,
						 DoubleLinkedList<Instance>& instance_path_a) {
  // declare local variables
  //
  Instance* tmp_instance = (Instance*)NULL;
  SearchNode*  tmp_node = (SearchNode*)NULL;
  
  //  long phone_counter = 0;  
  long curr_level = 0;
  long frame_ind = 0;
  long prev_frame_ind = -1;
  float score = 0.0;
  float frame_duration = vector_fe_d((long)0).getFrameDuration();
 
  SearchSymbol sym;

  // get id and type of the AnnotationGraph
  //
  String name_00;
  name_00 = angr_a.getId();

  String gtype_00;
  gtype_00 = angr_a.getType();
  
  String newid_00;
  
  Anchor* ancr_00 = (Anchor*)NULL;
  Anchor* ancr_01 = (Anchor*)NULL;
  
  String unit_00;
  unit_00.assign(L"seconds");
  
  String feat_00;
  feat_00.assign(AnnotationGraph::PARAM_SEARCH_LEVEL);

  String feat_01;
  feat_01.assign(AnnotationGraph::PARAM_SEARCH_LEVEL_INDEX);

  String feat_02;
  feat_02.assign(AnnotationGraph::PARAM_SCORE);
  
  String pre_level;
  String arc_score;
  
  Long numLevel = search_engine_d.getNumLevels();

  Vector <String> level_tag(numLevel);

  for (long j = 0; j < numLevel; j++) {
    SearchLevel& search_level = search_engine_d.getSearchLevel(j);
    level_tag(j).assign(search_level.getLevelTag());
  }
      
  Vector <String> vlevel(numLevel);
  Vector <Boolean> vflag(numLevel);
  Vector <String> vstart(numLevel);
  Vector <String> vend(numLevel);
  Vector <Float> start_score(numLevel);
  Vector <Float> end_score(numLevel);  
  
  for (long i = 0; i < numLevel; i++) {
    vflag(i) = true;
  }
  
  // use the best hypothesis instance path to generate the AnnotationGraph
  //
  for (boolean more_instances = instance_path_a.gotoFirst(); more_instances;
       more_instances = instance_path_a.gotoNext()) {
    
    tmp_instance = instance_path_a.getCurr();
    frame_ind = tmp_instance->getFrame();
    
    // get the central vertex from the top of the history stack
    //
    GraphVertex<SearchNode>* tmp_vertex = (GraphVertex<SearchNode>*)NULL;
    tmp_vertex = tmp_instance->getSymbol()->getCentralVertex();

    // check for a NULL vertex
    //
    if (tmp_vertex == (GraphVertex<SearchNode>*)NULL) {
      continue;
    }
    
    // make sure the vertex is neither the dummy
    // start nor terminating node
    //
    else if ((!tmp_vertex->isStart()) &&
	(!tmp_vertex->isTerm())) {

      tmp_node = tmp_vertex->getItem();
      curr_level = tmp_node->getSearchLevel()->getLevelIndex();
      
      tmp_node->getSymbol(sym);

      // check if this is a dummy node, skip dummy node
      //
      if (tmp_node->isDummyNode()) {
	continue;
      }    

      String level = tmp_node->getSearchLevel()->getLevelTag();
      score = tmp_instance->getScore();
      
      String context;
      tmp_instance->getSymbol()->print(context);
      sym.assign(context);

      String level_index;

      for (long j = 0; j < numLevel; j++) {
	
	if (j != (long)numLevel - 1 && level.eq(level_tag(j))) {

	  // insert word to AG
	  //
	  if (vflag(j)) {  // starting level mark
	    if (frame_ind == 0) {
	      if ( j == 0) {
		vstart(j) = angr_a.createAnchor(name_00,
						frame_ind * frame_duration,
						unit_00);
		start_score(j) = score;
	      }
	      else {
		vstart(j) = vstart(j - 1);
		start_score(j) = start_score(j - 1);
	      }
	    }
	    else {
	      vstart(j) = vend(j);
	      start_score(j) = end_score(j);
	    }
	  }
	  else {  // ending level mark

	    if (pre_level.eq(level)) {  // no expansin to next level
	      vend(j) = angr_a.createAnchor(name_00,
					    (frame_ind + 1) * frame_duration,
					    unit_00);
	      end_score(j) = score;

	      // add the connection for all levels below current level
	      //
	      for (long k = j + 1; k < (long)numLevel; k++) {
	    
		ancr_00 = angr_a.getAnchorById(vstart(j));
		ancr_01 = angr_a.getAnchorById(vend(j));
	    
		newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
						   context);

	    
		if (!angr_a.setFeature(newid_00, feat_00, level_tag(k))) {
		  return Error::handle(name(), L"create AG", ERR, __FILE__,
				       __LINE__);
		}

		level_index.assign(k);
		
		if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
		  return Error::handle(name(), L"create AG", ERR, __FILE__,
				       __LINE__);
		}	    

		float temp_score = end_score(j) - start_score(j);
		arc_score.assign(temp_score);
		if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {
		  return Error::handle(name(), L"create AG", ERR, __FILE__,
				       __LINE__);
		}
		start_score(k) = end_score(j);
		vstart(k) = vend(j);
		
	      }
	    } // end if if (pre_level...
	    else {
	      vend(j) = vstart(j + 1);
	      end_score(j) = start_score(j + 1);
	    }
 	    
	    ancr_00 = angr_a.getAnchorById(vstart(j));
	    ancr_01 = angr_a.getAnchorById(vend(j));
	    
	    newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
					       context);
	    
	    if (!angr_a.setFeature(newid_00, feat_00, level)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }

	    level_index.assign(j);
	    
	    if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }	    

	    float temp_score = end_score(j) - start_score(j);
	    arc_score.assign(temp_score);
	    if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }

	    start_score(j) = end_score(j);
  
	  }
	  
	  vflag(j) = !vflag(j);
	  if ( frame_ind != 0)
	    vstart(j) = vend(j);
	  	  
	  break;
	}
	
	else if (j == (long)numLevel - 1 && level.eq(level_tag(j))) {
	  
	  // insert state to AG
	  //
	  if (frame_ind == prev_frame_ind) {
	    vstart(j) = vstart(j - 1);
	    if (frame_ind == 0) {
	      start_score(j) = 0;
	    }
	    else {
	      start_score(j) = end_score(j);
	    }
	    
	    vend(j) = angr_a.createAnchor(name_00,
					  (frame_ind + 1) * frame_duration,
					  unit_00);
	    end_score(j) = score;
	    
	    ancr_00 = angr_a.getAnchorById(vstart(j));
	    ancr_01 = angr_a.getAnchorById(vend(j));
	    
	    newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
					       context);
	    
	    if (!angr_a.setFeature(newid_00, feat_00, level)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    level_index.assign(j);
	    
	    if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    float temp_score = end_score(j) - start_score(j);
	    arc_score.assign(temp_score);
	    if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {	    
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    vflag(j) = !vflag(j);
	    vstart(j) = vend(j);
	    start_score(j) = end_score(j);
	  }
	  else {
	    vend(j) = angr_a.createAnchor(name_00,
					  (frame_ind + 1) * frame_duration,
					  unit_00);
	    end_score(j) = score;
	    
	    ancr_00 = angr_a.getAnchorById(vstart(j));
	    ancr_01 = angr_a.getAnchorById(vend(j));
	    
	    newid_00 = angr_a.createAnnotation(name_00, ancr_00, ancr_01,
					       context);
	    
	    if (!angr_a.setFeature(newid_00, feat_00, level)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    level_index.assign(j);
	    
	    if (!angr_a.setFeature(newid_00, feat_01, level_index)) {
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }

	    float temp_score = end_score(j) - start_score(j);
	    arc_score.assign(temp_score);
	    if (!angr_a.setFeature(newid_00, feat_02, arc_score)) {	    
	      return Error::handle(name(), L"create AG", ERR, __FILE__,
				   __LINE__);
	    }
	    
	    vflag(j) = !vflag(j);
	    vstart(j) = vend(j);
	    start_score(j) = end_score(j);
	  }
	  break;
	}
      }
      prev_frame_ind = frame_ind;
      pre_level = level;
    }
  }

  // exit gracefully
  //
  return true;
  
}


// method: pruneAnnotationGraph
//
// arguments:
//  AnnotationGraph& anno: (output) the AnnotationGraph
//
// return: boolean value
//
// prune the AnnotationGraph representing the hypotheses according to
// the output levels
//
boolean HiddenMarkovModel::pruneAnnotationGraph(AnnotationGraph& anno_a) {

  Long numLevel = search_engine_d.getNumLevels();

  Vector <String> level_tag(numLevel);

  for (long j = 0; j < numLevel; j++) {
    SearchLevel& search_level = search_engine_d.getSearchLevel(j);
    level_tag(j).assign(search_level.getLevelTag());
  }

  String feat_00;
  feat_00.assign(AnnotationGraph::PARAM_SEARCH_LEVEL);
  
  // prune the uncessary tools
  //
  for (long j = 0; j < level_tag.length(); j++) {
    if (output_levels_d(j) == OFF) {
      anno_a.deleteAnnotationSetByFeature(feat_00, level_tag(j));
    }
  }
  
  return true;
}

