package com.jenjinstudios.io.serialization;

import com.google.gson.*;
import com.jenjinstudios.io.Message;
import com.jenjinstudios.io.annotations.MessageAdapter;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Used to deserialize Message objects with Gson.
 *
 * @author Caleb Brinkman
 */
public class GsonMessageDeserializer implements JsonDeserializer<Message>
{
    private static final Logger LOGGER = LoggerFactory.getLogger(GsonMessageDeserializer.class);
    private static final Map<String, Class> MESSAGE_CLASSES = new HashMap<>(10);

    static {
        LOGGER.debug("Scanning for message classes");
        Reflections reflections = new Reflections("");
        final Set<Class<? extends Message>> messageClasses = reflections.getSubTypesOf(Message.class);
        for (Class messageClass : messageClasses) {
            LOGGER.debug("Registering message class: " + messageClass.getName());
            Annotation annotation = messageClass.getAnnotation(MessageAdapter.class);
            if (annotation != null) {
                String adaptFromClass = ((MessageAdapter) annotation).adaptFrom().getName();
                LOGGER.debug("Registering adapter class: " + adaptFromClass);
                MESSAGE_CLASSES.put(adaptFromClass, messageClass);
            }
        }
        LOGGER.debug("Registered Message Classes: {}", MESSAGE_CLASSES);
    }

    @Override
    public Message deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
          throws JsonParseException
    {
        JsonObject jsonObject = json.getAsJsonObject();
        JsonElement classElement = jsonObject.get("class");
        if (classElement == null) {
            throw new JsonParseException("Message must specify class to be deserialized into");
        }
        String className = classElement.getAsString();
        Class<Message> lookupClass;
        if (MESSAGE_CLASSES.containsKey(className)) {
            lookupClass = MESSAGE_CLASSES.get(className);
        } else {
            try {
                lookupClass = (Class<Message>) Class.forName(className);
            } catch (ClassNotFoundException | ClassCastException e) {
                throw new JsonParseException("Message implementation not found or incorrect: ", e);
            }
        }
        JsonElement fieldsElement = jsonObject.get("fields");
        return (fieldsElement != null)
              ? context.deserialize(fieldsElement, lookupClass)
              : context.deserialize(new JsonObject(), lookupClass);
    }
}

@@ -697,23 +697,23 @@
  Class%3E 
-MESSAGE
+ADAPTED
 _CLASSES
@@ -1405,23 +1405,23 @@
         
-MESSAGE
+ADAPTED
 _CLASSES
@@ -1535,23 +1535,23 @@
 s: %7B%7D%22, 
-MESSAGE
+ADAPTED
 _CLASSES
@@ -2076,23 +2076,23 @@
     if (
-MESSAGE
+ADAPTED
 _CLASSES
@@ -2148,15 +2148,15 @@
 s = 
-MESSAGE
+ADAPTED
 _CLA

Rename MESSAGE_CLASSES to ADAPTED_CLASSES