package code.term.visitor;

import code.lang.SystemModule;
import code.table.ModuleTable;
import code.term.*;

/**
 * @author Stephen Johnson
 * @since Jul 6, 2004
 *
 * Generics-ized by Sergio on Mon Apr 11 10:37:06 PDT 2005.
 */
public class EqBoolTermVisitor implements TermVisitor<Term,TermImpl> {

    public final static EqBoolTermVisitor singleton = new EqBoolTermVisitor();

    // Ids and term frequently used
    // private final static String boolModuleName = "$Bool";
    private final static String boolModuleName = "Prelude";
    private final static String SystemModuleName = SystemModule.moduleName;
    private static final int andId
	= ModuleTable.sureGetId(boolModuleName, "&&");
    private static final int eqId
	= ModuleTable.sureGetId(SystemModuleName, "==");
    private static final int trueId
	= ModuleTable.sureGetId(boolModuleName, "True");
    private static final int falseId
	= ModuleTable.sureGetId(boolModuleName, "False");
    private static final Term termTrue = new Term(trueId, Term.noArgs);
    private static final Term termFalse	= new Term(falseId, Term.noArgs);


    private EqBoolTermVisitor() {}

    public Term visit(TermImplChar t, TermImpl right) {
        if (right instanceof TermImplChar) {
            char rightValue = ((TermImplChar) right).value;
            return t.value == rightValue ? termTrue : termFalse;
        } else {
            throw new RuntimeException("Type inconsistency " + right);
        }
    }

    public Term visit(TermImplFloat t, TermImpl right) {
        if (right instanceof TermImplFloat) {
            float rightValue = ((TermImplFloat) right).value;
            return t.value == rightValue ? termTrue : termFalse;
         } else {
            throw new RuntimeException("Type inconsistency " + right);
        }
    }

    public Term visit(TermImplInt t, TermImpl right) {
        if (right instanceof TermImplInt) {
            int rightValue = ((TermImplInt) right).value;
            return t.value == rightValue ? termTrue : termFalse;
        } else {
            throw new RuntimeException("Type inconsistency " + right);
        }
    }

    public Term visit(TermImplString t, TermImpl right) {
        if (right instanceof TermImplString) {
            String rightValue = ((TermImplString) right).value;
            return t.value.equals(rightValue) ? termTrue : termFalse;
        } else {
            throw new RuntimeException("Type inconsistency " + right);
        }
    }

    public Term visit(TermImplOpaque t, TermImpl right) {
        if (right instanceof TermImplOpaque) {
            return t.opaque.equals(((TermImplOpaque) right).opaque)
		? termTrue : termFalse;
        } else {
            throw new RuntimeException("Type inconsistency " + right);
        }
    }

    public Term visit(TermImplUser t, TermImpl right) {
        int rightRoot = right.getRoot();
        if (t.getRoot() == rightRoot) {
            Term[] leftArg = t.getArgument();
            Term[] rightArg = right.getArgument();
            if (leftArg.length == rightArg.length) {
                Term reduct;
                if (leftArg.length == 0) {
                    reduct = termTrue;
                } else {
                    int i = leftArg.length - 1;
                    reduct = new Term(eqId,
                            new Term[]{leftArg[i],
                                       rightArg[i], });
                    while (--i >= 0) {
                        reduct = new Term(andId,
                                new Term[]{
                                    new Term(eqId,
                                            new Term[]{leftArg[i],
                                                       rightArg[i], }),
                                    reduct, });
                    }
                }
                return reduct;
            } else {
                throw new RuntimeException("Type inconsistency #arg");
            }
        }
        return termFalse;
    }

    public Term visit(Variable v, TermImpl ignore) {
        throw new IllegalStateException("Improper call for == of a variable");
    }
}

