package edu.cmu.cs.l3.flowgraph;

import java.util.*;
import edu.cmu.cs.l3.temp.*;
import edu.cmu.cs.l3.graph.*;
import edu.cmu.cs.l3.assem.*;

public class AssemFGConstructor implements FGConstructor {

    public AssemFGConstructor() {
    }

    public FlowGraph build(List instrs) throws GraphException {
        int i, j;
        FlowGraph fg = new FlowGraph();

        for (i = 0; i < Temp.tempList.size(); i++) {
            ( (Temp) Temp.tempList.get(i)).resetUsage();
        }

        //Create all vertices
        for (i = 0; i < instrs.size(); i++) {
            fg.createVertex( ( (Instruction) instrs.get(i)));
        }

        //Create edges
        for (i = 0; i < instrs.size(); i++) {
            Instruction instr = (Instruction) instrs.get(i);
            List dsttemps = instr.destTemps(), srctemps = instr.sourceTemps();
            if (dsttemps != null) {
                for (j = 0; j < dsttemps.size(); j++) {
                    ( (Temp) dsttemps.get(j)).def();
                }
            }
            if (srctemps != null) {
                for (j = 0; j < srctemps.size(); j++) {
                    ( (Temp) srctemps.get(j)).use();
                }
            }
            //  FlowVertex v = locateVertexByInstruction(instr);
            FlowVertex v = (FlowVertex) fg.getVertex(i);
            if (instr instanceof OperInstruction) {
                OperInstruction posjump = (OperInstruction) instr;
                if (posjump.labels() != null && posjump.labels().size() > 0) {
                    for (j = 0; j < posjump.labels().size(); j++) {
                        FlowVertex u = locateVertexByLabel(fg, (Label) posjump.
                            labels().get(j));
                        if (u != null) {
                            fg.createEdge(v, u);
                        }
                    }
                }
                if (!posjump.jumpFallsThrough()) {
                    continue;
                }
            }

            if (i < instrs.size() - 1) {
                //FlowVertex u = locateVertexByInstruction((Instruction)instrs.get(i+1));
                FlowVertex u = (FlowVertex) fg.getVertex(i + 1);
                if (instrs.get(i + 1)instanceof LabelInstruction &&
                    i < instrs.size() - 2) {
                    u = (FlowVertex) fg.getVertex(i + 2);
                }
                fg.createEdge(v, u);
            }
        }

        return fg;
    }

    public FlowVertex locateVertexByLabel(FlowGraph fg, Label l) throws GraphException {

        int i, j;
        List verts = fg.getVertices();

        for (i = 0; i < verts.size(); i++) {

            FlowVertex v = (FlowVertex) verts.get(i);
            Instruction vinstr = v.getInstruction();
            if (vinstr instanceof LabelInstruction) {
                List jumps = ( (LabelInstruction) vinstr).labels();
                for (j = 0; j < jumps.size(); j++) {
                    if (jumps.get(j) == l) {
                        if (i < verts.size() - 1) {
                            return (FlowVertex) fg.getVertex(i + 1);
                        }
                        else {
                            return v;
                        }
                    }
                }
            }
        }

        return null;
    }

}