import java.util.ArrayList;
import java.util.List;

/**
 * Class which represents a particular rule along with its dotted position
 * A rule is of the format NONTERM -> LISTOFTOKENS
 *
 * NONTERM i.e the RHS is the precedent
 *
 * The LIST OF TOKENS is the subsequent
 *
 * The grammer class keeps a set of tokens
 *
 * The dotted rule is of the format - (x, R), where x stands for the position of the dot
 * and R stands for the rule itself
 *
 * A dotted rule is of the form : StartPos -> LHS -> RHS1 . RHS2
 *
 * @author asanyal
 */
public class DottedRule {

    // A special symbol marking the end of a rule in the dotted sequence
    public static final String EOR = "END_OF_RULE";

    // Position of the dot in the Dotted Rule
    private int dotPosition;

    // Position of the starting point in the Dotted Rule, i.e the amount of stuff
    // your dotted rule has already seen
    private int startPos;

    // The rule in question
    private CFGRule rule;

    // The back pointers for a given dottedrule
    private List<DottedRule> backpointers;

    public DottedRule(int startPos, int ruleDotPosition, CFGRule cfgRule) {
        this.startPos = startPos;
        this.dotPosition = ruleDotPosition;
        this.rule = cfgRule;
        backpointers = new ArrayList<DottedRule>();
    }

    /**
     * Returns the non terminal immediately after dotted position
     * Returns EOR if dot is at the end
     * @return
     */
    public String getNonTerminalAtDottedPosition() {

        List<String> subsequents = rule.getSubsequent();
        if (dotPosition >= subsequents.size())
            return EOR;

        return subsequents.get(dotPosition);
    }

    /**
     * Gets the dot position
     * @return
     */
    public int getdotPosition() {
        return dotPosition;
    }

    /**
     * Setter for the dot position, primarily for predict phase
     * @param newPos
     */
    public void setDotPosition(int newPos) {
        dotPosition = newPos;
    }

    public CFGRule getRule() {
        return rule;
    }

    /**
     * Gets the LHS of the rule component of the dotted rule
     * @return
     */
    public String getPrecedent() {
        return rule.getPrecedent();
    }

    /**
     * Getter for start position
     * @return
     */
    public int getStartPos() {
        return startPos;
    }

    /**
     * Adds an extra back pointer to this rule
     * @param rule
     */
    public void addBackPointer(DottedRule rule) {
        backpointers.add(rule);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DottedRule other = (DottedRule) obj;
        if (rule == null) {
            if (other.getRule() != null)
                return false;
        } else if (!rule.equals(other.getRule()))
            return false;

        if (dotPosition == other.dotPosition && startPos == other.startPos)
            return true;
        else
            return false;
    }

    public List<DottedRule> getBackPointers() {
        return backpointers;
    }

    public List<String> getSubsequent() {
        return rule.getSubsequent();
    }

    public double getWeight() {
        return rule.getWeight();
    }

    public String getSubsequentAsString() {
        return rule.getSubsequentAsString();
    }
}
