/*---------------------------------------------------------------------------
File:         		        RegtoFSA.java
Package:                        JFLAP Version 3.0
Author:			        Eric Gramond 
                                
Description of Contents:	Contains class regtoFSA.
				
--------------------------------------------------------------------------*/

/* 
 * Susan H. Rodger, Magda Procopiuc, Octavian Procopiuc, Eric Gramond
 * Computer Science Department
 * Duke University
 * June 1998
 * Supported by National Science Foundation DUE-9596002 and DUE-9555084.
 *
 * Copyright (c) 1998
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the author.  The name of the author may not be used to
 * endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

package flap;

import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.image.*;
import java.awt.event.*;


/** 
 * this class converts a regular grammar into an FSA
 */ 

public class RegtoFSA {

    /**
     * checks if the grammar can be turned into an FSA. throws exceptions if not.
     */
  public static void checkGrammar(Grammar g) throws BadInputException{
    
    Enumeration e, e2, e3;
    Rule ru;
    GrammarRightHandToken gt;
    int line = 1;
    int numvars;
    
    for( e = g.getRules().elements(); e.hasMoreElements(); line++)
    {      
      ru = (Rule) e.nextElement();

      numvars = 0;
      //check for more than one variable
      for(e3 = ru.getRightHand().elements(); e3.hasMoreElements(); )
      {
         gt = (GrammarRightHandToken) e3.nextElement();
         if(gt instanceof Variable)
            ++numvars; 
      }

      if(numvars > 1)
      {
         throw new BadInputException("On line " + line + 
	     ":\nRight linear grammars can have only one\n" + 
             "Variable on the right hand side.");
      }

      //check for terminal then variable
      for(e2 = ru.getRightHand().elements(); e2.hasMoreElements(); )
      {
        gt = (GrammarRightHandToken) e2.nextElement();
        if( !(gt instanceof Lambda) && !(gt instanceof Terminal) && 
            e2.hasMoreElements()) 
        {
          throw new BadInputException("On line " + line + 
	     ":\nIf the right hand side of a Right linear grammar\n" + 
	     "contains a variable, it must be the rightmost symbol.");
        }
      }
    } 
  }
  

    /**
     * does all the conversion work after the check
     */
  public static void regtoFSA(Grammar g, Desktop d)
  {

    Vector list = g.findAllVariables();
    State aState;
    Enumeration e;
    Variable grt;
    for(e = list.elements(); e.hasMoreElements(); )
    {
      grt = (Variable) e.nextElement();
      aState = d.addState(0,0);
      aState.label = grt.getContents();
      if(grt.getContents().equals(g.getStart().getContents()))
        d.initialState = aState;
    }

    Vector rules = g.getRules();
    Rule aRule;
    State StateFrom, StateTo = null;
    String label = null;
    Transition trans;
    int rightSize;
    for(e = rules.elements(); e.hasMoreElements(); )
    {
      aRule = (Rule) e.nextElement();
      rightSize = aRule.getRightHand().size();
      StateFrom = findState(aRule.getLeftHand().getContents(), list, d.theStates);
      
      if(rightSize == 0)
      {
        StateTo = findFinal(StateFrom, d);
        label = " ";
      }
      else if(aRule.getRightHand().elementAt(rightSize-1) instanceof Variable)
      {
        StateTo =findState(((Variable)aRule.getRightHand().elementAt(rightSize-1)).getContents(),list, d.theStates);
        label = makeLabel(aRule);
      }
      else
      {
        StateTo = findFinal(StateFrom, d);
        label = makeLabel(aRule);
      }
      trans = d.addTransition(StateFrom, StateTo);
      trans.label = new String(label);
    }

  }
  

  private static String makeLabel(Rule theRule)
  {

  String label = " ";
  GrammarRightHandToken grt;

  for(Enumeration e= theRule.getRightHand().elements(); e.hasMoreElements(); ) {
    grt = (GrammarRightHandToken) e.nextElement();
    if(grt instanceof Variable)
      break;
    if(! (grt instanceof Terminal))
      continue;
    label += grt.getContents();    
  }

  return label;
  }


  private static State findState(String name, Vector grammarList, Vector stateList) {

    for(int i = 0; i < grammarList.size(); i++) {
      if(((Variable)grammarList.elementAt(i)).getContents().equals(name))
        return (State) stateList.elementAt(i);
    }
    return null;
  }

  private static State findFinal(State stateFrom, Desktop d) {

    Transition t;
    for(Enumeration e = d.theTransitions.elements(); e.hasMoreElements(); ) {
      t = (Transition) e.nextElement();
      if(t.from == stateFrom && t.to.isFinal)
        return t.to;
    }
    State result = d.addState(0,0);
    result.isFinal = true;
    return result;
  }

}
