// file: $isip/class/search/StackSearch/ssrch_18.cc
// version: $Id: ssrch_18.cc 9144 2003-05-16 21:59:27Z jelinek $
//

// isip include files
//
#include "StackSearch.h"

// method: transformSkipModels
//
// arguments: none
//
// return: logical error status
//
// move each START->TERM transition to the above level
//
boolean StackSearch::transformSkipModels() {
    
  // define local variables
  //
  long num_levels = getNumLevels();

  // loop through all levels above the lowest level
  //
  for (long level_ind = num_levels - 2; level_ind >= 0; level_ind--) {
    
    long num_graphs = getSearchLevel(level_ind).getNumSubGraphs();
    
    // loop through all graphs at this level
    //
    for (long graph_ind = 0; graph_ind < num_graphs; graph_ind++) {

      DiGraph<SearchNode>& graph = 
	getSearchLevel(level_ind).getSubGraph(graph_ind);

      // loop over all vertices, except terminal and move skip arcs
      // of the subgraphs to this vertex
      //
      GraphVertex<SearchNode>* vertex = graph.getStart();
      addSkipArcs(vertex, level_ind);

      for (boolean more_vertices = graph.gotoFirst();
	   more_vertices;
	   more_vertices = graph.gotoNext()) {

	addSkipArcs(graph.getCurr(), level_ind);
      }
    }
  }
  
  // exit gracefully
  //
  return true;
}

// method: addSkipArcs
//
// arguments:
//  GraphVertex<SearchNode>* vertex: (input) vertex
//  long level_ind: (input) index of the current level
//
// return: logical error status
//
// add the skip tranisionts from lower level subgraph to this vertex
//
boolean StackSearch::addSkipArcs(GraphVertex<SearchNode>* vertex_a,
				 long level_ind_a) {

  for (boolean more = vertex_a->gotoFirst();
       more;
       more = vertex_a->gotoNext()) {

    GraphVertex<SearchNode>* vertex_next = vertex_a->getCurr()->getVertex();

    // if next vertex is terminal, nothing needs to be done
    //
    if (!vertex_next->isTerm()) {
      
      float score = vertex_a->getCurr()->getWeight();

      // if the subgraph of next vertex has a skip arc, remove it
      // (the code below works only with CI models!!!)
      //

      // first get the subgraph index
      //
      Context curr_context;
      curr_context.assignAndAdvance((ulong)vertex_next);
      curr_context.convert();

      SearchLevel& sl_curr = getSearchLevel(level_ind_a);
      Ulong* subgr_ind = sl_curr.getSubGraphIndex(curr_context);
	  
      if (subgr_ind == (Ulong*)NULL) {

	// throw an error message and exit
	//
	String out(L"addSkipArcs - no subgraph for context: ");
	curr_context.debug(L"undefined context");
	Console::put(out);
	return Error::handle(name(), L"addSkipArcs",
			     Error::ARG, __FILE__, __LINE__);
      }

      long subgr_index_long = (long)*subgr_ind;

      SearchLevel& sl_lower = getSearchLevel(level_ind_a + 1);
      DiGraph<SearchNode>& sub_graph =
	sl_lower.getSubGraph(subgr_index_long);

      // get the subgraph start vertex
      // 
      GraphVertex<SearchNode>* sub_start_vert =
	(sl_lower.getSubGraph((long)*subgr_ind)).getStart();

      sub_start_vert = sub_graph.getStart();
      for (boolean more_arcs = sub_start_vert->gotoFirst();
	   more_arcs;
	   more_arcs = sub_start_vert->gotoNext()) {

	GraphArc<SearchNode>* curr_sub_arc = sub_start_vert->getCurr();
	GraphVertex<SearchNode>* curr_arc_vert = curr_sub_arc->getVertex();

	// if subgraph has START->TERM transition, add it
	// 
	if (curr_arc_vert->isTerm()) {

	  // store a skip score
	  //
	  float skip_score = curr_sub_arc->getWeight();

	  // remove skip transition from lower level
	  //
	  sub_start_vert->removeArc(curr_arc_vert);

	  // add corresponding arcs to all the succesors of the
	  // vertex_next at the higher level
	  //
	  for (boolean more_arcs = vertex_next->gotoFirst();
	       more_arcs;
	       more_arcs = vertex_next->gotoNext()) {

	    GraphArc<SearchNode>* arc_next_next = vertex_next->getCurr();
	    GraphVertex<SearchNode>* vertex_next_next =
	      arc_next_next->getVertex();
	    float score_next_next = arc_next_next->getWeight();
	    vertex_a->insertArc(vertex_next_next,
				score + skip_score + score_next_next);
	  }
	}
      }
    }
  }
  
  // exit gracefully
  //
  return true;
}
