package accrue.analysis.ext;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import polyglot.ast.JLang;
import polyglot.ast.Term;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.util.InternalCompilerError;
import polyglot.util.SerialVersionUID;
import polyglot.visit.DataFlow;
import polyglot.visit.FlowGraph;
import polyglot.visit.FlowGraph.EdgeKey;
import polyglot.visit.FlowGraph.Peer;
import accrue.analysis.interprocanalysis.AnalysisContext;
import accrue.analysis.interprocanalysis.DataFlowDispatch;
import accrue.analysis.preciseExceptions.ThrowableType;

/**
 * Dataflow node extension object for an object sensitive analysis
 */
public class ExtTerm extends AccrueExt_c {
    private static final long serialVersionUID = SerialVersionUID.generate();

    /**
     * Get the collection of types of exceptions that might be thrown
     * 
     * @param lang
     *            The language to dispatch any needed calls on.
     * @param ts
     *            Polyglot type system
     * @param context
     *            Data flow analysis context
     * @return collection of types of exceptions that might be thrown
     */
    public Collection<ThrowableType> throwTypes(TypeSystem ts,
            AnalysisContext context) {
        List<Type> l = node().throwTypes(ts);
        List<ThrowableType> r = new ArrayList<ThrowableType>(l.size());
        for (Type t : l) {
            r.add(new ThrowableType(t, false));
        }
        return r;
    }

    /**
     * Dispatch function. Subclasses of ExtTerm should override this method
     * to invoke the appropriate method of <code>DataFlowDispatch<DFItem> d</code>.
     * This helps extensions implement and extend data flow analyses.
     * 
     * @param d
     * @param dfIn
     * @param graph
     * @param peer
     * @return
     */
    public <DFItem extends DataFlow.Item> Map<EdgeKey, DFItem> flowDispatch(
            DataFlowDispatch<DFItem> d, DFItem dfIn, FlowGraph<DFItem> graph,
            Peer<DFItem> peer) {
        Term n = (Term) this.node();
        throw new InternalCompilerError("Do not flowDispatch " + n + " ("
                + n.getClass().getName() + ") for " + d.getClass().getName());
    }

    /**
     * Dispatch function. Subclasses of ExtTerm may override this method
     * to invoke the appropriate method of <code>DataFlowDispatch<DFItem> d</code>.
     * Default behavior is to discard the trueItem and falseItem. 
     * 
     * @param d
     * @param dfIn
     * @param trueItem
     * @param falseItem
     * @param graph
     * @param peer
     * @return
     */
    public <DFItem extends DataFlow.Item> Map<EdgeKey, DFItem> flowDispatch(
            DataFlowDispatch<DFItem> d, DFItem dfIn, DFItem trueItem,
            DFItem falseItem, FlowGraph<DFItem> graph, Peer<DFItem> peer) {
        return this.flowDispatch(d, dfIn, graph, peer);
    }
}
