package be.iminds.ilabt.jfed.util;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.util.*;

/**
 * JSonHelper
 */
public class JSonHelper {
    private interface JsonHelper {
        Object getSourceObject();

        void setTranslation(Object o);
    }

    private static class PrimitiveHelper implements JsonHelper {
        Object source;
        Object translation;

        public Object getSourceObject() {
            return source;
        }

        public void setTranslation(Object o) {
            translation = o;
        }
    }

    private static class ListHelper implements JsonHelper {
        Object[] target;
        int index;
        Object item;

        public Object getSourceObject() {
            return item;
        }

        public void setTranslation(Object o) {
            target[index] = o;
        }
    }

    private static class MapHelper implements JsonHelper {
        Map<Object, Object> target;
        Object key;
        Object value;

        public Object getSourceObject() {
            return value;
        }

        public void setTranslation(Object o) {
            target.put(key, o);
        }
    }

    /**
     * converts into JSon object using List and Map
     */
    public static Object jsonStringToXmlRpcLikeObject(String jsonString) {
        if (jsonString == null) return null;
        if (jsonString.trim().isEmpty()) return null;
        if (Objects.equals(jsonString.trim(), "null")) return null;
        Deque<JsonHelper> objectsToProcess = new LinkedList<>();
        PrimitiveHelper base = new PrimitiveHelper();
        base.source = new JSONTokener(jsonString).nextValue();
        objectsToProcess.add(base);
        while (!objectsToProcess.isEmpty()) {
            JsonHelper jsonHelper = objectsToProcess.pollFirst();

            boolean handled = false;
            if (jsonHelper.getSourceObject() instanceof JSONObject) {
                handled = true;
                JSONObject o = (JSONObject) jsonHelper.getSourceObject();
                Map<Object, Object> ht = new HashMap<>();
                for (Object key : o.keySet()) {
                    MapHelper htHelp = new MapHelper();
                    htHelp.target = ht;
                    htHelp.key = key; //assumes key is primitive type and not something else!
                    htHelp.value =
                            o.get((String) key); //this actually seems to assume keys can only be String  (which is fine)
                    objectsToProcess.add(htHelp);
                }
                jsonHelper.setTranslation(ht);
            }
            if (jsonHelper.getSourceObject() instanceof JSONArray) {
                handled = true;
                JSONArray a = (JSONArray) jsonHelper.getSourceObject();
                Object[] v = new Object[a.length()];
                for (int i = 0; i < a.length(); i++) {
                    ListHelper vh = new ListHelper();
                    vh.target = v;
                    vh.index = i;
                    vh.item = a.get(i);
                    objectsToProcess.add(vh);
                }
                jsonHelper.setTranslation(v);
            }
            if (!handled) {
                jsonHelper.setTranslation(jsonHelper.getSourceObject());
            }
        }

        return base.translation;
    }

    public static String jsonObjectToString(Object o) {
        return XmlRpcPrintUtil.xmlRpcObjectToString(o);
    }
}
