/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package IntermediaryCode;

import API.Instruction;
import java.util.HashMap;
import java.util.LinkedList;

public class Block {

    public static int uniq = 0;
    public LinkedList<Instruction> instructions = new LinkedList<>();
    protected String name;
    protected Code code;
    protected HashMap<String, Instruction> labels = new HashMap<>();
    protected DataFrame Data;
    public int BaseAddress = 0;
    public int CurrentAddress = 0;
    public boolean HasCall;
    public int nonLabelCount;

    Block(String name, Code c) {
//        System.out.println("Open block:" + name + ":" + c.PosicaoLabel);
        code = c;
        BaseAddress = c.Position();
//        BaseAddress = c.PosicaoLabel;
        this.name = name;
        Data = new DataFrame(name, code.GData());

//        labels = new HashMap<>();
//        Data = new LinkedHashMap<>();
//        constants = new LinkedHashMap<>();
//        reverseName = new HashMap<>();
//        pointers = new HashMap<>();
//        ocorrencesPerBlocks = new LinkedHashMap<>();
    }

    public LinkedList<Instruction> Instructions() {
        return this.instructions;
    }

    public boolean HasCall() {
        return HasCall;
    }

    public Block Add(Instruction nr) {
        int pos = CurrentAddress;
        if (!nr.eq("type", "label")) {
//            nr.S("reference.position", pos);
//        } else {
//            nr.S("block.position", pos);
//            nr.S("block.position.origin", pos);
            CurrentAddress++;
        }
//        System.out.println("Add:" + nr);
        this.instructions.add(nr);

        return this;
    }

    public Block Remove(Instruction instruction) throws Exception {
//        System.out.println("Remove indtruction do block:" + instruction);
        this.instructions.remove(instruction);
        return this;
    }

    public String getName() {
        return this.name;
    }

    /**
     * Retorna o grupo de variaveiS de eScopo locaiS
     *
     * @return
     */
    public DataFrame Data() {
        return this.Data;
    }

    /**
     * Retorna o grupo de variaveiS de eScopo global
     *
     * @return
     */
    public DataFrame GData() {
        return this.code.GData();
    }

    public DataFrame Data(DataFrame d) {
        return this.Data.copy(d);
    }

    public void Close() throws Exception {
        Update();
    }

    public void Update() throws Exception {
        CurrentAddress = 0;
//        System.out.println("Update:" + instructions.size());

        for (Instruction n : instructions) {
//            System.out.println("Update->:" + CurrentAddress + ":" + code.Position());
            if (!n.eq("type", "label")) {
                n.set("block.position", CurrentAddress)
                        .set("block.position.origin", CurrentAddress++)
                        .set("global.position", code.PositionInc());
            } else {
                n.set("reference.position", CurrentAddress)
                        .set("global.reference.position", code.Position());
                code.RegisterLabelAddress(n.G("label"));
            }
        }
//        System.out.println("}");
    }

    public int LastAddress() {
        return Instructions().size() - 1;
    }

    public Instruction RemoveLast() {
        System.out.println("Remove indtruction do block:");
        return instructions.removeLast();
    }

    public Block ReplaceVar(String find, String replace) {
//        System.out.println("Replace " + find + " -> " + replace);
        for (Instruction inst : instructions) {
            for (String p : new String[]{"dst", "p1", "p2"}) {
                if (inst.eq(p, find)) {
                    inst.S(p, replace);
                }
            }
        }
        return this;
    }

    public int CountInstructions() {
        return nonLabelCount;
    }

}
