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

/* 
 * 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.*;

/**
 * a grammar rule. put a bunch of them together and you have a grammar.
 * The rule is made of a Variable on the left side, and a vector of
 * GrammarRightHandtokens (variables and terminals) on the right side.
 * an empty vector is lambda
 */
public class Rule {

  protected Variable myLeftHand;
  protected Vector myRightHand;
  
    /**
     * creates a new empty Rule 
     */
  public Rule() {
    myRightHand = new Vector();
    
  }
  
    /**
     * copy contructor 
     */
  public Rule(Rule copy) {
    myLeftHand = new Variable(copy.getLeftHand().getContents());
    myRightHand = new Vector();
    GrammarRightHandToken grt;
    for(Enumeration e = copy.getRightHand().elements(); e.hasMoreElements();) {
      grt = (GrammarRightHandToken) e.nextElement();
      if(grt instanceof Lambda)
        myRightHand.addElement(new Lambda(""));
      if(grt instanceof Variable)
        myRightHand.addElement(new Variable(grt.getContents()));
      if(grt instanceof Terminal)
        myRightHand.addElement(new Terminal(grt.getContents()));
    }
  }
    
    /**
     * creates a new Rule from a given string. all characters must be letters.
     * the first character will be the left hand, the others the right hand.
     * (1 character will make a lambda rule). Lower cases are assumed terminals
     *and upper cases variables.
     */
    public Rule(String ruleText) throws BadInputException {
	this();
	if(ruleText.length() == 0)
	    throw new BadInputException("Empty rule.");

	char letter = ruleText.charAt(0);
	if(!Character.isLetter(letter)) 
	    throw new BadInputException("Invalid character.");
	if(Character.isLowerCase(letter)) 
	    throw new BadInputException("Left side must be uppercase.");	
	myLeftHand = new Variable( new String(""+letter));

	int i = 1;
	while(i < ruleText.length()) {
	    letter = ruleText.charAt(i);
	    if(!Character.isLetter(letter)) 
		throw new BadInputException("Invalid character.");
	    if(Character.isLowerCase(letter)) 
		myRightHand.addElement(new Terminal( new String(""+letter)));
	    else
		myRightHand.addElement(new Variable( new String(""+letter)));
	    i++;
	}
    }

    /**
     * sets the left part of the rule
     */
    public void setLeft(Variable v) {
	myLeftHand = v;
    }

    /**
     * gets the left hand Variable
     */
    public Variable getLeftHand() {
	return myLeftHand;
    }

    /**
     * get the right hand of the rule 
     */
    public Vector getRightHand() {
	return myRightHand;
    }

    /**
     * adds a symbol to the end of the right hand of the rule
     */
    public void addRight(GrammarRightHandToken t) {
	myRightHand.addElement(t);
    }

    /**
     * draws the Rule onthe the given coordinates of the Graphics (in color)
     */
    public int draw(Graphics g, int x, int y) {
	String s;
	FontMetrics fm = g.getFontMetrics();
	GrammarRightHandToken grt;
	
	g.setColor(myLeftHand.getColor());
	g.drawString(myLeftHand.getContents(), x, y);
	x += fm.stringWidth(myLeftHand.getContents());
	
	g.setColor(Color.black);
	g.drawString(" -> ", x, y);
	x+= fm.stringWidth(" -> ");
	
	for(Enumeration e = myRightHand.elements(); e.hasMoreElements(); ) {
	    grt = (GrammarRightHandToken) e.nextElement();
	    g.setColor(grt.getColor());
	    g.drawString(grt.getContents(), x, y);
	    x+= fm.stringWidth(grt.getContents());
	    g.drawString(" ", x, y);
	    x+= fm.stringWidth(" ");
	}
	return x;
    }

    /**
     * turns the rule into a String (it might however be impossible to tell the
     * difference between a variable and a terminal)
     */
    public String toString() {
	GrammarRightHandToken grt;
	String result;
	result = myLeftHand.getContents() + " -> ";
	for(Enumeration e = myRightHand.elements(); e.hasMoreElements(); ) {
	    grt = (GrammarRightHandToken) e.nextElement();
	    result += grt.getContents();
	}
	return result;
    }

}
