/*
 * 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 inicializada = false;

    public static void inicializar(IvannosysCompiler compiler) throws Exception {
        if (inicializada) {
            return;
        }
        /*Inicializando importes*/
        /*Inicializando constantes*/

//        Constantes.add("FALSE", "bool", "0", "global");
//        Constantes.add("false", "bool", "0", "global");
//        Constantes.add("TRUE", "bool", "1", "global");
//        Constantes.add("true", "bool", "1", "global");
//        Constantes.add("null", "bool", "0", "global");
//        Constantes.add("NULL", "bool", "0", "global");
//        Constantes.add("__BASE_HEAP__", "int", "0", "global");
//        Constantes.add("__MAX_MEM__", "int", "1024", "global");

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

        Tipos.Add(Tipos.INTEGER, new Node(Tipos.INTEGER)
                .S("type", Tipos.INTEGER)
                .S("size", 1)
                .S("file", "std")
                .S("scope", "")
                .S("primitive", "true")
                .S("class", "type")
                .S("public", "true")
        );
        Tipos.Add(Tipos.BOOLEAN, new Node(Tipos.BOOLEAN)
                .S("type", Tipos.BOOLEAN)
                .S("size", 1)
                .S("file", "std")
                .S("scope", "")
                .S("primitive", "true")
                .S("class", "type")
                .S("public", "true")
        );
        Tipos.Add(Tipos.CHAR, new Node(Tipos.CHAR)
                .S("type", Tipos.CHAR)
                .S("size", 1)
                .S("file", "std")
                .S("scope", "")
                .S("primitive", "true")
                .S("class", "type")
                .S("public", "true")
        );

        System.out.println("Setei os tipos");
        Imports._init(compiler);
        Constantes._init();
//

//        Tipos.add(Tipos.UNDEFINED, 0);
//        Tipos.add(Tipos.VOID, 0);
//        Tipos.add("string", 1);
//        Tipos.add("thread", 1);
//        Tipos.add("reference", 1);
        Interfaces._init();
        /*Inicializando funcoes*/
        Functions._init();

//        HashMap<String, String> print = new HashMap<>();
//        Functions.add("print", "void", print, "program");
//
//        HashMap<String, String> read = new HashMap<>();
//        Functions.add("read", "void", print, "program");
//
//        HashMap<String, String> sync = new HashMap<>();
//        Functions.add("sync", "void", sync, "program");
//
//        HashMap<String, String> exec = new HashMap<>();
//        Functions.add("exec", "void", exec, "program");
//
//        HashMap<String, String> synexec = new HashMap<>();
//        Functions.add("synexec", "void", synexec, "program");

        /*Inicializando Traps*/
//        Traps._init();

        /*Inicializando Threads*/
//        Threads._init();

        /*Inicializando Variaveis*/
        Variaveis._init();

        /*Variavel global de acesso a structs das threads definidas no programa*/
//        int cod = Variaveis.add("__THREADS__", "magica", "program");
//        Node var = new Node("__THREADS__");
//        var.S("class", "var").S("tipo", "magica*").S("escopo", "program");
//        Variaveis.var(cod, var);
        inicializada = true;
    }

    /**
     * Retorna o numero_da_linha + ':' + numero_da_coluna + '|' nome_arquivo
     *
     * @param n
     * @return
     */
    public static String getFormatedPosition(Node n) {
        return "[" + n.G("line") + ":" + n.G("col") + "|" + n.G("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("&", "");
    }

}
