/*---------------------------------------------------------------------------
File:         			FSAToGrammar.java
Package:                        JFLAP Version 3.1
Author:			        Eric Gramond
Modified:			Ted Hung V3.1 7/18/99
                                
Description of Contents:	Contains class FSAToGrammar.
				
--------------------------------------------------------------------------*/

/* 
 * Susan H. Rodger, Magda Procopiuc, Octavian Procopiuc, Eric Gramond, Ted Hung
 * Computer Science Department
 * Duke University
 * August 1999
 * Supported by National Science Foundation DUE-9596002, DUE-9555084,
 *  and DUE-9752583
 *
 * Copyright (c) 1999
 * 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.awt.event.*;

/**
  * This is the class that handles converting an FSA to a grammar. The grammar will
  * be regular if there are no lambda transitions.
  */ 
public class FSAToGrammar extends ToGrammar
{

   private int curTransIndex;
   private Grammar answer;
   private boolean processed;

   final static String[] WARN_BUTTONS = {"Continue", "Cancel"};

   public FSAToGrammar(Desktop desk) throws BadInputException
   {
      super(desk);
      answer = new Grammar();
      answer.setStart(new Variable("S")); //new Variable(giveName(d.initialState)));

      //set up all the state transitions
      if(d.theStates.size() > 26)
	 throw new BadInputException("Too many states for\ngrammar conversion.");

      //warn if labels are going to be replaced
      boolean haslabels = false;
      for(Enumeration e = d.theStates.elements(); e.hasMoreElements(); )
      {
	 if(((State) e.nextElement()).label.length() > 0)
	 { 
	    haslabels = true;
	 }
      }
      if(haslabels)
      {
	 TextDialog dg = new TextDialog(
	    "\nWARNING: Converting to grammar" +
	    "\nwill replace all user defined" +
	    "\nstate labels.",
	    WARN_BUTTONS, "Convert To Grammar Warning");
	     
	 String pushed = dg.findResult();
	 if (pushed.equals("Cancel"))
	 {
	    throw new BadInputException("");
	 }
      }

      //replace the state labels
      char name = 'A';
      State aState;
      for(Enumeration e = d.theStates.elements(); e.hasMoreElements(); ) 
      {
	 aState = (State) e.nextElement();
	 if(aState == d.initialState)
	 {
	    aState.label = "S";
	 }
	 else
	 {
	    aState.label = name + "";
	    ++name;
	    if(name == 'S')
	       ++name;
	 }
	 d.setTransitions(aState, true);
      }

      d.selectedState = null;
      d.selectedTransition = null;

      d.showStateLabels = true;
      d.showStringLabel = true;

      curTransIndex = 0;
      processed = false;
   }
  
  public Grammar toGramm() throws BadInputException
  {
     if(processed)
	return answer;
     else
	processed = true;

     State aState;
     Vector subAnswer;
     Enumeration e2;
    
     for(Enumeration e = d.theStates.elements(); e.hasMoreElements(); )
     {
       aState = (State) e.nextElement();
       subAnswer = processState(aState);
       for(e2 = subAnswer.elements();  e2.hasMoreElements(); ) 
 	  answer.addRule((Rule) e2.nextElement());
     }
 
     answer.sortRules();
     return answer;
  }

  /** helps the toGramm function */
  private Vector processState(State s)
  {
    Transition aTransition;
    Vector answer = new Vector();
    Rule r;
    
    for(Enumeration e = s.transitions.elements(); e.hasMoreElements(); )
    {
      aTransition = (Transition) e.nextElement();

      StringTokenizer st = new StringTokenizer(aTransition.label.trim(), ",");
      String temp;
      if(st.countTokens() == 0)
      {
	 r = new Rule();
         r.setLeft(new Variable(s.label)); //new Variable(giveName(s)));
	 r.addRight(new Variable(aTransition.to.label)); //new Variable(giveName(aTransition.to)));
	 answer.addElement(r);
      }
      while (st.hasMoreTokens())
      {
	 r = new Rule();
         r.setLeft(new Variable(s.label)); //new Variable(giveName(s)));

	 temp = st.nextToken();
	 for(int i = 0; i< temp.trim().length(); i++) {
	   r.addRight( new Terminal(temp.trim().charAt(i)+""));
	 }
	 r.addRight(new Variable(aTransition.to.label)); //new Variable(giveName(aTransition.to)));
	 answer.addElement(r);
      }

    }
    if(s.isFinal) {
	r = new Rule();
	r.setLeft(new Variable(s.label)); //new Variable(giveName(s)));
	r.addRight(new Lambda());
	answer.addElement(r);
    }
    return answer;
  }

  public Vector stepNext()
  {
     if(curTransIndex >= d.theTransitions.size())
	return null;

     Vector vect = new Vector();

     Transition t = (Transition)(d.theTransitions.elementAt(curTransIndex));

     StringTokenizer st = new StringTokenizer(t.label.trim(), ",");
     String temp;
     Rule r;
     if(st.countTokens() == 0)
     {
	r = new Rule();
        r.setLeft(new Variable(t.from.label));
	r.addRight(new Variable(t.to.label));
	vect.addElement(r);
     }
     while (st.hasMoreTokens())
     {
	r = new Rule();
        r.setLeft(new Variable(t.from.label));

	temp = st.nextToken();
	for(int i = 0; i < temp.trim().length(); ++i)
	{
	   r.addRight(new Terminal(temp.trim().charAt(i)+""));
	}
	r.addRight(new Variable(t.to.label));
	vect.addElement(r);
     }

     t.st = Transition.HIGHLIGHTED;
     ++curTransIndex;

     if(t.to.isFinal) {
	r = new Rule();
	r.setLeft(new Variable(t.to.label));
	r.addRight(new Lambda());
	vect.addElement(r);
     }
     return vect;
  }


  /** 
    * finds a name to a state for the grammar
    */
  /*public String giveName(State s)
  {
    if(d.initialState == s)
      return "S";
    return "q" + s.id;
  }*/
}
