package code.term;

import code.instr.Instruction;
import code.subst.Subst;
import code.symbols.ConstructorSymbol;
import code.symbols.DataSymbol;
import code.term.visitor.TermVisitor;
import code.term.visitor.ToStringTermVisitor;

/**
 * Term representation for free variables.
 *
 * @author Sergio Antoy
 * @since June 17, 2003
 */
public class Variable implements TermImpl {

    /**
     * Counter for program-generated variable names.
     */
    private static int counter = 1;

    /**
     * Prefix for program-generated variable names.
     */
    public final static String autoVarPrefix = "_";

    /**
     * Exceptions thrown by Variable
     */
    private final static IllegalStateException argException
            = new IllegalStateException("No argument of a variable");
    private final static IllegalStateException replaceException
            = new IllegalStateException("No replacement of a variable");
    private final static IllegalStateException eqBool
            = new IllegalStateException("Improper call for == of a variable");

    private final String name;

    /**
     * Constructor for the Variable object
     *
     * @param name The name of this variable
     */
    public Variable(String name) { this.name = name; }

    /**
     * Constructor for the Variable object
     */
    public Variable() { this.name = autoVarPrefix + counter++; }

    /**
     * Returns the root symbol of this term.
     *
     * @return The rootSymbol value
     */
    public String getRootSymbol() {
        return accept(ToStringTermVisitor.singleton, null);
    }

    /**
     * Returns the root id of this term.
     *
     * @return The root value
     */
    public int getRoot() { return DataSymbol.UnboundVariable; }

    /**
     * Returns an empty list of terms since free
     * variables do not have arguments.
     *
     * @return The argument value
     */
    public Term[] getArgument() { return new Term[0]; }

    /**
     * Throws an exception since free variables
     * do not have arguments.
     *
     * @param number Description of the Parameter
     * @return The argument value
     */
    public Term getArgument(byte number) { throw argException; }

    /**
     * Returns the kind for variables.
     *
     * @return The kind value
     */
    public byte getKind() { return DataSymbol.UnboundVariable; }

    /**
     * Returns the name of this variable.
     *
     * @return String
     */
    public String getName() { return name; }

    /**
     * Returns an empty list since free variables
     * are not rewritten.
     *
     * @return The code value
     */
    public Instruction[] getCode() { return ConstructorSymbol.noCode; }

    /**
     * Returns true since free variables are in
     * head normal form.
     *
     * @return The hNF value
     */
    public boolean isHNF() { return true; }

    /**
     * Returns true since variables are in normal form.
     *
     * @return The nF value
     */
    public boolean isNF() { return true; }

    /**
     * Returns the String representation of this variable.
     * To get the string representation you can use the
     * ToStringTermVisitor.  This method is just a wrapper
     * for this.  I included this wrapper since PrintAsTxtLoadable
     * seems to be called in a number of places on a variable.
     */
    public String toString() {
        return accept(ToStringTermVisitor.singleton, null).toString();
    }

    /**
     * Accepts the visitor by passing this term as a parameter to
     * the visit method of the visitor.
     *
     */
    public <R,T> R accept(TermVisitor<R,T> v, T o) {
	return v.visit(this, o);
    }
    
}

