package accrue.analysis.interprocanalysis;

import polyglot.ast.CodeNode;
import polyglot.ast.FieldDecl;
import polyglot.ast.Initializer;
import polyglot.ast.ProcedureDecl;

/**
 * An AnalysisUnit is the unit of analysis that the WorkQueue deals with. It is a
 * code declaration (i.e., a method or a constructor or an initializer) in an object-sensitive context.
 */
public class AnalysisUnit {
    final CodeNode cn;
    final AnalysisContext context;

    public AnalysisUnit(ProcedureDecl pd, AnalysisContext context) {
        if (pd == null) throw new IllegalArgumentException();
        this.cn = pd;
        this.context = context;
    }

    public AnalysisUnit(CodeNode cn, AnalysisContext context) {
        if (cn == null
                || !(cn instanceof Initializer || cn instanceof FieldDecl || cn instanceof ProcedureDecl))
            throw new IllegalArgumentException();

        this.cn = cn;
        this.context = context;
    }

    public AnalysisUnit(Initializer init, AnalysisContext context) {
        if (init == null) throw new IllegalArgumentException();
        this.cn = init;
        this.context = context;
    }

    public AnalysisUnit(FieldDecl decl, AnalysisContext context) {
        if (decl == null || decl.init() == null)
            throw new IllegalArgumentException();
        this.cn = decl;
        this.context = context;
    }

    public ProcedureDecl procedureDecl() {
        return (ProcedureDecl) cn;
    }

    public CodeNode codeNode() {
        return cn;
    }

    public AnalysisContext context() {
        return this.context;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof AnalysisUnit) {
            AnalysisUnit that = (AnalysisUnit) o;
            return (this.cn == that.cn)
                    && (this.context == that.context || (this.context != null && this.context.equals(that.context)));
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.cn.hashCode()
                ^ (this.context == null ? 0 : this.context.hashCode());
    }

    @Override
    public String toString() {
        return cn + ":context " + context;
    }
}
