/*
 * 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.Utils;
import ast.AbstractSyntaxTree;
import ast.Node;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

    protected String name;
    protected LinkedHashMap<String, Node> values = new LinkedHashMap<>();//Map< String, String> copy = new TreeMap<>();
//    protected LinkedList<Node> values = new LinkedList<>();//Map< String, String> copy = new TreeMap<>();
//    protected HashMap<String, Integer> size = new LinkedHashMap<>();
//    protected HashMap<String, Integer> type = new LinkedHashMap<>();
//    protected HashMap<String, Integer> _offset_ = new LinkedHashMap<>();
    protected boolean initialized = false;
    protected static AbstractSyntaxTree ast;

    public static int TYPE_ARGUMENT = 0;
    public static int TYPE_VAR = 1;
    public static int TYPE_RETURN = 2;
    public static int TYPE_STACK = 3;

    public int offsetctrl = 0;
    protected DataFrame data;

    public DataFrame(String name, DataFrame data) {
        this.name = name;
        this.data = data;

    }

    public void setInicializar(boolean init) {
        initialized = init;
    }

    public DataFrame Add(String alias, Node var) throws Exception {
//        System.out.println("Add data to frame:" + var);
        int size = var.getInt("size"), vSize = 1;
//        boolean isArray = var.eq("array", "true");

//        if (isArray) {
//            vSize = Tipos.Size(var.G("type"));
//        }
        for (int i = 0; i < size; i++) {
            values.put(
                    alias + "." + i,
                    var.copy().S("size", vSize)
            );
        }

        return this;
    }

    public LinkedHashMap<String, Node> values() {
        return values;
    }

    public boolean has(String id) {
        for (Map.Entry<String, Node> x : values.entrySet()) {
            if (x.getKey().equals(id)) {
                return true;
            }
        }
        return false;
    }

    public static void setAbstractSyntaxTree(AbstractSyntaxTree ast) {
        DataFrame.ast = ast;
    }

    public int Size() {
        int val = 0;
        for (Map.Entry<String, Node> v : values.entrySet()) {
            try {
                val += v.getValue().getInt("size");
            } catch (Exception ex) {
                Logger.getLogger(DataFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return val;
    }

    @Override
    public String toString() {
        StringBuilder s = new StringBuilder("Data Frame <" + name + ">:" + Size() + "\n");
        Node value;
        for (Map.Entry<String, Node> x : values.entrySet()) {
            value = x.getValue();
            s.append(x.getKey())
                    .append(": ")
                    .append(value.G("name"))
                    .append("\tsize:")
                    .append(value.G("size"))
                    .append("\n");
        }

        return s.toString();
    }

    /**
     * Formata oS haSh para a impreSSão no metodatao toString
     *
     * @param hash
     * @return
     */
    protected String hashToString(HashMap<String, Node> hash) {
        String r = "";
        for (Map.Entry<String, Node> entry : hash.entrySet()) {
            String name = entry.getKey();
            Node value = entry.getValue();
//            int type = this.type.G(name);
            r += "{" + name + ":" + value + "},";
        }
        return r;
    }

    public int Offset(String id) {
        if (id.contains("_G") && data != null) {
            return data.Offset(id);
        }
        int offset = 0;
        try {
//            String cp = id;
            id = normalize(id);

            for (Map.Entry<String, Node> x : values.entrySet()) {
//                System.out.println("Offset:(" + id + ")" + x.getKey());

                if (!x.getKey().equals(id)) {
                    offset += x.getValue().getInt("size");
                    continue;
                }
                break;
            }
        } catch (Exception ex) {
            Logger.getLogger(DataFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        return offset;
    }

    protected Pattern normalId = Pattern.compile("(?<id>[\\w_]+)(\\[(?<index>\\w+)\\])?");

    protected String normalize(String id) {
        String shift = "0", index;
        Matcher m = normalId.matcher(id);
        if (m.find()) {
            id = m.group("id");
            index = m.group("index");
            if (Utils.isNumber(index)) {
                shift = index;
            }
        }

        if (!id.contains(".")) {
            id += "." + shift;
        }
//        System.out.println("Normalize:" + id + "::" + or);
        return id;
    }

    public DataFrame copy(DataFrame data) {
        for (Map.Entry<String, Node> x : data.values().entrySet()) {
//            System.out.println("Copy:" + x.getKey() + "-" + x.getValue());
            this.values.put(x.getKey(), x.getValue());
        }
        return this;
    }

    void Replace(String dst, String p1) {
        String rest;
//        System.out.println("Replace >> " + this.values);

        LinkedHashMap<String, Node> add = new LinkedHashMap<>();

        for (Map.Entry<String, Node> x : this.values.entrySet()) {
            rest = x.getKey().replace(dst, "");
            if (rest.equals("") || rest.substring(0, 1).equals(".")) {
                add.put(p1 + rest, x.getValue());
            } else {
                add.put(x.getKey(), x.getValue());
            }
        }
        this.values = add;

//        System.out.println("Replace << " + this.values);
    }
}
