package DOPParser;
/*
 * NonTerminal.java
 *
 * Created on 24 november 2005, 19:45
 */

/**
 *
 * @author gideon
 */
import java.util.ArrayList;
import java.util.HashSet ;
import java.util.LinkedHashSet ;

/**
 * a NonTerminal has a name, and a set of rules associated with it  
 * the rules have a fixed order, according to which the NonTerminal branches (expands) in parsing
 * extends Constituent, so you can combine nonTerminals with Terminals
 */
public class NonTerminal extends Constituent implements Cloneable{
    
    
    private String nonTerminalName;
    private ArrayList<Rule> associatedRules;
    private int nrSubtrees;
    
  
    
    /**
     * Creates a new instance of NonTerminal with given name without adding a rule
     *     (used only for S??)
     */
    public NonTerminal(String myName) {
        
        this.nonTerminalName = myName;
        this.associatedRules = new ArrayList<Rule>();
        
    }
    
     /**
     * Creates a new instance of NonTerminal from a word, and capitalized name 
     *    (at initialization of grammar: every word gets a category)
     */
    public NonTerminal(Terminal myWord, String myName) {
    
        this.nonTerminalName = myName;
        this.associatedRules = new ArrayList<Rule>();
        
        addRule(myWord);
    }
    
       
    /**
     * Creates a new instance of NonTerminal after chunking two nonTerminals together, and invents name
     *    
     */
    public NonTerminal(NonTerminal cat1, NonTerminal cat2, String newName) {
    
        this.nonTerminalName = newName;
        this.associatedRules = new ArrayList<Rule>();
        
        addRule(cat1, cat2);
    }
    
    /**
     * add a rule of the form X->YZ to NonTerminal 
     */
    public void addRule(NonTerminal cat1, NonTerminal cat2){
        this.associatedRules.add(new Rule(this, cat1, cat2));
        
    }
    
    /**
     * add a rule of the form X->a to NonTerminal 
     */
    public void addRule(Terminal word){
        this.associatedRules.add(new Rule(this, word));
        
    }
    
    /**
     * add a rule of the form X->any ArrayList of Constituents to NonTerminal 
     */
    public void addRule(ArrayList<Constituent> constituentArray){
        this.associatedRules.add(new Rule(this, constituentArray));
        
    }
    
    /**
     * add a ready made rule 
     */
    public void addRule(Rule myRule){
        this.associatedRules.add(myRule);
    }
    
    
    
    /**
     * iterates over all associated rules and returns count of rules 
     */
    public int countRules(){
        
        return this.associatedRules.size();
    }
    
    public Rule getRule(int nrRule){
        //todo: error if nrRule > totalRules
        int totalRules = this.associatedRules.size();
        //System.out.println("NonTerminal= " + this.getName() + "; totalRules= " + totalRules + "; nrRule=" + nrRule);
        //assert(nrRule>0 && nrRule < totalRules); ??? werkt niet
        return this.associatedRules.get(nrRule);
        
    }
    
    //??? delete this one?
    /*
    public double getRuleProbability(int nrRule){
        
        int totalCount = 0;
        for (Rule myRule : this.associatedRules) {
            totalCount += myRule.getCount();
        }
        
        return (double) this.associatedRules.get(nrRule).getCount()/totalCount;
    }
    */
    
    public ArrayList<Rule> getRules(){
        
        return this.associatedRules;
    }
    
    /**
     * iterates over all associated rules and returns count of RHS symbols 
     */
       
    public String getName(){
        return this.nonTerminalName;
    }
    
   public void setnrSubtrees(int mynrSubtrees){
        this.nrSubtrees = mynrSubtrees;
    }
    
     public int getnrSubtrees(){
        return this.nrSubtrees;
    }
    
    public boolean equals(Object obj){
        if(!(obj instanceof NonTerminal)){
            return false;
        }
        
        NonTerminal other = (NonTerminal) obj;
        if (this.nonTerminalName.equals(other.nonTerminalName) && this.associatedRules.equals(other.associatedRules)) return true;
        return false;
        //???klopt dit?
    }
    
    public int hashCode(){
        return nonTerminalName.hashCode();
    }
    
    public Object clone() {
            try {
                NonTerminal aobj = (NonTerminal) super.clone();
                //aobj.nonTerminalName = (String) nonTerminalName.clone();
                aobj.associatedRules = (ArrayList<Rule>) associatedRules.clone();
                
                return aobj;
            }
            catch (CloneNotSupportedException e) {
                throw new InternalError(e.toString());
            }
        }
}
