/*
 * 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 Processors;

import API.Utils;
import API.CodeProcessorInterface;
import common.Block;
import common.Code;
import common.Instruction;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;

/**
 *
 * @author EUGENIO CARVALHO
 */
public class VariablesConstantsProcessor implements CodeProcessorInterface {

    private Block block;
    private Iterator<Instruction> interator;
    private Instruction instruction;

    public VariablesConstantsProcessor() {
    }

    @Override
    public void Exec(Code c, LinkedHashMap<String, CodeProcessorInterface> cp) throws Exception {
//        String label, dst;
        String dst;

        block = c.Block();
        HashMap<String, Integer> varUpdate = new HashMap<>();
//        HashMap<String, Integer> rc = c.labelsReferenceCount;
        interator = block.Instructions().iterator();
        // Remove todos os labels não referenciados
        while (interator.hasNext()) {
            instruction = interator.next();
            dst = instruction.G("dst");
            if (!dst.equals("")) {
                if (!varUpdate.containsKey(dst)) {
                    varUpdate.put(dst, 0);
                }
                varUpdate.put(dst, varUpdate.get(dst) + 1);
            }
        }

//        System.out.println("varUpdate:" + varUpdate);
        interator = block.Instructions().iterator();
        int i = 0, value;
        while (interator.hasNext()) {
            instruction = interator.next();
            dst = instruction.G("dst");
            // Se a variavel foi escrita apenas uma vez e o valor atribuido não for uma variavel
            if (!dst.equals("")
                    && varUpdate.get(dst) == 1
                    && instruction.eq("p1value", "true")) {

//                    && ) {
//                if (instruction.eq("type", "assign")) {
//
//                }
                ReplaceConstant(dst, Resolve(instruction), i);

                interator.remove();
            }
            i++;
        }
    }

    protected String Resolve(Instruction instruction) throws Exception {
        System.out.println("instruction:"+ instruction);
        int value = instruction.getInt("p1");
        
        switch (instruction.G("cat")) {
            case "exp":
                if (instruction.eq("p2value", "true")) {
                    value = Utils.ResolveExpr(
                            instruction.G("op"),
                            value,
                            instruction.getInt("p2"));

                }
        }

        return "" + value;
    }

    private void ReplaceConstant(String dst, String value, int i) {
        LinkedList<Instruction> instructions = block.Instructions();
        int size = instructions.size();
        String[] fields = new String[]{"p1", "p2"};

        for (; i < size; i++) {
            instruction = instructions.get(i);
            for (String field : fields) {

                if (instruction.eq(field, dst)) {
                    instruction.S(field, value);
                    instruction.S(field + "value", "true");
                }
            }
        }

    }

}