package org.bdware.sc.engine;

import com.google.gson.*;
import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror;
import wrp.jdk.nashorn.internal.runtime.PropertyMap;
import wrp.jdk.nashorn.internal.scripts.JO;

import java.util.HashSet;
import java.util.Set;

public class JSONTool {
    public static JsonElement convertMirrorToJson(Object ret2) {
        return convertMirrorToJsonInternal(ret2, new HashSet<>());
    }

    public static Object convertJsonElementToMirror(JsonElement jsonElement) {
        if (jsonElement.isJsonPrimitive()) {
            JsonPrimitive primitive = jsonElement.getAsJsonPrimitive();
            if (primitive.isString())
                return primitive.getAsString();
            else if (primitive.isBoolean())
                return primitive.getAsBoolean();
            return primitive.getAsNumber();
        } else if (jsonElement.isJsonObject()) {
            JO jo = new JO(PropertyMap.newMap());
            JsonObject jsonObject = jsonElement.getAsJsonObject();
            for (String key : jsonObject.keySet()) {
                jo.put(key, convertJsonElementToMirror(jsonObject.get(key)), false);
            }
            return jo;
        } else if (jsonElement.isJsonArray()) {
            JO jo = new JO(PropertyMap.newMap());
            jo.setIsArray();
            JsonArray jsonArray = jsonElement.getAsJsonArray();
            for (int i = 0; i < jsonArray.size(); i++)
                jo.put(i, convertJsonElementToMirror(jsonArray.get(i)), false);
            return jo;
        }
        return null;
    }

    private static JsonElement convertMirrorToJsonInternal(Object obj, Set<Object> recorded) {
        if (recorded.contains(obj)) return JsonNull.INSTANCE;
        if (obj == null) return JsonNull.INSTANCE;
        if (obj.getClass() == wrp.jdk.nashorn.internal.runtime.Undefined.class)
            return JsonNull.INSTANCE;
        if (obj.getClass() == ScriptObjectMirror.class) {
            recorded.add(obj);
            ScriptObjectMirror som = (ScriptObjectMirror) obj;
            if (som.isFunction()) {
                return JsonNull.INSTANCE;
            }
            if (som.isArray()) {
                JsonArray jarray = new JsonArray();

                for (String str : som.getOwnKeys(true)) {
                    try {
                        if (Integer.parseInt(str) >= 0)
                            jarray.add(convertMirrorToJsonInternal(som.getMember(str), recorded));
                    } catch (Exception e) {
                        // System.out.println("[JSONTool] ignore key:"+str);
                    }
                }
                return jarray;
            } else {
                JsonObject jo = new JsonObject();
                for (String str : som.getOwnKeys(true)) {
                    jo.add(str, convertMirrorToJsonInternal(som.getMember(str), recorded));
                }
                return jo;
            }
        } else if (obj.getClass() == jdk.nashorn.api.scripting.ScriptObjectMirror.class) {
            recorded.add(obj);
            jdk.nashorn.api.scripting.ScriptObjectMirror som =
                    (jdk.nashorn.api.scripting.ScriptObjectMirror) obj;
            if (som.isFunction()) {
                return JsonNull.INSTANCE;
            }
            if (som.isArray()) {
                JsonArray jarray = new JsonArray();

                for (String str : som.getOwnKeys(true)) {
                    try {
                        if (Integer.parseInt(str) >= 0)
                            jarray.add(convertMirrorToJsonInternal(som.getMember(str), recorded));
                    } catch (Exception e) {
                        // System.out.println("[JSONTool] ignore key:"+str);
                    }
                }
                return jarray;
            } else {
                JsonObject jo = new JsonObject();
                for (String str : som.getOwnKeys(true)) {
                    jo.add(str, convertMirrorToJsonInternal(som.getMember(str), recorded));
                }
                return jo;
            }
        } else if (obj.getClass() == jdk.internal.dynalink.beans.StaticClass.class) {
            return JsonNull.INSTANCE;
        } else if (obj instanceof Number) {
            return new JsonPrimitive((Number) obj);

        } else if (obj instanceof String) {
            return new JsonPrimitive((String) obj);

        } else if (obj instanceof Character) {
            return new JsonPrimitive((Character) obj);
        }
        if (obj instanceof Boolean) {
            return new JsonPrimitive((Boolean) obj);
        }
        return JsonNull.INSTANCE;
    }
}
