package accrue.jl5;

import polyglot.ast.NodeFactory;
import polyglot.ext.jl5.JL5ExtensionInfo;
import polyglot.ext.jl5.ast.J5Lang_c;
import polyglot.ext.jl5.ast.JL5ExtFactory_c;
import polyglot.ext.jl5.ast.JL5NodeFactory_c;
import polyglot.frontend.Compiler;
import polyglot.frontend.Job;
import polyglot.frontend.Scheduler;
import polyglot.frontend.goals.Goal;
import polyglot.main.Options;
import accrue.AccrueExtensionInfo;
import accrue.AccrueScheduler;
import accrue.analysis.AnalysisTopics;
import accrue.analysis.interprocanalysis.AbstractLocation;
import accrue.analysis.pointer.PointsToEngine;
import accrue.analysis.pointer.StmtRegistrar;
import accrue.analysis.pointer.analyses.HeapAbstractionFactory;
import accrue.analysis.signatures.AnalysisSignatures;
import accrue.jl5.ext.JL5AnalysisExtFactory_c;
import accrue.jl5.pointer.JL5StmtRegistrar;

/**
 * Extension information for Accrue extension for JL5 source code.
 */
public class AccrueJL5ExtensionInfo extends JL5ExtensionInfo implements
        AccrueExtensionInfo {

    static {
        // force Topics to load
        new AnalysisTopics();
    }

    /**
     * Is this extension info being used as an output extension 
     * (i.e., after some preprocessing pass)? If so, then the behavior of the
     * scheduler and the options will be slightly changed. 
     */
    protected boolean isOutputExtensionInfo = false;

    @Override
    public void setIsOutputExtensionInfo(boolean isOutputExtensionInfo) {
        this.isOutputExtensionInfo = isOutputExtensionInfo;
    }

    @Override
    public String compilerName() {
        return "accrue5c";
    }

    @Override
    protected NodeFactory createNodeFactory() {
        return new JL5NodeFactory_c(J5Lang_c.instance,
                                    new JL5AnalysisExtFactory_c(new JL5ExtFactory_c()));
    }

    @Override
    public Scheduler createScheduler() {
        return new AccrueJL5Scheduler(this);
    }

    @Override
    public Goal getCompileGoal(Job job) {
        return ((AccrueScheduler) scheduler).helper().AnalysesDone(job);
    }

    @Override
    public void initCompiler(Compiler compiler) {
        super.initCompiler(compiler);
        AbstractLocation.clearMemoization();
        pointsToEngine = null;
    }

    protected AnalysisSignatures analysisSignatures = null;

    @Override
    public AnalysisSignatures getAnalysisSignatures() {
        if (analysisSignatures == null) {
            analysisSignatures = createAnalysisSignatures();
        }
        return analysisSignatures;

    }

    private PointsToEngine pointsToEngine = null;

    @Override
    public PointsToEngine pointsToEngine() {
        if (pointsToEngine == null) {
            AccrueJL5Options opts = (AccrueJL5Options) this.getOptions();
            pointsToEngine = opts.helper().createPointsToEngine();
        }
        return pointsToEngine;
    }

    @Override
    public HeapAbstractionFactory heapAbstractionFactory() {
        return this.pointsToEngine().heapAbstractionFactory();
    }

    protected AnalysisSignatures createAnalysisSignatures() {
        return new AnalysisSignatures();
    }

    @Override
    protected Options createOptions() {
        return new AccrueJL5Options(this);
    }

    @Override
    public StmtRegistrar createStmtRegistrar() {
        return new JL5StmtRegistrar(this);
    }

    @Override
    public boolean isOutputExtensionInfo() {
        return this.isOutputExtensionInfo;
    }

    @Override
    public String[] defaultFileExtensions() {
        String ext = defaultFileExtension();
        return new String[] { ext, "jl", "jl5", "java" };
    }

}
