// file: $isip/class/asr/JSGFParser/jp_09.cc
// version: $Id: jp_09.cc 10499 2006-03-15 21:43:17Z may $
//
// isip include files
//
#include "JSGFParser.h"

// method: drawGraph
//
// arguments: none
//
// return: a boolean value indicating status
//
// This method draw a ISIP DiGraph (directed graph) based on the given rules
// in the grammar
//
boolean JSGFParser::drawGraph() {
  
  Stack<String> replaced_rules_a;
  
  // replace all rule reference
  //
  JSGFToken t;
  t = public_rule_table_d(0).first();
  
  replaced_rules_a.clear();

  replaceRuleReference(t, replaced_rules_a);


  /////////////////////////////////////////////////////////////
  Queue<JSGFToken> final = final_d;
  while (!final.isEmpty()) {
    JSGFToken tt;
    final.remove(&tt);
    //tt.printToken();
    if (tt.getTokenType() == JSGFToken::TERMINAL ||
	tt.getTokenType() == JSGFToken::QUOTED_TOKEN) {
      String cc;
      cc.assign(tt.vertex_index_d);
      //  cc.debug(L"-------------index");
    } 
  }
  //////////////////////////////////////////////////////////////

  // preprocess the token queue final_d by getting rid of weight tokens
  // after setting the weight values to their modified object
  // tag tokens are also skipped
  //
  Queue<JSGFToken> tmp_queue;

  while (!final_d.isEmpty()) {

    JSGFToken current, next;
    final_d.remove(&current);

    // skip tag token
    //
    if (current.getTokenType() == JSGFToken::TAG) {
      continue;
    }
    // get rid of weight token after assigning its value to appropriate object
    //
    else if (current.getTokenType() == JSGFToken::WEIGHT) {
      
      // get the next token and assign the weight to it
      //
      final_d.remove(&next);
      next.setTerminalWeight(current);
      tmp_queue.add(&next);
    }
    // otherwise store the token
    //
    else {
      tmp_queue.add(&current);
    }
  }

  // update the token queue final_d
  //
  final_d.assign(tmp_queue);
////////////////////////////////////////////////////////////////
/////////////////// debug /////////////////////////////////////
  final = final_d;
  while (!final.isEmpty()) {
    JSGFToken tt;
    final.remove(&tt);
    //tt.printToken();
    if (tt.getTokenType() == JSGFToken::TERMINAL ||
	tt.getTokenType() == JSGFToken::QUOTED_TOKEN) {
      String cc;
      cc.assign(tt.vertex_index_d);
      //  cc.debug(L"-------------index");
    } 
    Float w(tt.weight_d);
    //  w.debug(L"--------------------weight----");
  }
//////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////  

  // declare dummy arrays
  //
  Vector<JSGFToken> dummy_start;
  Vector<JSGFToken> dummy_end;
  boolean is_alter = false; 

  // call the recursive function to draw the graph
  //
  drawUnit(dummy_start, dummy_end, is_alter);

  // exit gracefully
  //
  return true;
}

// method: drawUnit
// arguments: Vector<JSGFToken>& start_a: (input/output) start token of
//                                        the rule/group 
//            Vector<JSGFToken>& end_a: (input/output) end token of
//                                        the rule/group
//            boolean is_alter: (input) boolean value for determing if the
//                              token or group  is alternative
//
// return: a boolean value indicating status
//
// This recursive method draws a rule unit in parentheses
//
boolean JSGFParser::drawUnit(Vector<JSGFToken>& start_a,
			     Vector<JSGFToken>& end_a,
			     boolean is_alter_a) {

  // declare variables
  //
  JSGFToken current, next, dummy;
  JSGFToken*  op_token;
  Long curr_vert_index;
    
  // get the first token as the current
  //
  final_d.remove(&current);

  // if the current token is ( leading a grouping unit
  // recursively process the grouped rule expansion
  //
  if (current.operator_d(0).eq(L"(")) {
    drawUnit(start_a, end_a, false);
    boolean is_loop = false;
    
    // get weight
    //
    boolean epsilon = true;
    float weight = 0.0;
    if (current.weighted_terminal_d) {
      epsilon = false;
      weight = current.weight_d;
    }
    
    // determining if next token is "+" or "*" 
    //
    if (final_d.length() != 0) {
      op_token = final_d.peek();
      if (op_token->operator_d(0).eq(L"+") ||
	  op_token->operator_d(0).eq(L"*" )) {
	is_loop = true;
	
	// set flag (is_head_group_d = true) for each token in the start_a
	// 
	if (op_token->operator_d(0).eq(L"*" )) {
	  for(int i = 0; i < start_a.length(); i++) {
	    start_a(i).is_head_group_d = true;
	  }
	}
	final_d.remove(&dummy);
      }
    }

    if(is_loop) {
      
      for(int i = 0; i < end_a.length(); i++) {
	GraphVertex<String>* end_vert = vertex_list_d[end_a(i).vertex_index_d];
	for(int j = 0; j < start_a.length(); j++) {
	  GraphVertex<String>* start_vert = vertex_list_d[start_a(j).vertex_index_d];
	  boolean find_arc = findArcIndex(end_a(i).vertex_index_d, start_a(j).vertex_index_d);
	  if(!find_arc) {

	    Pair< Long, Long> pair;
	    Long t_1(end_a(i).vertex_index_d);
	    Long t_2(start_a(j).vertex_index_d);
	    pair.assign(t_1, t_2);
	    arc_index_d.concat(pair);
	 
	    // there exists weight problem for + or *
	    //draw arc from parent to the child (next)
	    //
	    graph_d.insertArc(end_vert, start_vert, false, weight);
	  }
	} // end for loop(int j = 0)
      } //end for loop(int i = 0)
    }

    // set weight for each start token
    //
    for(int j = 0; j < start_a.length(); j++) {
      if(current.weighted_terminal_d && !is_loop) {
	start_a(j).weighted_terminal_d = true;
	start_a(j).weight_d = current.weight_d;
      }       
    }// end for loop (int j =0)
  }

  // if the current token is [ leading a optional grouping unit
  // recursively process the optional grouped rule expansion
  //
  if (current.operator_d(0).eq(L"[")) {
    //is_optional = true;
    drawUnit(start_a, end_a, false);
    boolean is_loop = false;

    // get weight
    //
    boolean epsilon = true;
    float weight = 0.0;
    if (current.weighted_terminal_d) {
      epsilon = false;
      weight = current.weight_d;
    }
    
    // set flag (is_head_group_d = true) for each token in the start_a
    //      
    for(int i = 0; i < start_a.length(); i++) {
      start_a(i).is_head_group_d = true;
    }

    // determining if next token is "+" or "*" 
    //
    if (final_d.length() != 0) {
      op_token = final_d.peek();
      if (op_token->operator_d(0).eq(L"+") ||
	  op_token->operator_d(0).eq(L"*" )) {
	final_d.remove(&dummy);
	is_loop = true;
      }
    }
    
    if(is_loop) {
      
      for(int i = 0; i < end_a.length(); i++) {
	GraphVertex<String>* end_vert = vertex_list_d[end_a(i).vertex_index_d];
	for(int j = 0; j < start_a.length(); j++) {
	  GraphVertex<String>* start_vert = vertex_list_d[start_a(j).vertex_index_d];
	  boolean find_arc = findArcIndex(end_a(i).vertex_index_d, start_a(j).vertex_index_d);
	  if(!find_arc) {
	    
	    Pair< Long, Long> pair;
	    Long t_1(end_a(i).vertex_index_d);
	    Long t_2(start_a(j).vertex_index_d);
	    pair.assign(t_1, t_2);	        
	    arc_index_d.concat(pair);
	    
	    // there exists weight problem for + or *
	    //draw arc from parent to the child (next)
	    //
	    graph_d.insertArc(end_vert, start_vert, false, weight);
	  }
	} // end for loop(int j = 0)
      } //end for loop(int i = 0)
    }

    // set weight for each start token
    //
    for(int j = 0; j < start_a.length(); j++) {
      if(current.weighted_terminal_d && !is_loop) {
	start_a(j).weighted_terminal_d = true;
	start_a(j).weight_d = current.weight_d;
      }       
    }// end for loop (int j =0)
    
  }

  // if it is terminal or quoted token, create a vertex and add to the array
  //
  if (current.getTokenType() == JSGFToken::TERMINAL ||
      current.getTokenType() == JSGFToken::QUOTED_TOKEN) {

    // store corresponding vertex index of the token into the start list
    //
    curr_vert_index = current.vertex_index_d;
    start_a.concat(current);
    end_a.concat(current);
    
    // get weight
    //
    boolean epsilon = true;
    float weight = 0;
    if (current.weighted_terminal_d) {
      epsilon = false;
      weight = current.weight_d;
    }
    GraphVertex<String>* child_vert = vertex_list_d[current.vertex_index_d];
    
    // determining if next token is "+" or "*" 
    //
    if (final_d.length() != 0) {
      op_token = final_d.peek();
      if (op_token->operator_d(0).eq(L"+") ||
	  op_token->operator_d(0).eq(L"*" )) {
	final_d.remove(&dummy);
	current.is_head_group_d = true;
	boolean find_arc = findArcIndex(current.vertex_index_d, current.vertex_index_d);
	if(!find_arc) {
	  
	    Pair< Long, Long> pair;
	    Long t_1(current.vertex_index_d);
	    Long t_2(current.vertex_index_d);
	    pair.assign(t_1, t_2);	        
	    arc_index_d.concat(pair);
	    
	    // there exists weight problem for + or *
	    //draw arc from parent to the child (next)
	    //
	    if (!epsilon) {
	      graph_d.insertArc(child_vert, child_vert, false, weight);
	    }
	    else {
	      graph_d.insertArc(child_vert, child_vert, true);
	    }
	}
      }
    }
  }

  // if the next is a recursive grammar
  // 
  else if (current.operator_d(0).eq(L"@@")) {

    Stack<String> replaced_rules;

    // token queue for final processing in graph drawing section
    //
    Queue<JSGFToken> rule_final;
    
    // replace all rule reference
    //
    String t;
    boolean is_processed = false;
    t = current.rulename_d;
    for(long i = 0; i < recursive_grammar_d.length(); i++) {
      if(t.eq(recursive_grammar_d(i).first())) {
	is_processed = true;
	start_a.concat(recursive_grammar_d(i).second());
	end_a.clear(Integral::RELEASE);
      }	
    }

    if(!is_processed) {
      replaced_rules.clear();
    
      replaceRecursionRuleReference(t, replaced_rules, rule_final);
  
      /////////////////////////////////////////////////////////////
      Queue<JSGFToken> final = rule_final;
      while (!final.isEmpty()) {
	JSGFToken tt;
	final.remove(&tt);
	//tt.printToken();
      }
      //////////////////////////////////////////////////////////////
    
      // preprocess the token queue final_d by getting rid of weight tokens
      // after setting the weight values to their modified object
      // tag tokens are also skipped
      //
      Queue<JSGFToken> tmp_queue;

      while (!rule_final.isEmpty()) {
	
	JSGFToken current, next;
	rule_final.remove(&current);
	
	// skip tag token
	//
	if (current.getTokenType() == JSGFToken::TAG) {
	  continue;
	}
	// get rid of weight token after assigning its value to appropriate object
	//
	else if (current.getTokenType() == JSGFToken::WEIGHT) {
	  
	  // get the next token and assign the weight to it
	  //
	  rule_final.remove(&next);
	  next.setTerminalWeight(current);
	  tmp_queue.add(&next);
	}
	// otherwise store the token
	//
	else {
	  tmp_queue.add(&current);
	}
      }
  
      // update the token queue rule_final
      //
      rule_final.assign(tmp_queue);
      
      ////////////////////////////////////////////////////////////////
      /////////////////// debug /////////////////////////////////////
      final = rule_final;
      while (!final.isEmpty()) {
	JSGFToken tt;
	final.remove(&tt);
	//      tt.printToken();
	Float w(tt.weight_d);
	//      w.debug(L"--------------------weight----");
      }
      //////////////////////////////////////////////////////////////
      ///////////////////////////////////////////////////////////////  
      
      // call the recursive function to get start token and end token
      // for the right recursive rule
      //
      searchStartEnd(start_a, end_a, false, rule_final);
      end_a.clear(Integral::RELEASE);
      Pair<String, Vector<JSGFToken> > pair;
      Vector<JSGFToken> start_tokens;
      start_tokens.concat(start_a);
      pair.assign(t, start_tokens);      
      recursive_grammar_d.concat(pair);
    }
    
    // set weight for each start token
    //
    for(int j = 0; j < start_a.length(); j++) {
      if(current.weighted_terminal_d) {
	start_a(j).weighted_terminal_d = true;
	start_a(j).weight_d = current.weight_d;
      }       
    }// end for loop (int j =0)
    
  }

  // loop through all tokens until meeting a grouping unit or the end
  //
  while (true) {

    JSGFToken*  op_token1;
    Long next_vert_index;
    //    GraphVertex<String>* next_vert;

    if(final_d.length() == 0)
      break;

    if (is_alter_a) {
      
      // determining if next token is "]" or ")" or ";" 
      //
      op_token1 = final_d.peek();
      if (op_token1->operator_d(0).eq(L"]") ||
	  op_token1->operator_d(0).eq(L")")) {
	break;
      }
    }

    // get the next token
    //
    final_d.remove(&next);
    if (next.operator_d(0).eq(L"]") ||
	next.operator_d(0).eq(L")")) {
      break;
    }

    // if the next token is a terminal or quoted token for sequence
    //
    if (next.getTokenType() == JSGFToken::TERMINAL ||
	next.getTokenType() == JSGFToken::QUOTED_TOKEN) {

      // initialize is_optional = false;
      //
      boolean is_optional = false;
      
      // get weight
      //
      boolean epsilon = true;
      float weight = 0.0;
      if (next.weighted_terminal_d) {
	epsilon = false;
	weight = next.weight_d;
      }

      GraphVertex<String>* child_vert = vertex_list_d[next.vertex_index_d];
      JSGFToken* op_token2 = (JSGFToken*)NULL;

      // determining if next token is "+" or "*" 
      //
      if (final_d.length() != 0) {

	op_token2 = final_d.peek();

	if (op_token2->operator_d(0).eq(L"+") ||
	    op_token2->operator_d(0).eq(L"*" )) {

	  final_d.remove(&dummy);
	  boolean find_arc = findArcIndex(next.vertex_index_d, next.vertex_index_d);
	  if(!find_arc) {
	    
	    Pair< Long, Long> pair;
	    Long t_1(next.vertex_index_d);
	    Long t_2(next.vertex_index_d);
	    pair.assign(t_1, t_2);	        
	    arc_index_d.concat(pair);
	    
	    // there exists weight problem for + or *
	    //draw arc from parent to the child (next)
	    //
	    if (!epsilon) {
	      graph_d.insertArc(child_vert, child_vert, false, weight);
	    }
	    else {
	      graph_d.insertArc(child_vert, child_vert, true);
	    }
	  }
	}

	// determing if there exists optional_group token in the start_a
	//
	for(int j = 0; j < start_a.length(); j++) {
	  if(start_a(j).is_head_group_d) {
	    is_optional = true;
	    if (!op_token2->operator_d(0).eq(L"*")) {
	      start_a(j).is_head_group_d = false;
	    }
	  } 
	}// end for loop (int j =0)
      }// end if (final_d.length() != 0)

      else {
	
	// determing if there exists optional_group token in the start_a
	//
	for(int j = 0; j < start_a.length(); j++) {
	  if(start_a(j).is_head_group_d) {
	    is_optional = true;
	    start_a(j).is_head_group_d = false;
	  } 
	}// end for loop (int j =0)
      }
      
      // add the vertex_index into start_a list if its parent is optional
      //
      if (is_optional) {
	start_a.concat(next);
	is_optional = false;
      }
      
      for(int i = 0; i < end_a.length(); i++) {
	long end_index = end_a(i).vertex_index_d;
	GraphVertex<String>* parent_vert = vertex_list_d[end_index];
	boolean find_arc = findArcIndex(end_index, next.vertex_index_d);
	if(!find_arc) {
	    
	  Pair< Long, Long> pair;
	  Long t_1(end_index);
	  Long t_2(next.vertex_index_d);
	  pair.assign(t_1, t_2);	        
	  arc_index_d.concat(pair);

	  //draw arc from parent to child (next)
	  //
	  if (!epsilon) {
	    graph_d.insertArc(parent_vert, child_vert, false, weight);
	  }
	  else {
	    graph_d.insertArc(parent_vert, child_vert, true);
	  }
	}
      } // end for loop(i=0)
      
      if ((op_token2 != (JSGFToken*)NULL) &&
	  (op_token2->operator_d(0).eq(L"*"))) {
	end_a.concat(next);
      }
      else {
	if(end_a.length() != 0) {
	  end_a.clear(Integral::RELEASE);
	}
	end_a.concat(next);	
      }
    }

    // if the next token is ( leading a grouping unit
    // recursively process the grouped rule expansion
    //
    else if (next.operator_d(0).eq(L"(")) {
      
      Vector<JSGFToken> sub_start;
      Vector<JSGFToken> sub_end;

      // get weight
      //
      boolean epsilon = true;
      float weight = 0.0;
      if (next.weighted_terminal_d) {
	epsilon = false;
	weight = next.weight_d;
      }	 
      
      drawUnit(sub_start, sub_end, false);
      
      JSGFToken* op_token2 = (JSGFToken*)NULL;
      boolean is_loop = false;
      boolean is_optional = false;
	
      // determining if next token is "+" or "*"
      // sub_end.length() to test if it is recursive grammar
      //
      if (final_d.length() != 0 ) {
	op_token2 = final_d.peek();
	if (op_token2->operator_d(0).eq(L"+") ||
	    op_token2->operator_d(0).eq(L"*" )) {
	  if (op_token2->operator_d(0).eq(L"*")) {
	    
	    // setting optional_group_flag in the sub_start
	    //
	    for(int j = 0; j < sub_start.length(); j++) {
	      sub_start(j).is_head_group_d = true;
	    }
	  }
	  
	  if (sub_end.length() != 0)
	    is_loop = true;
	  else {

	    // skip (recursive grammar)+
	    //
	    is_loop = false;
	  }
	  final_d.remove(&dummy);
	}
      }
      
      if(is_loop) {

	for(int i = 0; i < sub_end.length(); i++) {
	  GraphVertex<String>* end_vert = vertex_list_d[sub_end(i).vertex_index_d];
	  for(int j = 0; j < sub_start.length(); j++) {
	    GraphVertex<String>* start_vert = vertex_list_d[sub_start(j).vertex_index_d];
	    boolean find_arc = findArcIndex(sub_end(i).vertex_index_d, sub_start(j).vertex_index_d);
	    if(!find_arc) {
	      
	      Pair< Long, Long> pair;
	      Long t_1(sub_end(i).vertex_index_d);
	      Long t_2(sub_start(j).vertex_index_d);
	      pair.assign(t_1, t_2);		
	      arc_index_d.concat(pair);
	      
	      // there exists weight problem for + or *
	      //draw arc from parent to the child (next)
	      //
	      graph_d.insertArc(end_vert, start_vert, false, weight);
	    }//end if(!find_arc)
	  } // end for loop(int j = 0)
	} //end for loop(int i = 0)
      }

      // determing if there exists optional_group token in the start_a
      //
      for(int j = 0; j < start_a.length(); j++) {
	if(start_a(j).is_head_group_d) {	  
	    is_optional = true;
	    break;
	} 
      }

      boolean is_optional_substart = false;
      
      // determing if there exists optional_group token in the sub_start
      //
      for(int j = 0; j < sub_start.length(); j++) {
	if(sub_start(j).is_head_group_d) {
	   is_optional_substart = true;
	  if(!is_optional) {
	    sub_start(j).is_head_group_d = false;
	  }
	}
      }

      if(is_optional == true && is_optional_substart == false) {
	for(int j = 0; j < start_a.length(); j++) {
	  if(start_a(j).is_head_group_d)	  
	       start_a(j).is_head_group_d = false;
	}
      }
      
      for(int j = 0; j < sub_start.length(); j++) {
	
	// get corresponding vertex_index of group tokens
	//
	JSGFToken child_token = sub_start(j);
	Long tmp_index = child_token.vertex_index_d;

	// get weight
	//
	boolean epsilon = true;
	float weight = 0.0;

	if(!is_loop && next.weighted_terminal_d) {
	  epsilon = false;
	  weight = next.weight_d;
	}
	else if (child_token.weighted_terminal_d) {
	  epsilon = false;
	  weight = child_token.weight_d;
	}
	
	// add the vertex_index into start_a list if its parent is optional
	//
	if (is_optional) {
	  start_a.concat(child_token);
	}

	GraphVertex<String>* child_vert = vertex_list_d[child_token.vertex_index_d];	
	for(int i = 0; i < end_a.length(); i++) {
	  
	  long end_index = end_a(i).vertex_index_d;
	  GraphVertex<String>* parent_vert = vertex_list_d[end_index];
	  boolean find_arc = findArcIndex(end_index, child_token.vertex_index_d);
	  if(!find_arc) {
	    
	    Pair< Long, Long> pair;
	    Long t_1(end_index);
	    Long t_2(child_token.vertex_index_d);
	    pair.assign(t_1, t_2);		
	    arc_index_d.concat(pair);
	    
	    //draw arc from parent to the child (next)
	    //
	    if (!epsilon) {
	      graph_d.insertArc(parent_vert, child_vert, false, weight);
	    }
	    else {
	      graph_d.insertArc(parent_vert, child_vert, true);
	    }
	  } // if(!find_arc)
	} // end for loop(i=0)
      } // end for loop(j=0)

      is_optional = false;
      if(sub_end.length() != 0) {
	if (is_optional_substart) {
	  for(int i = 0; i < sub_end.length(); i++) {
	    end_a.concat(sub_end(i));
	  }
	}
	else {
	  end_a.clear(Integral::RELEASE);
	  for(int i = 0; i < sub_end.length(); i++) {
	    end_a.concat(sub_end(i));
	  }	
	}
      }
      else {
	end_a.clear(Integral::RELEASE);
      }
    } // end if(next.operator_d(0).eq(L"("))

    // if the next token is [ leading a optional grouping unit
    // recursively process the optional grouped rule expansion
    //
    else if (next.operator_d(0).eq(L"[")) {
      
      Vector<JSGFToken> sub_start;
      Vector<JSGFToken> sub_end;
      boolean is_optional = false;

      // get weight
      //
      boolean epsilon = true;
      float weight = 0.0;
      if (next.weighted_terminal_d) {
	epsilon = false;
	weight = next.weight_d;
      }  
 
      drawUnit(sub_start, sub_end, false);

      // set is_head_group_d = true for each token of sub_start 
      //
      for(int j = 0; j < sub_start.length(); j++) {
	sub_start(j).is_head_group_d = true;
      }
      
      JSGFToken* op_token2 = (JSGFToken*)NULL;
      boolean is_loop = false;
      
      // determining if next token is "+" or "*" 
      //
      if (final_d.length() != 0 && sub_end.length() != 0) {
	op_token2 = final_d.peek();
	if (op_token2->operator_d(0).eq(L"+") ||
	    op_token2->operator_d(0).eq(L"*" )) {
	  final_d.remove(&dummy);
	  is_loop = true;
	}
      }

      if(is_loop) {
	
	for(int i = 0; i < sub_end.length(); i++) {
	  GraphVertex<String>* end_vert = vertex_list_d[sub_end(i).vertex_index_d];
	  for(int j = 0; j < sub_start.length(); j++) {
	    GraphVertex<String>* start_vert = vertex_list_d[sub_start(j).vertex_index_d];
	    boolean find_arc = findArcIndex(sub_end(i).vertex_index_d, sub_start(j).vertex_index_d);
	    if(!find_arc) {
	      
	      Pair< Long, Long> pair;
	      Long t_1(sub_end(i).vertex_index_d);
	      Long t_2(sub_start(j).vertex_index_d);
	      pair.assign(t_1, t_2);	        
	      arc_index_d.concat(pair);
	      
	      // there exists weight problem for + or *
	      //draw arc from parent to the child (next)
	      //
	      graph_d.insertArc(end_vert, start_vert, false, weight);
	    }// end  if(!find_arc) {
	  }// end for loop (int j=0)
	} //end for loop(int i = 0)
      }
      
      // determing if there exists optional_group token in the start_a
      //
      for(int j = 0; j < start_a.length(); j++) {
	if(start_a(j).is_head_group_d) {	  
	    is_optional = true;
	    break;
	} 
      }

      //      boolean is_optional_substart = true;
      
      // determing if there exists optional_group token in the sub_start
      //
      for(int j = 0; j < sub_start.length(); j++) {
	if(sub_start(j).is_head_group_d) {
	  if(!is_optional) {
	    sub_start(j).is_head_group_d = false;
	  }
	}
      }
      
      for(int j = 0; j < sub_start.length(); j++) {
	
	// get corresponding vertex_index of group tokens
	//
	JSGFToken child_token = sub_start(j);
	Long tmp_index = child_token.vertex_index_d;

	// get weight
	//
	boolean epsilon = true;
	float weight = 0.0;
	if(!is_loop && next.weighted_terminal_d) {
	  epsilon = false;
	  weight = next.weight_d;
	}
	else if (child_token.weighted_terminal_d) {
	  epsilon = false;
	  weight = child_token.weight_d;
	}
	
	// add the vertex_index into start_a list if its parent is optional
	//
	if (is_optional) {
	  start_a.concat(child_token);
	}

	GraphVertex<String>* child_vert = vertex_list_d[child_token.vertex_index_d];
	for(int i = 0; i < end_a.length(); i++) {
	  
	  long end_index = end_a(i).vertex_index_d;
	  GraphVertex<String>* parent_vert = vertex_list_d[end_index];
	  boolean find_arc = findArcIndex(end_index, child_token.vertex_index_d);
	  if(!find_arc) {
	      
	    Pair< Long, Long> pair;
	    Long t_1(end_index);
	    Long t_2(child_token.vertex_index_d);
	    pair.assign(t_1, t_2);	        
	    arc_index_d.concat(pair);
	    
	    //draw arc from parent to the child (next)
	    //
	    if (!epsilon) {
	      graph_d.insertArc(parent_vert, child_vert, false, weight);
	    }
	    else {
	      graph_d.insertArc(parent_vert, child_vert, true);
	    }
	  }//end if(!find_arc) {
	} // end for loop(i=0)
      } // end for loop(j=0)

      is_optional = false;
      for(int i = 0; i < sub_end.length(); i++) {
	  end_a.concat(sub_end(i));
      }
    } // end if(next.operator_d(0).eq(L"["))
      
    // if the next is a recursive grammar
    // 
    else if (next.operator_d(0).eq(L"@@")) {
      
      Stack<String> replaced_rules;

      // token queue for final processing in graph drawing section
      //
      Queue<JSGFToken> rule_final;
  
      // replace all rule reference
      //
      String t;
      t = next.rulename_d;      
      boolean is_processed = false;

      // declare dummy arrays
      //
      Vector<JSGFToken> sub_start;
      Vector<JSGFToken> sub_end;

      for(long i = 0; i < recursive_grammar_d.length(); i++) {
	if(t.eq(recursive_grammar_d(i).first())) {
	  is_processed = true;
	  sub_start.concat(recursive_grammar_d(i).second());
	  sub_end.clear(Integral::RELEASE);
	}	
      }

      if(!is_processed) {
	replaced_rules.clear();
	replaceRecursionRuleReference(t, replaced_rules, rule_final);
	
	/////////////////////////////////////////////////////////////
	Queue<JSGFToken> final = rule_final;
	while (!final.isEmpty()) {
	  JSGFToken tt;
	  final.remove(&tt);
	  //tt.printToken();
	}
	//////////////////////////////////////////////////////////////

	// preprocess the token queue final_d by getting rid of weight tokens
	// after setting the weight values to their modified object
	// tag tokens are also skipped
	//
	Queue<JSGFToken> tmp_queue;
	
	while (!rule_final.isEmpty()) {
	  
	  JSGFToken current, next;
	  rule_final.remove(&current);
	  
	  // skip tag token
	  //
	  if (current.getTokenType() == JSGFToken::TAG) {
	    continue;
	  }
	  // get rid of weight token after assigning its value to appropriate object
	  //
	  else if (current.getTokenType() == JSGFToken::WEIGHT) {
	    
	    // get the next token and assign the weight to it
	    //
	    rule_final.remove(&next);
	    next.setTerminalWeight(current);
	    tmp_queue.add(&next);
	  }
	  // otherwise store the token
	  //
	  else {
	    tmp_queue.add(&current);
	  }
	}
  
	// update the token queue rule_final
	//
	rule_final.assign(tmp_queue);
      
	////////////////////////////////////////////////////////////////
	/////////////////// debug /////////////////////////////////////
	final = rule_final;
	while (!final.isEmpty()) {
	  JSGFToken tt;
	  final.remove(&tt);
	  //	tt.printToken();
	  if (tt.getTokenType() == JSGFToken::TERMINAL ||
	      tt.getTokenType() == JSGFToken::QUOTED_TOKEN) {
	    String cc;
	    cc.assign(tt.vertex_index_d);
	    // cc.debug(L"-------------index");
	  } 
	  Float w(tt.weight_d);
	  //	w.debug(L"--------------------weight----");
	}
	//////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////  
	
	boolean is_alter = false;
	
	// call the recursive function to get start token and end token
	// for the right recursive rule
	//
	searchStartEnd(sub_start, sub_end, is_alter, rule_final);
	sub_end.clear(Integral::RELEASE);
	Pair<String, Vector<JSGFToken> > pair;
	Vector<JSGFToken> start_tokens;
	start_tokens.concat(sub_start);
	pair.assign(t, start_tokens);      
	recursive_grammar_d.concat(pair);
      }
      
      // connect the sub_start with end_a
      //''''''''''''''''''''''''
      boolean is_optional = false;
      
      // determing if there exists optional_group token in the start_a
      //
      for(int j = 0; j < start_a.length(); j++) {
	if(start_a(j).is_head_group_d) {	  
	  is_optional = true;
	  break;
	} 
      }

      boolean is_optional_substart = false;
      
      // determing if there exists optional_group token in the sub_start
      //
      for(int j = 0; j < sub_start.length(); j++) {
	if(sub_start(j).is_head_group_d) {
	  is_optional_substart = true;
	  if(!is_optional) {
	    sub_start(j).is_head_group_d = false;
	  }
	}
      }

      if(is_optional == true && is_optional_substart == false) {
	for(int j = 0; j < start_a.length(); j++) {
	  if(start_a(j).is_head_group_d) 	  
	       start_a(j).is_head_group_d = false;
	}
      }
      
      for(int j = 0; j < sub_start.length(); j++) {
	
	// get corresponding vertex_index of group tokens
	//
	JSGFToken child_token = sub_start(j);
	Long tmp_index = child_token.vertex_index_d;

	// get weight
	//
	boolean epsilon = true;
	float weight = 0.0;
	if (next.weighted_terminal_d) {
	  epsilon = false;
	  weight = next.weight_d;
	}

	// add the vertex_index into start_a list if its parent is optional
	//
	if (is_optional) {
	  start_a.concat(child_token);
	}

	GraphVertex<String>* child_vert = vertex_list_d[child_token.vertex_index_d];	
	for(int i = 0; i < end_a.length(); i++) {
	  
	  long end_index = end_a(i).vertex_index_d;
	  GraphVertex<String>* parent_vert = vertex_list_d[end_index];
	  boolean find_arc = findArcIndex(end_index, child_token.vertex_index_d);
	  if(!find_arc) {
	      
	    Pair< Long, Long> pair;
	    Long t_1(end_index);
	    Long t_2(child_token.vertex_index_d);
	    pair.assign(t_1, t_2);	        
	    arc_index_d.concat(pair);
	    
	    //draw arc from parent to the child (next)
	    //
	    if (!epsilon) {
	      graph_d.insertArc(parent_vert, child_vert, false, weight);
	    }
	    else {
	      graph_d.insertArc(parent_vert, child_vert, true);
	    }
	  }// end if(!find_arc) {
	} // end for loop(i=0)
      } // end for loop(j=0)

      is_optional = false;
      if(sub_end.length() != 0) {
	if (is_optional_substart) {
	  for(int i = 0; i < sub_end.length(); i++) {
	    end_a.concat(sub_end(i));
	  }
	}
	else {
	  end_a.clear(Integral::RELEASE);
	  for(int i = 0; i < sub_end.length(); i++) {
	    end_a.concat(sub_end(i));
	  }	
	}      
      }
      else {
	 end_a.clear(Integral::RELEASE);	 
      }
    } // end if (next.operator_d(0).eq(L"@@"))
      
    // if the next is vertical bar | for alternatives
    //
    else if (next.operator_d(0).eq(L"|")) {

      boolean is_optional = false;
      
      Vector<JSGFToken> sub_start;
      Vector<JSGFToken> sub_end;

      // set optional = false
      //
      if (is_optional) {
	is_optional = false;
      }
      
      // get weights for group tokens
      //........................

      drawUnit(sub_start, sub_end, true);

      for(int j = 0; j < sub_start.length(); j++) {
	
	// get corresponding vertex_index of group tokens
	//
	JSGFToken child_token = sub_start(j);	
	start_a.concat(child_token);	
      } // end for loop(j=0)

      for(int i = 0; i < sub_end.length(); i++) {
	end_a.concat(sub_end(i));
      }
    } // endif (next.operator_d(0).eq(L"|"))
  } // end of the while loop

  // exit gracefully
  //
  return true;
}

// method: searchStartEnd
//
// arguments: Vector<JSGFToken>& start_a: (input/output) start token of
//                                        the rule 
//            Vector<JSGFToken>& end_a: (input/output) end token of
//                                        the rule
//            boolean is_alter: (input) boolean value for determing if the
//                              token or group  is alternative
//            Queue<JSGFToken>& rule_final_a: (input) storing all tokens for
//                                            the grammar
// return: a boolean value indicating status
//
// This method get the start_tokens and end_tokens 
//
boolean JSGFParser::searchStartEnd(Vector<JSGFToken>& start_a, Vector<JSGFToken>& end_a, boolean is_alter, Queue<JSGFToken>& rule_final_a) { 
  
  // declare variables
  //
  JSGFToken current, next, dummy;
  JSGFToken* op_token = (JSGFToken*)NULL;
  Long curr_vert_index;
  boolean is_loop = false;
  
  // get the first token as the current
  //
  rule_final_a.remove(&current);

  // if the current token is ( leading a grouping unit
  // recursively process the grouped rule expansion
  //
  if (current.operator_d(0).eq(L"(")) {
    searchStartEnd(start_a, end_a, false, rule_final_a);

    // determining if next token is "+" or "*" 
    //
    if (rule_final_a.length() != 0) {
      op_token = rule_final_a.peek();
      if (op_token->operator_d(0).eq(L"+") ||
	  op_token->operator_d(0).eq(L"*" )) {
	rule_final_a.remove(&dummy);
	is_loop = true;

	// set flag (is_head_group_d = true) for each token in the start_a
	// 
	if (op_token->operator_d(0).eq(L"*" )) {
	  for(int i = 0; i < start_a.length(); i++) {
	    start_a(i).is_head_group_d = true;
	  }
	} // end if(op_token->operator_d(0).eq(L"*"))
      } 
    }    
  } //end if  (current.operator_d(0).eq(L"(")) {
  
  // if the current token is [ leading a optional grouping unit
  // recursively process the optional grouped rule expansion
  //
  if (current.operator_d(0).eq(L"[")) {

    searchStartEnd(start_a, end_a, false, rule_final_a);
    boolean is_loop = false;
    
    // determining if next token is "+" or "*" 
    //
    if (rule_final_a.length() != 0) {
      op_token = rule_final_a.peek();
      if (op_token->operator_d(0).eq(L"+") ||
	  op_token->operator_d(0).eq(L"*" )) {
	rule_final_a.remove(&dummy);
	is_loop = true;
      }
    }

    // set flag (is_head_group_d = true) for each token in the start_a
    //    
    for(int i = 0; i < start_a.length(); i++) {
      start_a(i).is_head_group_d = true;
    }    
  } // end  if (current.operator_d(0).eq(L"[")) {

  // if the next is a recursive grammar
  //   
  if (current.operator_d(0).eq(L"@@")) {

    // do nothing
    //
  } 
  
  // if it is terminal or quoted token, create a vertex and add to the array
  //
  if (current.getTokenType() == JSGFToken::TERMINAL ||
      current.getTokenType() == JSGFToken::QUOTED_TOKEN) {

    // store corresponding vertex index of the token into the start list
    //
    curr_vert_index = current.vertex_index_d;
    start_a.concat(current);
    
    // determining if next token is "+" or "*" 
    //
    if (rule_final_a.length() != 0) {
      op_token = rule_final_a.peek();
      if (op_token->operator_d(0).eq(L"+") ||
	  op_token->operator_d(0).eq(L"*" )) {
	rule_final_a.remove(&dummy);
	current.is_head_group_d = true;
      }
    }    
  }// end if (current.getTokenType() == 5 || current.getTokenType() == 7) 
 
  
  // loop through all tokens until meeting a grouping unit or the end
  //
  while (true) {

    JSGFToken*  op_token1;
    Long next_vert_index;

    if(rule_final_a.length() == 0)
      break;

    if (is_alter) {
      
      // determining if next token is "]" or ")" or ";" 
      //
      op_token1 = rule_final_a.peek();
      if (op_token1->operator_d(0).eq(L"]") ||
	  op_token1->operator_d(0).eq(L")")) {
	break;
      }
    }

    // get the next token
    //
    rule_final_a.remove(&next);
    if (next.operator_d(0).eq(L"]") ||
	next.operator_d(0).eq(L")")) {
      break;
    }
        
    // if the next token is a terminal or quoted token for sequence
    //
    if (next.getTokenType() == JSGFToken::TERMINAL ||
	next.getTokenType() == JSGFToken::QUOTED_TOKEN) {

      // initialize is_optional = false;
      //
      boolean is_optional = false;
      
      // get weight
      //
      boolean epsilon = true;
      float weight;
      if (next.weighted_terminal_d) {
	epsilon = false;
	weight = next.weight_d;
      }

      JSGFToken* op_token2 = (JSGFToken*)NULL;
      
      // determining if next token is "+" or "*" 
      //
      if (rule_final_a.length() != 0) {
	op_token2 = rule_final_a.peek();
	if (op_token2->operator_d(0).eq(L"+") ||
	    op_token2->operator_d(0).eq(L"*" )) {
	  rule_final_a.remove(&dummy);  
	}
	
	// determing if there exists optional_group token in the start_a
	//
	for(int j = 0; j < start_a.length(); j++) {
	  if(start_a(j).is_head_group_d) {
	    is_optional = true;
	    if (!op_token2->operator_d(0).eq(L"*")) {
	      start_a(j).is_head_group_d = false;
	    }
	  } 
	}// end for loop (int j =0)	
      }
      else {
	
	// determing if there exists optional_group token in the start_a
	//
	for(int j = 0; j < start_a.length(); j++) {
	  if(start_a(j).is_head_group_d) {
	    is_optional = true;
	    start_a(j).is_head_group_d = false;
	  } 
	}// end for loop (int j =0)
      }

      // add the vertex_index into start_a list if its parent is optional
      //
      if (is_optional) {
	start_a.concat(next);
	is_optional = false;
      }
      
      if ((op_token2 != (JSGFToken*)NULL) &&
	  (op_token2->operator_d(0).eq(L"*"))) {
	end_a.concat(next);
      }
      else {
	if(end_a.length() != 0) {
	  end_a.clear(Integral::RELEASE);
	}	
	end_a.concat(next);
      }
    }

    // if the next token is ( leading a grouping unit
    // recursively process the grouped rule expansion
    //
    else if (next.operator_d(0).eq(L"(")) {
      
      Vector<JSGFToken> sub_start;
      Vector<JSGFToken> sub_end;
      
      // get weights for group tokens
      //........................
      
      searchStartEnd(sub_start, sub_end, false, rule_final_a);
      
      JSGFToken* op_token2 = (JSGFToken*)NULL;
      boolean is_optional = false;
	
      // determining if next token is "+" or "*" 
      //
      if (rule_final_a.length() != 0) {
	op_token2 = rule_final_a.peek();
	if (op_token2->operator_d(0).eq(L"+") ||
	    op_token2->operator_d(0).eq(L"*" )) {

	  
	  if (op_token2->operator_d(0).eq(L"*")) {
	    
	    // setting optional_group_flag in the sub_start
	    //
	    for(int j = 0; j < sub_start.length(); j++) {
	      sub_start(j).is_head_group_d = true;
	    }
	  } //end   if (op_token2->operator_d(0).eq(L"*")) {
	  rule_final_a.remove(&dummy);
	}
      }
            
      // determing if there exists optional_group token in the start_a
      //
      for(int j = 0; j < start_a.length(); j++) {
	if(start_a(j).is_head_group_d) {	  
	    is_optional = true;
	    break;
	} 
      }

      boolean is_optional_substart = false;
      
      // determing if there exists optional_group token in the sub_start
      //
      for(int j = 0; j < sub_start.length(); j++) {
	if(sub_start(j).is_head_group_d) {
	   is_optional_substart = true;
	  if(!is_optional) {
	    sub_start(j).is_head_group_d = false;
	  }
	}
      }

      if(is_optional == true && is_optional_substart == false) {
	for(int j = 0; j < start_a.length(); j++) {
	  if(start_a(j).is_head_group_d) 	  
	       start_a(j).is_head_group_d = false;
	}
      }
      
      for(int j = 0; j < sub_start.length(); j++) {
	
	// get corresponding vertex_index of group tokens
	//
	JSGFToken child_token = sub_start(j);
	
	// add the vertex_index into start_a list if its parent is optional
	//
	if (is_optional) {
	  start_a.concat(child_token);
	}	
      } // end for loop(j=0)

      is_optional = false;
      if(sub_end.length() != 0) {
	if ( is_optional_substart) {
	  for(int i = 0; i < sub_end.length(); i++) {
	    end_a.concat(sub_end(i));
	  }
	}
	else {
	  end_a.clear(Integral::RELEASE);
	  for(int i = 0; i < sub_end.length(); i++) {
	    end_a.concat(sub_end(i));
	  }	
	}
      }
      else {
	end_a.clear(Integral::RELEASE);
      }
    } // end if(next.operator_d(0).eq(L"("))

    // if the next token is [ leading a optional grouping unit
    // recursively process the optional grouped rule expansion
    //
    else if (next.operator_d(0).eq(L"[")) {
      
      Vector<JSGFToken> sub_start;
      Vector<JSGFToken> sub_end;

      // get weights for group tokens
      //......
      //      
      searchStartEnd(sub_start, sub_end, false, rule_final_a);

      // set is_head_group_d = true for each token of sub_start 
      //
      for(int j = 0; j < sub_start.length(); j++) {
	sub_start(j).is_head_group_d = true;
      }
      
      JSGFToken* op_token2 = (JSGFToken*)NULL;
      
      // determining if next token is "+" or "*" 
      //
      if (rule_final_a.length() != 0 && sub_end.length() != 0) {
	op_token2 = rule_final_a.peek();
	if (op_token2->operator_d(0).eq(L"+") ||
	    op_token2->operator_d(0).eq(L"*" )) {
	  rule_final_a.remove(&dummy);
	}
      }

      boolean is_optional = false;
      
      // determing if there exists optional_group token in the start_a
      //
      for(int j = 0; j < start_a.length(); j++) {
	if(start_a(j).is_head_group_d) {	  
	    is_optional = true;
	    break;
	} 
      }

      boolean is_optional_substart = false;
      
      // determing if there exists optional_group token in the sub_start
      //
      for(int j = 0; j < sub_start.length(); j++) {
	if(sub_start(j).is_head_group_d) {
	   is_optional_substart = true;
	  if(!is_optional) {
	    sub_start(j).is_head_group_d = false;
	  }
	}
      }
      
      for(int j = 0; j < sub_start.length(); j++) {
	
	// get corresponding vertex_index of group tokens
	//
	JSGFToken child_token = sub_end(j);
	
	// add the vertex_index into start_a list if its parent is optional
	//
	if (is_optional) {
	  start_a.concat(child_token);	
	}
      } // end for loop(j=0)

      is_optional = false;
      for(int i = 0; i < sub_end.length(); i++) {
	  end_a.concat(sub_end(i));
      }
    } // end if(next.operator_d(0).eq(L"["))
    
    // if the next is a recursive grammar
    // 
    else if (next.operator_d(0).eq(L"@@")) {

      // do nothing
      //
    }
    
    // if the next is vertical bar | for alternatives
    //
    else if (next.operator_d(0).eq(L"|")) {
      
      Vector<JSGFToken> sub_start;
      Vector<JSGFToken> sub_end;
      boolean is_optional = false;
      
      // set optional = false
      //
      if (is_optional) {
	is_optional = false;
      }
      
      // get weights for group tokens
      //........................

      searchStartEnd(sub_start, sub_end, true, rule_final_a);

      for(int j = 0; j < sub_start.length(); j++) {
	
	// get corresponding vertex_index of group tokens
	//
	JSGFToken child_token = sub_start(j);	
	start_a.concat(child_token);	
      } // end for loop(j=0)

      for(int i = 0; i < sub_end.length(); i++) {
	end_a.concat(sub_end(i));
      }
    } // endif (next.operator_d(0).eq(L"|"))
  } // end of the while loop
  
  // exit gracefully
  //
  return true;
}

// method: findArcIndex
//
// arguments:long first_index_a: (input) parent of arc
//           long second_index_a: (input) child of arc
//
// return: a boolean value indicating status
//
// This method examine if the graph arc has been connected 
//boolean JSGFParser::
boolean JSGFParser::findArcIndex(long first_index_a, long second_index_a) {

  for ( long i=0; i < arc_index_d.length(); i++) {
    
    Long t_1(first_index_a);
    Long t_2(second_index_a);
    if(t_1.eq(arc_index_d(i).first()) && t_2.eq(arc_index_d(i).second()))
      return true;
  }

  // exit gracefully
  //
  return false;
  
}




















