package io.delphi.qa.auto.awsmfrw.common_baby.gson;

import com.google.gson.*;
import com.google.gson.internal.LinkedTreeMap;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MapDeserializerDoubleAsIntFix implements JsonDeserializer<Map<String, Object>> {

  @Override
  @SuppressWarnings("unchecked")
  public Map<String, Object> deserialize(
      JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {
    return (Map<String, Object>) read(json);
  }

  public Object read(JsonElement in) {

    if (in.isJsonArray()) {
      List<Object> list = new ArrayList<Object>();
      JsonArray arr = in.getAsJsonArray();
      for (JsonElement anArr : arr) {
        list.add(read(anArr));
      }
      return list;
    } else if (in.isJsonObject()) {
      Map<String, Object> map = new LinkedTreeMap<String, Object>();
      JsonObject obj = in.getAsJsonObject();
      Set<Map.Entry<String, JsonElement>> entitySet = obj.entrySet();
      for (Map.Entry<String, JsonElement> entry : entitySet) {
        map.put(entry.getKey(), read(entry.getValue()));
      }
      return map;
    } else if (in.isJsonPrimitive()) {
      JsonPrimitive prim = in.getAsJsonPrimitive();
      if (prim.isBoolean()) {
        return prim.getAsBoolean();
      } else if (prim.isString()) {
        return prim.getAsString();
      } else if (prim.isNumber()) {
        Number num = prim.getAsNumber();
        // here you can handle double int/long values
        // and return any type you want
        // this solution will transform 3.0 float to long values
        if (Math.ceil(num.doubleValue()) == num.intValue()) return num.intValue();
        if (Math.ceil(num.doubleValue()) == num.longValue()) return num.longValue();
        if (Math.ceil(num.doubleValue()) == num.floatValue()) return num.floatValue();
        if (Math.ceil(num.doubleValue()) == num.byteValue()) return num.byteValue();
        else {
          return num.doubleValue();
        }
      }
    }
    return null;
  }
}
