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

//import IntermediaryCode.Allocation;
import ast.Node;
import compiler.IvannosysCompiler;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author Eugenio
 */
public class Api {

    protected static boolean inited = false;

    public static void Init(IvannosysCompiler compiler) throws Exception {
        if (inited) {
            return;
        }

        BuildParams.Set("display.PARSETREE", "false");
        BuildParams.Set("display.ERRORS", "false");
        BuildParams.Set("display.AST", "true");

        BuildParams.Set("mode", "developement");

        /*Inicializando tipos*/
        Types._init();

        // Registra os processadores de codigo padrão
        Middleware.Add("ir.clear.labels", new middlewares.RemoveUnusedLabelsMiddleware());
        Middleware.Add("ir.basic.blocks", new middlewares.BasicBlockMiddleware());
        Middleware.Add("ir.o.load_store", new middlewares.LoadStoreMiddleware());
        Middleware.Add("ir.o.VariablesConstants", new middlewares.VariablesConstantsMiddleware());
        Middleware.Add("ir.o.DeadInstructions", new middlewares.DeadInstructionsMiddleware());
        Middleware.Add("ir.o.copies", new middlewares.CodeOtimizadorMiddleware(true));

        // Processadores do alvo mips
        Middleware.Add("mips.copy.dep", new targets.mips.MipsCopyDepsMiddleware());
        Middleware.Add("mips.register.alloc", new targets.mips.MipsRegisterAllocMiddleware());
        Middleware.Add("mips.o.L1", new targets.mips.MipsOtimizationMiddleware());
        Middleware.Add("mips.update.address", new targets.mips.MipsUpdateAddressMiddleware());

//        Middleware.Add("print.data", (c, cp) -> {
//
//            System.out.println("@@@@@@DATA_LAYOUT:\n\n"
//                    + c.Block().GlobalContext()
//                    + c.Block().Context().toString());
//
//        });
//        Middleware.On("IR", "close.block", "print.data");
        String middlelist = Utils.Join(new String[]{
            // Remove labels não referenciadas
            "ir.clear.labels",
            // Remove copias
            "ir.o.copies",
            // Propagacao de constantes
            //                + "ir.o.VariablesConstants,"
            // Remove instruções que não tem impacto algum na execusao
            //                + "ir.o.DeadInstructions,"
            "ir.basic.blocks", // Extrai os blocos basicos de uma subrotina
//            "ir.o.load_store", // Remove loads e stores desnecessarios
//            "ir.basic.blocks", // Extrai os blsocos basicos de uma subrotina
        }, ",");

        // Define os processadores padrão da IR
        Middleware.On("IR", "close.block", middlelist);
        /*Inicializando importes*/
        Imports._init(compiler);
//        Constantes._init();
        Interfaces._init();
        /*Inicializando funcoes*/
        Functions._init();
        /*Inicializando parametros de compilacao*/
        BuildParams._init();
        /*Inicializando Variables*/
        Variables._init();

        inited = true;
    }

    /**
     * Retorna o numero_da_linha + ':' + numero_da_coluna + '|' nome_arquivo
     *
     * @param n
     * @return
     */
    public static String getFormatedPosition(Node n) {
        return "[" + n.Get("line") + ":" + n.Get("col") + "|" + n.Get("file") + "\t]";
    }

    /**
     * Retorna numero de ocorrenciaS de um Padrão dentro de uma String
     *
     * @param pattern
     * @param input
     * @return
     */
    public static int countRegexOcorrences(String pattern, String input) {
        Matcher matcher = Pattern.compile(pattern).matcher(input);
        int count = 0;
        while (matcher.find()) {
            count++;
        }
        return count;
    }

    public static int countChatOcorrece(String input, char c) {
        int charCount = 0;
        for (int i = 0; i < input.length(); i++) {
            if (input.charAt(i) == c) {
                charCount++;
            }
        }
        return charCount;
    }

    /**
     * Retorna valor de um indice em um vetor unidirecional. <br>
     * var[valor] -> valor;
     *
     * @param var
     * @return
     */
    public static String getIndice(String var) {
        return var.split("\\[")[1].replace("]", "");
    }

    public static String num2bin(int num, int SizeBits) {
        String binario = Integer.toBinaryString(num);
        String paded = Utils.Pad(SizeBits, binario);
        return Utils.cut(SizeBits, paded);
    }

    public static String num2bin(String num, int SizeBits) {
        int val = Integer.parseInt(num);
        return num2bin(val, SizeBits);
    }

//    public static String reg2bin5(String reg) throws Exception {
//        return reg2Bin(reg, 5);
//    }
//    public static String reg2Bin(String reg, int SizeBits) throws Exception {
//        if (reg.equals("")) {
//            return num2bin(0, SizeBits);
//        }
////        System.out.print("Valor do reg:" + reg);
//        int val = Allocation.reg2Int(reg);
////        System.out.println(":val:" + val);
//        return num2bin(val, SizeBits);
//    }
    public static String bin2Hex(String bin, int size) {
//        System.out.println("bin:[" + bin + "]");
        if (bin.equals("")) {
            return "falha";
        }
        return String.format("%" + size + "X", Long.parseLong(bin, 2));
    }

    public static String implode(char delimiter, ArrayList<String> elements) {
        String tmp = elements.toString();
        return tmp.substring(1, tmp.length() - 1).replace(", ", "" + delimiter);
    }

    public static boolean IsValue(String param) {
        if (Utils.IsNumber(param)) {
            return true;
        } else if (param.toLowerCase().matches("(true|false)")) {
            return true;
        }
        return false;
    }

    public static String Value(String v) {
        String vt = v.toLowerCase();
        if (vt.matches("(true|false)")) {
            return vt.equals("true") ? "1" : "0";
        } else {
            return v;
        }
    }

    public static String clearID(String id) {
        return id.replace("*", "").replace("&", "");
    }

    public static void Update() throws Exception {
        Types.Update();
    }

    public static void List() {
        BuildParams.List();
        Types.List();
        Interfaces.List();
        Variables.List();
        Functions.List();
    }

}
