package net.heartshield.util;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import net.heartshield.data.NoRemote;
import net.heartshield.data.TimeZoneAdapter;

import org.json.JSONException;
import org.json.JSONObject;

import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TimeZone;

/**
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-04-07
 */
public class JsonUtil {
    private static String[] jsonKeys(JSONObject obj) {
        ArrayList<String> keys = new ArrayList<>();
        Iterator<String> ita = obj.keys();
        while(ita.hasNext())
            keys.add(ita.next());
        return keys.toArray(new String[keys.size()]);
    }

    public static JSONObject mergeJson(JSONObject a, JSONObject b) throws JSONException {
        JSONObject merged = new JSONObject();

        for(String k : jsonKeys(a))
            merged.put(k, a.get(k));

        for(String k : jsonKeys(b))
            merged.put(k, b.get(k));

        return merged;
    }

    public enum Target {
        REMOTE,
        LOCAL
    }

    public static Gson getGson() {
        return getGson(null);
    }

    public static Gson getGson(Target target) {
        GsonBuilder builder = new GsonBuilder()
                .registerTypeAdapter(TimeZone.class, new TimeZoneAdapter())
                .registerTypeAdapter(Object.class, new JsonSerializer<Object>() {
                    @Override
                    public JsonElement serialize(Object src, Type typeOfSrc, JsonSerializationContext context) {
                        return context.serialize(src);
                    }
                })
                .excludeFieldsWithModifiers(Modifier.PRIVATE)
                .setPrettyPrinting();

        if(target == Target.REMOTE) {
            builder.addSerializationExclusionStrategy(new ExclusionStrategy() {
                @Override
                public boolean shouldSkipField(FieldAttributes f) {
                    return (f.getAnnotation(NoRemote.class) != null);
                }

                @Override
                public boolean shouldSkipClass(Class<?> clazz) {
                    return false;
                }
            });
        }

        return builder.create();
    }
}
