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

import java.util.Set;

import polyglot.main.Report;
import polyglot.types.CodeInstance;
import polyglot.types.FieldInstance;
import polyglot.types.Type;
import polyglot.util.Position;
import accrue.analysis.AnalysisTopics;
import accrue.analysis.pointer.PointsToEngine.StmtAndContext;
import accrue.analysis.pointer.analyses.HeapAbstractionFactory;

public class StmtLocalToField extends PointsToStmt {

    final ReferenceVariable left;
    final FieldInstance fi;
    final String fieldName;
    final ReferenceVariable right;
    final Type expectedFieldType;

    /**
     * left.fi = right
     */
    public StmtLocalToField(ReferenceVariable left, FieldInstance fi, ReferenceVariable right,
            Position origin, CodeInstance code) {
        super(origin, code, fi.type(), right.expectedType(), false);
        this.left = left;
        this.right = right;
        this.fi = fi;
        this.fieldName = fi.name();
        this.expectedFieldType = fi.type();
    }

    /**
     * left.fi = right
     * 
     * Only use for "special fields" that have no field instance (such as the
     * contents of an array)
     */
    public StmtLocalToField(ReferenceVariable left, String fieldName,
            Type expectedFieldType, ReferenceVariable right, Position origin,
            CodeInstance code) {
        super(origin, code, expectedFieldType, right.expectedType(), false);
        this.left = left;
        this.right = right;
        this.fi = null;
        this.fieldName = fieldName;
        this.expectedFieldType = expectedFieldType;
    }

    @Override
    public String toString() {
        return left + "." + fieldName + " = " + right;
    }

    @Override
    public boolean process(CContext context, PointsToGraph g,
            StmtRegistrar registrar, HeapAbstractionFactory af,
            StmtAndContext sac) {
        PointsToGraphNode l =
                ReferenceVariableReplica.create(context, left, af);
        PointsToGraphNode r =
                ReferenceVariableReplica.create(context, right, af);

        if (Report.should_report(AnalysisTopics.POINTSTO, 3))
            Report.report(3, "Processing local to field " + this
                    + " in context " + context);

        Set<HContext> trgs = g.pointsToFiltered(sac, r, expectedFieldType);

        boolean changed = false;
        for (HContext i : g.pointsTo(sac, l)) {
            ObjectField t;
            if (fi != null) {
                t = ObjectField.create(i, fi);
            }
            else {
                t = ObjectField.create(i, fieldName, expectedFieldType);
            }
            changed = g.addEdges(sac, t, trgs, origin) || changed;
        }
        return changed;
    }

}
