package code.term;

import code.instr.Instruction;
import code.symbols.DataSymbol;
import code.table.MapTable;
import code.term.visitor.TermVisitor;
import code.term.visitor.ToStringTermVisitor;

/**
 * Term representation for user defined terms.
 *
 * @author Sergio Antoy
 * @since June 17, 2003
 */
public class TermImplUser implements TermImpl {
    private int root;
    private Term[] argument;

    /**
     * Constructor for the TermImplUser object
     *
     * @param root     Description of the Parameter
     * @param argument Description of the Parameter
     */
    public TermImplUser(int root, Term[] argument) {
        this.root = root;
        this.argument = argument;

    }

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

    /**
     * Returns the root symbol for this term.
     *
     * @return The rootSymbol value
     */
    public String getRootSymbol() {
        return MapTable.getSymbol(getRoot()).symbolName;
    }

    /**
     * Returns the list of arguments for this term.
     *
     * @return The argument value
     */
    public Term[] getArgument() {
        return argument;
    }


    /**
     * Returns the numberth argument of this term.
     *
     * @param number Description of the Parameter
     * @return The argument value
     */
    public Term getArgument(byte number) {
        try {
            return argument[number];
        } catch (ArrayIndexOutOfBoundsException ex) {
            System.err.println("Attempt to access argument #" + number +
                    " in term " + (accept(ToStringTermVisitor.singleton, null)).toString());
            throw ex;
        }
    }

    /**
     * Returns the kind of this term
     *
     * @return The kind value
     */
    public byte getKind() { return MapTable.getSymbol(root).kind; }


    /**
     * Returns true if this term is in head normal form.
     *
     * @return The hNF value
     */
    public boolean isHNF() {
        return getKind() >= 0;
    }


    /**
     * Returns true if this term is in normal form.
     *
     * @return The nF value
     */
    public boolean isNF() {
        if (isHNF()) {
            for (int i = 0; i < argument.length; i++) {
                if (!argument[i].isNF()) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }


    /**
     * Returns the bytecode in object format used
     * to rewrite this term.
     *
     * @return The code value
     */
    public Instruction[] getCode() {
        return MapTable.getSymbol(root).code;
    }


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

