/**
 * 
 */
package accrue.analysis.pointer;

import java.util.List;
import java.util.Map;

import polyglot.main.Report;
import polyglot.types.CodeInstance;
import polyglot.types.MethodInstance;
import polyglot.types.Type;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import accrue.analysis.AnalysisTopics;
import accrue.analysis.pointer.PointsToEngine.StmtAndContext;
import accrue.analysis.pointer.StmtRegistrar.CodeInfo;
import accrue.analysis.pointer.StmtRegistrar.ExceptionHandlerReferenceVariable;
import accrue.analysis.pointer.analyses.HeapAbstractionFactory;

public class StmtStaticMethodCall extends StmtProcedureCall {

    final ReferenceVariable result;
    final MethodInstance mi;
    final List<ReferenceVariable> actuals;
    final List<ExceptionHandlerReferenceVariable> exceptionHandlers;
    final Map<Type, ReferenceVariable> procedureThrows;

    public StmtStaticMethodCall(ReferenceVariable result, CallSiteNode callSiteNode,
            MethodInstance mi, List<ReferenceVariable> actuals,
            List<ExceptionHandlerReferenceVariable> exceptionHandlers,
            Map<Type, ReferenceVariable> procedureThrows, Position origin,
            CodeInstance code) {
        super(origin, code, callSiteNode);
        this.result = result;
        this.mi = mi;
        this.actuals = actuals;
        this.exceptionHandlers = exceptionHandlers;
        this.procedureThrows = procedureThrows;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        if (result != null) {
            sb.append(result + "=");
        }
        sb.append(mi.signature());
        sb.append(actuals);
        return sb.toString();
    }

    @Override
    public boolean process(CContext callerContext, PointsToGraph g,
            StmtRegistrar registrar, HeapAbstractionFactory af,
            StmtAndContext sac) {

        if (Report.should_report(AnalysisTopics.POINTSTO, 3))
            Report.report(3, "Processing static method call " + this
                    + " in context " + callerContext);

        ReferenceVariableReplica l = null;
        if (result != null) {
            l = ReferenceVariableReplica.create(callerContext, result, af);
        }

        List<ReferenceVariableReplica> args =
                convert(callerContext, actuals, af);
        List<ExceptionHandlerPointsToGraphNode> handlers =
                convert2(callerContext, exceptionHandlers, af);
        Map<Type, ReferenceVariableReplica> procThrows =
                convert(callerContext, procedureThrows, af);

        CodeInfo calleeProcInfo = registrar.getCodeInfo(mi);
        if (calleeProcInfo == null || mi.flags().isNative()) {
            // we don't have code for this constructor
            return registrar.processMissingCode(this.codeInstance,
                                                callerContext,
                                                callSiteNode,
                                                mi,
                                                args,
                                                null,
                                                l,
                                                handlers,
                                                procThrows,
                                                g,
                                                origin,
                                                af,
                                                sac);
        }

        if (calleeProcInfo.formals.size() != args.size()) {
            throw new InternalCompilerError("I don't understand the alg");
        }

        return addEdgesForCall(this.codeInstance,
                               callerContext,
                               callSiteNode,
                               registrar,
                               g,
                               calleeProcInfo,
                               null,
                               args,
                               l,
                               handlers,
                               procThrows,
                               origin,
                               af,
                               sac);

    }

}
