/*
   Tamot --- Task Modelling Editor
   Copyright (C) 2000 Commonwealth Scientific and Industrial Research Organisation
   (CSIRO), Australia. All rights reserved. 

   The Software, owned by CSIRO Australia, has been developed by the CSIRO 
   Intelligent Interactive Technology group. 
   For more information, please see http://www.cmis.csiro.au/iit/.

   The Software is a beta-test version for internal research and evaluation purposes 
   by the Licensee. The Software is still at a development stage. 
   It has not undergone complete testing and may have inherent errors,
   bugs or deficiencies that can affect the operation of the Software. 

   We encourage your feedback and suggestions. Any bugs / suggestions found please email to
   Shijian.Lu@cmis.csiro.au and Thomas.Lo@cmis.csiro.au. 

   After you have signed the Beta-Test Software License Agreement with the CSIRO,
   CSIRO grants you a non-exclusive, non-transferable license to use it only for your 
   personal, non-commercial and lawful end use. Implied licenses are negated. 

   Warranty Disclaimer : 

   CSIRO supplies the Software on an "as is" basis and makes no warranties that use of
   the Software by the Licensee will not infringe any third party’s 
   Intellectual Property Rights nor that the Software will be of merchantable quality,
   or suitable for a particular purpose. CSIRO excludes all terms, conditions and
   warranties implied by custom, the general law or statute in relation to the
   Software.
*/

//Source file: D:/Projects/Isolde/parser/Grammar.java

package parser.FSParser;

import java.util.StringTokenizer;
import java.util.Vector;
import java.lang.ClassLoader;
import java.io.*;

import domainModel.DmRelation;

public class Grammar 
{
  private Vector states;         // list of states in the grammar
  private Vector transitions;    // list of transitions in the grammar
  private int startState;        // index of the start state of the grammar
  private int currentState;      // index of the current state of the grammar
  private String currentConstituent; //name of the current constituent. brasser 2001-6-18
   
   
  public Grammar(String filename) 
  {
    states = new Vector();
    transitions = new Vector();
    load(filename);
    initialize();
  }
   
  /**
    Sets the current state of the grammar to the start state.
    @roseuid 3959F8AA01B4
    */
  public void initialize() 
  {
    currentState = startState;
  }
   
  /**
    Returns true if the grammar is currently in a final state.
    @roseuid 3959F8B0004A
    */
  public boolean inTerminalState() 
  {
    return ((State)(states.elementAt(currentState))).terminal();
  }
   
  /**
    Loads the grammar from an ascii file
    @roseuid 3959FDC90119
    */
  public void load(String filename) 
  {
    Transition aTransition;  // a utility transition instance
    String inLine;           // utility string for input
    BufferedReader in;       // an input stream for the given file
    StringTokenizer st;      // a tokenizer for the input lines
    String currentOperation; // a temporary string for the operation name
    String fullFileName =    // the grammar filename within the system CLASSPATH
      ClassLoader.getSystemResource("parser/FSParser/" + filename).getFile();
    String constituentName, terminalStatus, constituentStatus;  // utility strings

    try {
      // Open the file (if it exists)
      in = new BufferedReader(new FileReader(fullFileName));

      // Build a grammar based on the file contents:
      // First, eat the beginning comments
      while (!in.readLine().startsWith("states:"));

      // Next, read/create the states
      for (;;) {
	inLine = in.readLine();
	if (inLine.equals("")) break;  // that's the end of the states
	if (!inLine.startsWith("#")) {  // skip the comment lines
	  st = new StringTokenizer(inLine);
	  //System.out.println("state: " + inLine);
	  constituentName = st.nextToken();
	  terminalStatus = st.nextToken();
	  constituentStatus = st.nextToken();
	  
	  states.add(new State(constituentName, 
			       (terminalStatus.equals("terminal") ? true : false),
			       (constituentStatus.equals("constituent") ? true : false)
			       ));
	  // Add the case roll name to the list of possible DM relations.
	  // actor/actee will be predefined, process/start will not be relations
	  // on the action, and everything else will be added as specified in
	  // the grammar file.
	  if (!constituentName.equals("process") && 
	      !constituentName.equals("start") && 
	      constituentStatus.equals("constituent")) 	  // We now only add relations for constituent states.  this is based on shijian's changes of 20-aug-2001. - kvlinden 29-aug-2001
	    DmRelation.getInstance().addActionRelation(constituentName);
	}}
      startState = 0;  // Assume that the start state is the first one

      // Now, eat the comments and blank lines up to the transitions.
      while (!in.readLine().startsWith("transitions:"));

      // Finally, read/create the transitions
      for (;;) {
	inLine = in.readLine();
	if ((inLine == null) || (inLine.equals(""))) break; // the end of the transitions
	if (!inLine.startsWith("#")) {  // skip the comment lines
	  // the transition itself
	  st = new StringTokenizer(inLine);
	  aTransition = new Transition(indexOf(st.nextToken()),   // the start state
				       indexOf(st.nextToken()),   // the stop state
				       st.nextToken());           // the guard
	  // the operations (a list of known operations matching the enum type in Transitions)
	  //    Added some new operations for the contextual type - kvlinden, 23jan2002
	  while (st.hasMoreTokens()) {
	    currentOperation = st.nextToken();
	    if (currentOperation.equals("START_EQ_WORKING"))
	      aTransition.addOperation(Transition.START_EQ_WORKING);
	    else if (currentOperation.equals("INCREMENT_CURRENT"))
	      aTransition.addOperation(Transition.INCREMENT_CURRENT);
	    else if (currentOperation.equals("PREPSTART_EQ_CURRENT"))
	      aTransition.addOperation(Transition.PREPSTART_EQ_CURRENT);
	    else if (currentOperation.equals("PREPSTART_EQ_WORKING"))
	      aTransition.addOperation(Transition.PREPSTART_EQ_WORKING);
	    else if (currentOperation.equals("DETSTART_EQ_CURRENT"))
	      aTransition.addOperation(Transition.DETSTART_EQ_CURRENT);
	    else if (currentOperation.equals("DETSTART_EQ_WORKING"))
	      aTransition.addOperation(Transition.DETSTART_EQ_WORKING);
	    else if (currentOperation.equals("START_EQ_CURRENT"))
	      aTransition.addOperation(Transition.START_EQ_CURRENT);
	    else if (currentOperation.equals("WORKING_EQ_START"))
	      aTransition.addOperation(Transition.WORKING_EQ_START);
	    else if (currentOperation.equals("WORKING_EQ_CURRENT"))
	      aTransition.addOperation(Transition.WORKING_EQ_CURRENT);
	    else if (currentOperation.equals("HEAD_EQ_CURRENT"))
	      aTransition.addOperation(Transition.HEAD_EQ_CURRENT);
	    else if (currentOperation.equals("END_EQ_CURRENT_MINUS_1"))
	      aTransition.addOperation(Transition.END_EQ_CURRENT_MINUS_1);
		else if (currentOperation.equals("ADD_TO_HEAD"))
		  aTransition.addOperation(Transition.ADD_TO_HEAD); 
		else if (currentOperation.equals("RESTART_PARSER"))
		  aTransition.addOperation(Transition.RESTART_PARSER); 
		else if (currentOperation.equals("SET_ROLE"))
		  aTransition.addOperation(Transition.SET_ROLE);   
	  }
	  transitions.add(aTransition);
	}}
      in.close();
    }
    catch (FileNotFoundException e) {
      System.err.println("file not found: " + fullFileName);
    } 
    catch (IOException e) {
      System.err.println("Problems reading file: " + fullFileName);
    }
  }

  // Utility function that returns the index of a state with the name stateName.
  private int indexOf(String stateName)
  {
    for (int i = 0; i < states.size(); i++)
      if (stateName.equals(((State)states.elementAt(i)).name()))
	return i;
    System.out.println("Warning (Grammar.java): No state exists for given name: " + stateName);
    return -1;
  }

  // Utility function that returns the name of a state with the index stateIndex.
  //     This one just calls name(), but it does error checking as well.
  private String nameOf(int stateIndex)
  {
    if ((stateIndex < states.size()) && (stateIndex >= 0))
      return ((State)(states.elementAt(stateIndex))).name();
    System.out.println("Warning: No state exists for given name: " + stateIndex);
    return "";
  }

  /**
    returns a vector of the names of the States that are designated as "official" 
    CNL constituents.
    @roseuid 395A0D8A0096
    */
  public Vector constituents() 
  {
    Vector constituentsList = new Vector();
    for (int i = 0; i < states.size(); i++){
      if (((State)(states.elementAt(i))).constituent())
	constituentsList.add(((State)(states.elementAt(i))).name());
	//shijian, 23-10-2001
	//System.out.println("state name: " + i+ " =" +
	//	((State)(states.elementAt(i))).name());
    }
    return constituentsList;
  }
   
  /**
    returns a vector of strings identifying the possible transitions, not counting UNKNOWN.
    @roseuid 395A196A00DE
    */
  public Vector possibleTransitions() 
  {
    Vector transitionList = new Vector();
    for (int i = 0; i < transitions.size(); i++)
      if (((Transition)(transitions.elementAt(i))).source() == currentState)
		transitionList.add(((Transition)(transitions.elementAt(i))).guard());
    return transitionList;
  }
   
  /**
    Moves the grammar to the state pointed to by the transition with guardName as its guard.
    Returns the operations associated with the transition that is followed so that the parser
    can execute them.
    @roseuid 395A1E94025B
    */
  public Vector transition(String guardName) 
  {
    for (int i = 0; i < transitions.size(); i++)
      if ((((Transition)(transitions.elementAt(i))).source() == currentState) && 
	  (((Transition)(transitions.elementAt(i))).guard().equals(guardName)))
	{
	  
	  currentState = ((Transition)(transitions.elementAt(i))).destination();
	  
	  //set the current constituent to the state if the state is a constituent
	  //brasser 2001-6-18
	  if (((State)(states.elementAt(currentState))).constituent())
	  	currentConstituent = ((State)(states.elementAt(currentState))).name();
	  
	  return ((Transition)(transitions.elementAt(i))).operations();
	}
    System.out.println("Warning: Invalid transition from state: " + nameOf(currentState)
		       + " using guard: " + guardName);
    return null;
  }
   
  public String getCurrentState()
  {
    return ((State)(states.elementAt(currentState))).name();
  }
  
  //brasser 2001-6-18
  public String getCurrentConstituent()
  {
  	//System.out.println("Constituent: " + currentConstituent);
	//System.out.println("State: " + currentState);
    return currentConstituent;
  }
  

}
