package accrue.analysis.notnulldataflow;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import polyglot.ast.CodeNode;
import polyglot.ast.Node;
import polyglot.frontend.ExtensionInfo;
import polyglot.frontend.goals.Goal;
import polyglot.visit.NodeVisitor;
import accrue.AccrueExtensionInfo;
import accrue.analysis.ext.AccrueExt;
import accrue.analysis.ext.AccrueExt_c;
import accrue.analysis.ext.ExtExpr;
import accrue.analysis.goals.RegisterProceduresGoal;
import accrue.analysis.interprocanalysis.AnalysisFactory;
import accrue.analysis.interprocanalysis.Registrar;
import accrue.analysis.interprocanalysis.WorkQueue;
import accrue.analysis.interprocvarcontext.InterProcVarContextPass;
import accrue.analysis.interprocvarcontext.VarContext;

public class NotNullAnalysisPass extends InterProcVarContextPass<NotNullAbsVal> {

    static private Map<ExtensionInfo, NotNullAnalysisPass> singletons =
            new HashMap<ExtensionInfo, NotNullAnalysisPass>();

    static public NotNullAnalysisPass singleton(AccrueExtensionInfo extInfo) {
        NotNullAnalysisPass singleton = singletons.get(extInfo);
        if (singleton == null) {
            singleton =
                    new NotNullAnalysisPass(extInfo,
                                            RegisterProceduresGoal.registrar(extInfo),
                                            new NotNullAnalysisFactory(extInfo));
            singletons.put(extInfo, singleton);
        }
        return singleton;
    }

    private NotNullAnalysisPass(ExtensionInfo extInfo, Registrar registrar,
            AnalysisFactory<VarContext<NotNullAbsVal>> analysisFactory) {
        super(extInfo,
              NotNullGoal.singleton(extInfo),
              registrar,
              analysisFactory);
    }

    protected NotNullAnalysisPass(ExtensionInfo extInfo, Goal goal,
            Registrar registrar,
            AnalysisFactory<VarContext<NotNullAbsVal>> analysisFactory) {
        super(extInfo, goal, registrar, analysisFactory);
    }

    @Override
    protected void postSuccessfulProcess(
            WorkQueue<VarContext<NotNullAbsVal>> workQueue) {
        // Mark the non-peer not-null results as valid
        Collection<CodeNode> allCode = workQueue.registrar().allCode();
        NodeVisitor v = new MakeNonPeerNullResultValid();
        for (CodeNode cd : allCode) {
            cd.visit(v);
        }
    }

    public static class MakeNonPeerNullResultValid extends NodeVisitor {

        @Override
        public Node leave(Node old, Node n, NodeVisitor v) {
            AccrueExt ext = AccrueExt_c.ext(n);
            if (ext instanceof ExtExpr) {
                ExtExpr ee = (ExtExpr) ext;
                ee.setNullResultsNoPeerValid();
            }
            return super.leave(old, n, v);
        }

    }

}
