// file: gc_net_0.cc
// 

// isip include files
//
#include "grammar_compiler.h"
#include "grammar_compiler_constants.h"

// method: build_net_cc()
//  
// arguments:
//  char_1** symbols: (input)the array of strings
//  int_4& index: (output)the index to the current symbol 
//  Lattice_node* start: (input)the start node of the current scope
//                             defined by symbol like braces
//  Lattice_node* end: (input)the end node of the current scope
//  Lattice_node*& prev: (input/output) the previous lattice node
//  Lattice*& lattice: (output)the lattice
//  int_4& num_nodes: (output)number of lattice nodes
//  int_4& num_arcs: (output)number of arcs in the lattice
//  logical_1 allprob_flag: (output)flag indicating probabilistic grammar
//
// return: a logical_1 indicating status
//
// this method parses the grammar string and build a lattice
//
logical_1 build_net_cc(char_1** symbols_a, int_4& index_a,
		       Lattice_node* start_a, Lattice_node* end_a,
		       Lattice_node*& prev_a, Lattice*& lattice_a,
		       int_4& num_nodes_a, int_4& num_arcs_a,
		       logical_1& allprob_flag_a) {
  
  // define local constants
  //
  Lattice_node* latn = (Lattice_node*)NULL;
  logical_1 add_flag = ISIP_TRUE;
  logical_1 allprob_flag = ISIP_FALSE;
  logical_1 noneprob_flag = ISIP_TRUE;
  logical_1 noword_flag = ISIP_FALSE;
  end_a = (Lattice_node*)NULL;
  float_8 lmscore = (float_8)0;
  float_8 acscore = (float_8)0;
  char_1* symbol = symbols_a[index_a];
  int_4 index_next = index_a + 1;
  char_1* symbol_next = symbols_a[index_next];
  
  // parse the string if it's not empty
  //
  while (symbol != (char_1*)NULL) {

    // ordinary parenthesis
    //
    if (strcmp((char*)symbol, BRACE_START) == 0) {
      
      // change the start scope
      //
      index_a++;
      index_next = index_a + 1;
      build_net_cc(symbols_a, index_a, prev_a, end_a, prev_a, lattice_a,
		   num_nodes_a, num_arcs_a, allprob_flag_a);
    }
    
    else if (strcmp((char*)symbol, BRACE_CLOSE) == 0) {
      
      // change the end scope
      //
      if (end_a == (Lattice_node*)NULL) {
	
	end_a = prev_a;
	
	// not create a new NULL node if the previous one is a NULL node
	//
	if (strcmp((char*)prev_a->get_word_cc()->get_name_cc(), WRD_NULL)
	    == 0) {
	  end_a = prev_a ;
	  add_flag = ISIP_FALSE;
	}
	
	// create the end scope NULL node
	//
	else {
	  end_a = create_latnode_cc((char_1*)WRD_NULL, num_nodes_a,
				    lattice_a);
	}
      }
      
      if (add_flag == ISIP_TRUE) {
	
	// no probability associated
	//
	lmscore = (float_8)0;
	
	end_a->add_prev_node_cc(prev_a);
	prev_a->add_next_node_cc(end_a);
	prev_a->add_lm_score_cc(lmscore);
	prev_a->add_ac_score_cc(acscore);
	num_arcs_a++;
	prev_a = end_a;
      }
      
      // exit gracefully
      //
      return ISIP_TRUE;
    } 
    
    // one or more repetition
    //
    else if (strcmp((char*)symbol, ONE_OR_MORE_REPEAT_START) == 0) {
      
      // create the start scope NULL node
      //
      latn = create_latnode_cc((char_1*)WRD_NULL, num_nodes_a, lattice_a);
      latn->add_prev_node_cc(prev_a);
      prev_a->add_next_node_cc(latn);
      prev_a->add_lm_score_cc(lmscore);
      prev_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      // parse the following string
      //
      prev_a = latn;
      index_a++;
      index_next = index_a + 1;
      build_net_cc(symbols_a, index_a, latn, end_a, prev_a, lattice_a,
		   num_nodes_a, num_arcs_a, allprob_flag_a);
    } 
    
    else if (strcmp((char*)symbol, ONE_OR_MORE_REPEAT_CLOSE) == 0) {
      
      // create the end scope NULL node
      //
      if (end_a == (Lattice_node*)NULL) {
	end_a = create_latnode_cc((char_1*)WRD_NULL, num_nodes_a, lattice_a);
      }
      end_a->add_prev_node_cc(prev_a);
      prev_a->add_next_node_cc(end_a);
      prev_a->add_lm_score_cc((float_8)0);
      prev_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      // make an arc from the end scope to the start scope
      //
      start_a->add_prev_node_cc(end_a);
      end_a->add_next_node_cc(start_a);
      end_a->add_lm_score_cc((float_8)0);
      end_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      prev_a = end_a;
      
      // exit gracefully
      //
      return ISIP_TRUE;
    } 
    
    // zero or more repetition
    //
    else if (strcmp((char*)symbol, ZERO_OR_MORE_REPEAT_START) == 0) {
      
      // make the start scope NULL node
      //
      latn = create_latnode_cc((char_1*)WRD_NULL, num_nodes_a, lattice_a);
      latn->add_prev_node_cc(prev_a);
      prev_a->add_next_node_cc(latn);
      prev_a->add_lm_score_cc(lmscore);
      prev_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      // parse the following string
      //
      prev_a = latn;
      index_a++;
      index_next = index_a + 1;
      build_net_cc(symbols_a, index_a, latn, end_a, prev_a, lattice_a,
		   num_nodes_a, num_arcs_a, allprob_flag_a);
    }
    
    else if (strcmp((char*)symbol, ZERO_OR_MORE_REPEAT_CLOSE) == 0) {
      
      //  create the end scope NULL node
      //
      if (end_a == (Lattice_node*)NULL) {
	end_a = create_latnode_cc((char_1*)WRD_NULL, num_nodes_a, lattice_a);
      }
      end_a->add_prev_node_cc(prev_a);
      prev_a->add_next_node_cc(end_a);
      prev_a->add_lm_score_cc(lmscore);
      prev_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      // make arcs between the end scope and the start scope
      //
      start_a->add_prev_node_cc(end_a);
      end_a->add_next_node_cc(start_a);
      end_a->add_lm_score_cc(lmscore);
      end_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      end_a->add_prev_node_cc(start_a);
      start_a->add_next_node_cc(end_a);
      start_a->add_lm_score_cc(lmscore);
      start_a->add_ac_score_cc(acscore);
      num_arcs_a++;      
      
      prev_a = end_a;
      
      // exit gracefully
      //
      return ISIP_TRUE;
    }
    
    // zero or more repetition
    //
    else if (strcmp((char*)symbol, OPTIONAL_START) == 0) {
      
      // parse the following string
      //
      index_a++;
      index_next = index_a + 1;
      build_net_cc(symbols_a, index_a, prev_a, end_a, prev_a, lattice_a,
		   num_nodes_a, num_arcs_a, allprob_flag_a);
    }
    
    else if (strcmp((char*)symbol, OPTIONAL_CLOSE) == 0) {
      
      // create the end scope NULL node
      //
      if (end_a == (Lattice_node*)NULL) {
	end_a = create_latnode_cc((char_1*)WRD_NULL, num_nodes_a, lattice_a);
      }
      end_a->add_prev_node_cc(prev_a);
      prev_a->add_next_node_cc(end_a);

      // no score associated with this NULL since its probabilty is one
      //
      prev_a->add_lm_score_cc((float_8)0);
      prev_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      // make arc from the start scope to the end scope
      //
      end_a->add_prev_node_cc(start_a);
      start_a->add_next_node_cc(end_a);
      
      if (noneprob_flag == ISIP_TRUE) {
      start_a->add_lm_score_cc((float_8)0);
      }
      
      else {
	start_a->add_lm_score_cc((float_8)0);
      }
      
      start_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      
      prev_a = end_a;
      
      // exit gracefully
      //
      return ISIP_TRUE;
    }
    
    // alternative
    //
    else if (strcmp((char*)symbol, ALTERNATIVE_SYMBOL) == 0) { 
      
      // move the string buffer position
      //
      index_a++;
      index_next = index_a + 1;
      symbol = symbols_a[index_a];
      symbol_next = symbols_a[index_next];
      
      // read the probability
      //
      symbol_next = symbols_a[++index_next];
      lmscore = (float_8)atof((char*)symbol_next);

      // form the end node
      //
      if ((lmscore != (float_8)1 && allprob_flag == ISIP_TRUE) ||
	  noneprob_flag == ISIP_TRUE ||
	  (strcmp((char*)symbol, BRACE_START) == 0)) {
	
	// change the end scope
	//
	if (end_a == (Lattice_node*)NULL) {  
	  end_a = create_latnode_cc((char_1*)WRD_NULL, num_nodes_a,
				    lattice_a);
	}
	
	// no probability associated
	//
	lmscore = (float_8)0;
	
	end_a->add_prev_node_cc(prev_a);
	prev_a->add_next_node_cc(end_a);
	prev_a->add_lm_score_cc(lmscore);
	prev_a->add_ac_score_cc(acscore);
	num_arcs_a++;
	
	// go to start scope 
	//
	prev_a = start_a;
      }
      
      // move back the string buffer position
      //
      index_a--;
      index_next = index_a - 2;
      symbol = symbols_a[index_a];
      symbol_next = symbols_a[index_next]; 
    }
    
    else if (strcmp((char*)symbol, (char*)EMPTY) == 0) {
      
      // skip
      //
    }

    // start
    //
    else if (strcmp((char*)symbol, (char*)SENTSTART) == 0) {

      // create a lattice node
      //
      latn = create_latnode_cc(symbol, num_nodes_a, lattice_a);
      
      // set up the arc connections
      //
      latn->add_prev_node_cc(prev_a);
      prev_a->add_next_node_cc(latn);
      prev_a->add_lm_score_cc(lmscore);
      prev_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      prev_a = latn;
    }

    // end
    //
    else if (strcmp((char*)symbol, (char*)SENTEND) == 0) {
      
      // create a lattice node
      //
      latn = create_latnode_cc(symbol, num_nodes_a, lattice_a);
      
      // no probability associated
      //
      if (noneprob_flag == ISIP_TRUE) {
	lmscore = (float_8)0;
      }
      
      else {
	lmscore = (float_8)0;
      }
      
      // set up the arc connections
      //
      latn->add_prev_node_cc(prev_a);
      prev_a->add_next_node_cc(latn);
      prev_a->add_lm_score_cc(lmscore);
      prev_a->add_ac_score_cc(acscore);
      num_arcs_a++;
      prev_a = latn;
    }
    
    // a word
    //
    else {

      // probability
      //
      if (strcmp((char*)symbol_next, (char*)PROBABILITY_SYMBOL) == 0) {
	// all probability required
	//
	allprob_flag = ISIP_TRUE;
	allprob_flag_a = allprob_flag;
	
	// read the probability
	//
	symbol_next = symbols_a[++index_next];
	lmscore = (float_8)atof((char*)symbol_next);
	index_a += 2;
	
	// error if case WORD~
	//
	if ((strcmp((char*)symbol_next, (char*)ALTERNATIVE_SYMBOL) == 0) ||
	    (strcmp((char*)symbol_next, (char*)BRACE_CLOSE) == 0) ||
	    (strcmp((char*)symbol_next, (char*)ONE_OR_MORE_REPEAT_CLOSE) == 0)
	    || (strcmp((char*)symbol_next, (char*)ZERO_OR_MORE_REPEAT_CLOSE)
		== 0) ||
	    (strcmp((char*)symbol_next, (char*)OPTIONAL_CLOSE) == 0)) {
	  printf("Error, Probability missing in the grammar\n");
	  exit(ISIP_PROTO_ERROR);
	}
	
	// reset flag for next word
	//
	noword_flag = ISIP_FALSE;
	
	// no arc for word with zero probability
	//
	if (!lmscore) {
	  noword_flag = ISIP_TRUE;
	  index_a++;
	}

	// error if probabilty is  < 0 or > 1
	//
	if (lmscore < (float_8)0 || lmscore > (float_8)1) {
	  printf("error, probabilities should be specified between 0 and 1\n");
	  exit(ISIP_PROTO_ERROR);
	}
      } // end of if PROBABILITY_SYMBOL==0
      
      // no probability
      //
      else if (noword_flag == ISIP_FALSE) {
	
	// no probability required
	//
	noneprob_flag = ISIP_TRUE;

	// probability is one
	//
	lmscore = (float_8)0;

	// probability missing, fill in zero
	// this will be calculated during loop back
	//
	if (allprob_flag == ISIP_TRUE) {
	  lmscore = (float_8)0; 
	}
	
      }  //end of else if noword_flad==ISIP_FALSE

      if (noword_flag == ISIP_FALSE) {
	
	// create a lattice node
	//
	latn = create_latnode_cc(symbol, num_nodes_a, lattice_a);
	
	// set up the arc connections
	//
	latn->add_prev_node_cc(prev_a);
	prev_a->add_next_node_cc(latn);
	prev_a->add_lm_score_cc(lmscore);
	prev_a->add_ac_score_cc(acscore);
	num_arcs_a++;
	prev_a = latn;
      } // end of if (noword_flag==ISIP_FALSE)
      
    } //end of else
    
    // move the string buffer position
    //
    lmscore = (float_8)0;
    index_a++;
    index_next = index_a + 1;
    symbol = symbols_a[index_a];
    symbol_next = symbols_a[index_next];
    
  } // end symbol != NULL while loop 
  
  // exit gracefully
  //
  return ISIP_TRUE;
}
