package org.hildan.fxlog.config;

import java.lang.reflect.Type;
import java.util.regex.Pattern;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

/**
 * Creates a pre-configured {@link GsonBuilder} that handles properly JavaFX properties.
 * <p>
 * Basically, this class contains custom serializers for properties. These custom serializers make sure the serialized
 * version of the property simply contains the value of the property.
 */
class FxGson {

    /**
     * Creates a pre-configured {@link GsonBuilder} that handles properly JavaFX properties.
     *
     * @return a pre-configured {@link GsonBuilder} that handles properly JavaFX properties.
     */
    static GsonBuilder builder() {
        return new GsonBuilder().registerTypeAdapter(ObservableList.class, new ObservableListCreator())
                                .registerTypeAdapter(DoubleProperty.class, new DoublePropertySerializer())
                                .registerTypeAdapter(DoubleProperty.class, new DoublePropertyDeserializer())
                                .registerTypeAdapter(BooleanProperty.class, new BooleanPropertySerializer())
                                .registerTypeAdapter(BooleanProperty.class, new BooleanPropertyDeserializer())
                                .registerTypeAdapter(Pattern.class, new PatternSerializer())
                                .registerTypeAdapter(Pattern.class, new PatternDeserializer());
    }

    private static class ObservableListCreator implements InstanceCreator<ObservableList<?>> {

        public ObservableList<?> createInstance(Type type) {
            // No need to use a parametrized list since the actual instance will have the raw type anyway.
            return FXCollections.observableArrayList();
        }
    }

    private static class DoublePropertySerializer implements JsonSerializer<DoubleProperty> {
        @Override
        public JsonElement serialize(DoubleProperty doubleProp, Type type, JsonSerializationContext context) {
            return new JsonPrimitive(doubleProp.get());
        }
    }

    private static class DoublePropertyDeserializer implements JsonDeserializer<DoubleProperty> {
        @Override
        public DoubleProperty deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
                JsonParseException {
            return new SimpleDoubleProperty(json.getAsDouble());
        }
    }

    private static class BooleanPropertySerializer implements JsonSerializer<BooleanProperty> {
        @Override
        public JsonElement serialize(BooleanProperty booleanProp, Type type, JsonSerializationContext context) {
            return new JsonPrimitive(booleanProp.get());
        }
    }

    private static class BooleanPropertyDeserializer implements JsonDeserializer<BooleanProperty> {
        @Override
        public BooleanProperty deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
                JsonParseException {
            return new SimpleBooleanProperty(json.getAsBoolean());
        }
    }

    private static class PatternSerializer implements JsonSerializer<Pattern> {
        @Override
        public JsonElement serialize(Pattern pattern, Type type, JsonSerializationContext context) {
            return new JsonPrimitive(pattern.toString());
        }
    }

    private static class PatternDeserializer implements JsonDeserializer<Pattern> {
        @Override
        public Pattern deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
                JsonParseException {
            return Pattern.compile(json.getAsString());
        }
    }
}

@@ -27,16 +27,60 @@
 onfig;%0A%0A
+import java.lang.reflect.ParameterizedType;%0A
 import j
@@ -98,24 +98,24 @@
 flect.Type;%0A
-
 import java.
@@ -218,32 +218,117 @@
 DoubleProperty;%0A
+import javafx.beans.property.IntegerProperty;%0Aimport javafx.beans.property.Property;%0A
 import javafx.be
@@ -406,32 +406,135 @@
 DoubleProperty;%0A
+import javafx.beans.property.SimpleIntegerProperty;%0Aimport javafx.beans.property.SimpleObjectProperty;%0A
 import javafx.co
@@ -2060,32 +2060,444 @@
 Deserializer())%0A
+                                .registerTypeAdapter(IntegerProperty.class, new IntegerPropertySerializer())%0A                                .registerTypeAdapter(IntegerProperty.class, new IntegerPropertyDeserializer())%0A                                .registerTypeAdapter(Property.class, new PropertySerializer())%0A                                .registerTypeAdapter(Property.class, new PropertyDeserializer())%0A
                 
@@ -4227,32 +4227,32 @@
 arseException %7B%0A
-
             retu
@@ -4311,32 +4311,1444 @@
        %7D%0A    %7D%0A%0A
+    private static class IntegerPropertySerializer implements JsonSerializer%3CIntegerProperty%3E %7B%0A        @Override%0A        public JsonElement serialize(IntegerProperty intProp, Type type, JsonSerializationContext context) %7B%0A            return new JsonPrimitive(intProp.get());%0A        %7D%0A    %7D%0A%0A    private static class IntegerPropertyDeserializer implements JsonDeserializer%3CIntegerProperty%3E %7B%0A        @Override%0A        public IntegerProperty deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws%0A                JsonParseException %7B%0A            return new SimpleIntegerProperty(json.getAsInt());%0A        %7D%0A    %7D%0A%0A    private static class PropertySerializer implements JsonSerializer%3CProperty%3C?%3E%3E %7B%0A        @Override%0A        public JsonElement serialize(Property%3C?%3E doubleProp, Type type, JsonSerializationContext context) %7B%0A            return context.serialize(doubleProp.getValue());%0A        %7D%0A    %7D%0A%0A    private static class PropertyDeserializer implements JsonDeserializer%3CProperty%3C?%3E%3E %7B%0A        @Override%0A        public Property%3C?%3E deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws%0A                JsonParseException %7B%0A            Type typeParam = ((ParameterizedType)typeOfT).getActualTypeArguments()%5B0%5D;%0A            Object obj = context.deserialize(json, typeParam);%0A            return new SimpleObjectProperty%3C%3E(obj);%0A        %7D%0A    %7D%0A%0A
     private stat

Add custom (de)serializer for Property