package me.exz.wailanbt.handler;

import com.google.gson.JsonElement;
import me.exz.wailanbt.configuration.config;
import me.exz.wailanbt.util.NBTHelper;
import net.minecraft.nbt.*;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static mcp.mobius.waila.api.SpecialChars.*;
class NBTHandler {
    static byte flag;//0 for block; 1 for entity
    static String id = "";

    static List<String> getTipsFromNBT(NBTTagCompound n, String heldItemName) {
        List<String> tips = new ArrayList<String>();
        Set<Map.Entry<String, JsonElement>> holdItemA = config.configJson.entrySet();
        for (Map.Entry<String, JsonElement> holdItem : holdItemA) {
            Pattern pattern = Pattern.compile(holdItem.getKey());
            Matcher matcher = pattern.matcher(heldItemName);
            if (matcher.matches() || flag == 2) {
                Set<Map.Entry<String, JsonElement>> teIDA = holdItem.getValue().getAsJsonObject().entrySet();
                for (Map.Entry<String, JsonElement> teID : teIDA) {
                    tips.addAll(getTipsFromNBTWithHeldItem(n, teID.getKey(), teID.getValue()));
                }
            }
        }

        return tips;
    }

    private static List<String> getTipsFromNBTWithHeldItem(NBTTagCompound n, String teID, JsonElement teEntry) {
        List<String> tips = new ArrayList<String>();
        String teIDReal = id;
        Pattern pattern = Pattern.compile(teID);
        Matcher matcher = pattern.matcher(teIDReal);
        if (matcher.matches()) {
            Set<Map.Entry<String, JsonElement>> pathA = teEntry.getAsJsonObject().entrySet();
            for (Map.Entry<String, JsonElement> path : pathA) {
                String tip = getTipFromNBTWithPath(n, path.getKey(), path.getValue().getAsString());
                if (!tip.equals("__ERROR__")) {
                    tips.add(tip);
                }
            }
        }
        return tips;
    }

    private static String getTipFromNBTWithPath(NBTTagCompound n, String path, String displayName) {
        List<String> pathDeep = new ArrayList<String>(Arrays.asList(path.split(">>>")));
        String tip = getTipFromPathDeep(n, pathDeep, displayName.isEmpty()?path:displayName);
        if (!tip.equals("__ERROR__")) {
            return tip;
        } else {
            return "__ERROR__";
        }

    }


    private static String getTipFromPathDeep(NBTBase n, List<String> pathDeep, String displayName) {
        if (pathDeep.size() == 0) {
            String tipValue = NBTHelper.NBTToString(n);
            if (tipValue.equals("__ERROR__")) {
                return "__ERROR__";
            }
            return getTipFormatted(displayName, tipValue);
        } else {
            String subID = pathDeep.get(0);
            pathDeep.remove(0);
            NBTBase subTag = null;
            try {
                switch (n.getId()) {
                    case 10:
                        subTag = ((NBTTagCompound) n).getTag(subID);
                        break;
                    case 9:
                        NBTTagList tag = (NBTTagList) n;
                        Integer subTagType = tag.func_150303_d();
                        Integer subTagID = Integer.valueOf(subID);
                        switch (subTagType) {
                            case 10:
                                subTag = tag.getCompoundTagAt(subTagID);
                                break;
                            case 11:
                                subTag = new NBTTagIntArray(tag.func_150306_c(subTagID));
                                break;
                            case 6:
                                subTag = new NBTTagDouble(tag.func_150309_d(subTagID));
                                break;
                            case 5:
                                subTag = new NBTTagFloat(tag.func_150308_e(subTagID));
                                break;
                            case 8:
                                String tipValue = tag.getStringTagAt(subTagID);
                                return getTipFormatted(displayName, StringUtils.substring(tipValue, 1, -1));
                            default:
                                return "__ERROR__";
                        }
                }
                return getTipFromPathDeep(subTag, pathDeep, displayName);
            } catch (Exception e) {
                return "__ERROR__";
            }
        }

    }

    private static String getTipFormatted(String displayName, String tipValue) {
        if (flag == 2) {
            return String.format("%s : %s", displayName, tipValue);
        } else {
            return String.format("%s" + TAB + ALIGNRIGHT + WHITE + "%s", displayName, tipValue);
        }
    }
}

@@ -221,16 +221,122 @@
 Utils;%0A%0A
+import javax.script.Invocable;%0Aimport javax.script.ScriptEngine;%0Aimport javax.script.ScriptEngineManager;%0A
 import j
@@ -463,16 +463,17 @@
 hars.*;%0A
+%0A
 class NB
@@ -2380,14 +2380,18 @@
 ty()
-?
+ ? 
 path
-:
+ : 
 disp
@@ -4711,24 +4711,552 @@
 tipValue) %7B%0A
+        if (displayName.startsWith(%22function p(v)%7B%22)) %7B%0A            ScriptEngineManager manager=new ScriptEngineManager();%0A            ScriptEngine engine=manager.getEngineByName(%22javascript%22);%0A            try %7B%0A                engine.eval(displayName);%0A                Invocable invoke = (Invocable)engine;%0A                return String.valueOf(invoke.invokeFunction(%22p%22,tipValue));%0A            %7D catch (Exception e) %7B%0A                e.printStackTrace();%0A                return %22__ERROR__%22;%0A            %7D%0A        %7D else %7B%0A    
         if (
@@ -5260,32 +5260,36 @@
 f (flag == 2) %7B%0A
+    
             retu
@@ -5340,32 +5340,36 @@
 Value);%0A        
+    
 %7D else %7B%0A       
@@ -5365,32 +5365,36 @@
 e %7B%0A            
+ 
+   
 return String.fo
@@ -5454,32 +5454,46 @@
 ame, tipValue);%0A
+            %7D%0A
         %7D%0A    %7D%0A

support javascript to modify display value