package accrue.analysis.pointer;

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

import polyglot.frontend.AbstractPass;
import polyglot.frontend.ExtensionInfo;
import polyglot.main.Report;
import accrue.AccrueExtensionInfo;
import accrue.analysis.AnalysisTopics;
import accrue.analysis.goals.PointerAnalysisGoal;

public class PointerAnalysisPass extends AbstractPass {
    public static final String ANALYSIS_NAME = "accrue.analysis.pointer";
    static private Map<ExtensionInfo, PointerAnalysisPass> singletons =
            new HashMap<ExtensionInfo, PointerAnalysisPass>();

    static public PointerAnalysisPass singleton(ExtensionInfo extInfo) {
        PointerAnalysisPass singleton = singletons.get(extInfo);
        if (singleton == null) {
            singleton = new PointerAnalysisPass(extInfo);
            singletons.put(extInfo, singleton);

        }
        return singleton;
    }

    private final AccrueExtensionInfo extInfo;
    private final StmtRegistrar registrar;
    private PointsToGraph pointsToGraph;

    private PointerAnalysisPass(ExtensionInfo extInfo) {
        super(PointerAnalysisGoal.singleton(extInfo));
        this.extInfo = (AccrueExtensionInfo) extInfo;
        this.registrar = this.extInfo.createStmtRegistrar();
    }

    public StmtRegistrar registrar() {
        return this.registrar;
    }

    public PointsToGraph pointsToGraph() {
        return this.pointsToGraph;
    }

    @Override
    public boolean run() {
        //        try {        
        Collection<PointsToStmt> stmts = this.registrar().stmts();

        if (Report.should_report(AnalysisTopics.POINTSTO, 6)) {
            for (PointsToStmt s : stmts) {
                Report.report(6, s.toString());
            }
        }
        long startTime = System.currentTimeMillis();
        if (!Report.should_report(AnalysisTopics.POINTSTOGRAPH, 1)) {
            System.err.println("Starting pointer analysis...");
        }
        this.pointsToGraph =
                extInfo.pointsToEngine().solve(this.registrar, this.extInfo);
        long stopTime = System.currentTimeMillis();

        if (!Report.should_report(AnalysisTopics.POINTSTOGRAPH, 1)) {
            System.err.println("Time for pointer analysis: "
                    + (stopTime - startTime));
            System.err.println("  nodes: " + this.pointsToGraph.nodeSize());
            System.err.println("  edges: " + this.pointsToGraph.edgeSize());
        }
        if (Report.should_report(AnalysisTopics.POINTSTO, 4)) {
            this.pointsToGraph.dump(System.out);
        }

        return true;
        //        }
        //        catch (SemanticException e) {
        //            ErrorQueue eq = extInfo.compiler().errorQueue();
        //            eq.enqueue(ErrorInfo.SEMANTIC_ERROR,
        //                       e.getMessage(), e.position());
        //            return false;
        //        }       
    }
}
