// file: JSGFParser.h
//
// make sure definitions are only made once
//
#ifndef ISIP_JSGF_PARSER
#define ISIP_JSGF_PARSER

// isip include files
//
#ifndef ISIP_VECTOR
#include <Vector.h>
#endif

#ifndef ISIP_PAIR
#include <Pair.h>
#endif

#ifndef ISIP_QUEUE
#include <Queue.h>
#endif

#ifndef ISIP_STACK
#include <Stack.h>
#endif

#ifndef ISIP_DI_GRAPH
#include <DiGraph.h>
#endif

#ifndef ISIP_JSGF_TOKEN
#include <JSGFToken.h>
#endif

// JSGFParser: a class used to parse a JSGF grammar and then convert it to
// a directed graph (DiGraph format) which is the ISIP internal grammar
// representation
//
class JSGFParser {
  
  //-------------------------------------------------------------
  //
  // public constants
  //
  //-------------------------------------------------------------
public:

  //define the class name
  //
  static const String CLASS_NAME;

  // constants: i/o related constants
  //
  static const String DEF_GRAPH_START;
  static const String DEF_GRAPH_TERM;
  static const String DEF_GRAMMAR_NAME;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = (long)50100;
  
  //-------------------------------------------------------------
  //
  // protected data
  //
  //-------------------------------------------------------------
public:
  
  // string to store the whole source JSGF grammar
  //
  String expression_d;

  // array of queues to contain all tokens of the expressions
  //
  Vector<JSGFToken> token_vect_d;

  // index to keep track of the position of the current token
  // in the above token vector
  //
  long token_index_d;  

  // a flag to check if grouping parentheses are paired correctly in a rule
  // correct if the flag is zero after the check
  //
  long grouping_match_d;

  // a flag to check if optional grouping brackets are paired correctly
  // in a rule. correct if the flag is zero after the check
  //
  long op_grouping_match_d;
  
  // a table to store all public rule definitions by pairing
  // rulenames and their corrsponding rule expansions
  //
  Vector<Pair<JSGFToken, Vector<JSGFToken> > > public_rule_table_d;
  
  // a table to store all private rule definitions by pairing
  // rulenames and their corrsponding rule expansions
  //
  Vector<Pair<JSGFToken, Vector<JSGFToken> > > private_rule_table_d;

  // a table to store all recursive grammar by pairing
  // rulenames and their corrsponding terminal tokens 
  //
  Vector<Pair<String, Vector<JSGFToken> > > recursive_grammar_d;
  
  // a table to store vertex index for each graph arc
  //
  Vector<Pair<Long, Long > > arc_index_d;

  // a vector to store all rulenames that has been processed
  // since starting running the replaceRuleReference method
  // It is used to check out unique terminal symbols
  //
  Vector<JSGFToken> processed_rules_d;
  
  // token queue for final processing in graph drawing section
  //
  Queue<JSGFToken> final_d;

   // graph to contain the converted JSGF grammar
  //
  DiGraph<String> graph_d;

  // grammar name
  //
  String grammar_name_d;

  // a list of all terminal symbols in the graph
  //
  Vector<String> symbol_list_d;
  
  // a list of GraphVertex in the graph
  //
  GraphVertex<String>* vertex_list_d[500];
  
  // index of vertex in the graph
  //
  long vertex_list_index_d;
  
  // ISIP default starting and terminial points for DiGraph
  //
  String graph_start_d;
  String graph_term_d;

  // static memory manager
  //
  static MemoryManager mgr_d;

  //------------------------------------------------------------------------
  //
  // required public methods
  //
  //-----------------------------------------------------------------------
public:

  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }

  // methopd: diagnose
  //
  static boolean diagnose(Integral::DEBUG level_a);

  // methopd: debug
  //
  boolean debug(const unichar* msg_a) const;
  
  // method: destructor
  //
  ~JSGFParser() {};

  // method: constructor
  //
  JSGFParser();
   
  // method: assign
  //
  boolean assign(const JSGFParser& arg_a);

  // method: operator=
  //
  JSGFParser& operator=(const JSGFParser& arg_a) {
    assign(arg_a);
    return *this;
  }
  
  // equality methods
  //
  boolean eq(const JSGFParser& arg_a) const;

  // method: read
  //
  boolean read(Sof& sof, long tag, const String& cname = CLASS_NAME) {
    return Error::handle(name(), L"read", Error::NOT_IMPLEM, __FILE__,
			 __LINE__);
  }

  // method: write
  //
  boolean write(Sof& sof, long tag, const String& cname = CLASS_NAME) const {
    return Error::handle(name(), L"write", Error::NOT_IMPLEM, __FILE__,
			 __LINE__);
  }
  
  // method: clear
  //
  boolean clear(Integral::CMODE ctype_a);

  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }
  
  //-------------------------------------------------------------
  //
  // class-specified public methods
  //
  //-------------------------------------------------------------
public:

  // method: setExpression
  //
  boolean setExpression(String& expression_a);
  
  // method: parserJSGF
  //
  boolean parseJSGF(const String& graph_start_a,
		    const String& graph_term_a);
  
  // method: parserJSGF
  //
  boolean parseJSGF(){
    return parseJSGF(L"", L"");
  }
  
  // method: getGraph
  //
  DiGraph<String> getGraph() {
    return graph_d;
  }

  // method: getSymbolList
  //
  Vector<String> getSymbolList() {
    return symbol_list_d;
  }

  // method: getGrammarName
  //
  String getGrammarName() {
    return grammar_name_d;
  }

  // method: getPublicRuleNames
  //
  boolean getPublicRuleNames(Vector<JSGFToken>& public_tokens_a);

  // method: getPublicRuleNames
  //
  boolean getPublicRuleNames(Vector<String>& public_tokens_a);
 
  // method: getTokenVector
  //
  Vector<JSGFToken> getTokenVector() {
    return token_vect_d;
  }



  //-------------------------------------------------------------
  //
  // private methods
  //  
  //-------------------------------------------------------------
private:

  // method: getToken
  //
  boolean getToken();

  // method: parseGrammar
  //
  boolean parseGrammar();

  // method: parseRuleDefinition
  //
  boolean parseRuleDefinition();

  // method: parseRuleExpansion
  //
  boolean parseRuleExpansion();

  // method: parseUnit
  //
  boolean parseUnit();
  
  // method: parseGrouping
  //
  boolean parseGrouping();

  // method: parseOptionalGrouping
  //
  boolean parseOptionalGrouping();

  // method: setRuleTables
  //
  boolean setRuleTables();

  // method: ruleNotDefined
  //
  boolean ruleNotDefined(JSGFToken& rulename_a);

  // method: replaceRuleExpansion
  //
  boolean replaceRuleReference(JSGFToken& rulename_a,
			       Stack<String>& replaced_rules_a);

  // method: replaceRecursionRuleExpansion
  //
  boolean replaceRecursionRuleReference(String& rulename_a,
					Stack<String> replaced_rules_a,
					Queue<JSGFToken>& rule_final_a);
 		
  // method: resolveReference
  //
  boolean resolveReference(String& rulename_a,
			   Vector<JSGFToken>& rule_exp_a);
  // method: setVertexIndex
  //
  boolean setVertexIndex(JSGFToken& token_a);
  
  // method: drawGraph
  //
  boolean drawGraph();

  // method: drawUnit
  //
  boolean drawUnit(Vector<JSGFToken>& start_a,
		   Vector<JSGFToken>& end_a,
		   boolean is_alter_a);
  
  // method: searchStartEnd
  //
  boolean searchStartEnd(Vector<JSGFToken>& start_a,
		      Vector<JSGFToken>& end_a,
		      boolean is_alter, Queue<JSGFToken>& rule_final_a);
  // method: findArcIndex
  //
  boolean findArcIndex(long first_index_a, long second_index_a);

};

// end of include file
//
#endif










