/*
 * Copyright 2018 MovingBlocks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.terasology.recording;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.entitySystem.entity.EntityManager;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.entity.internal.EngineEntityManager;
import org.terasology.input.ButtonState;
import org.terasology.input.Keyboard;
import org.terasology.input.MouseInput;
import org.terasology.input.events.MouseAxisEvent;
import org.terasology.logic.characters.MovementMode;
import org.terasology.module.ModuleEnvironment;
import org.terasology.persistence.typeHandling.PersistedData;
import org.terasology.persistence.typeHandling.TypeHandler;
import org.terasology.persistence.typeHandling.TypeSerializationLibrary;
import org.terasology.persistence.typeHandling.coreTypes.EnumTypeHandler;
import org.terasology.persistence.typeHandling.extensionTypes.EntityRefTypeHandler;
import org.terasology.persistence.typeHandling.gson.GsonPersistedData;
import org.terasology.persistence.typeHandling.gson.GsonPersistedDataSerializer;
import org.terasology.reflection.TypeInfo;
import org.terasology.reflection.copy.CopyStrategyLibrary;
import org.terasology.reflection.reflect.ReflectionReflectFactory;
import org.terasology.utilities.ReflectionUtil;

import java.io.Reader;
import java.io.FileReader;
import java.io.Writer;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * Serializes and deserializes RecordedEvents.
 */
class RecordedEventSerializer {

    private static final Logger logger = LoggerFactory.getLogger(RecordedEventSerializer.class);

    private TypeHandler<List<RecordedEvent>> recordedEventListTypeHandler;

    public RecordedEventSerializer(EntityManager entityManager, ModuleEnvironment moduleEnvironment) {
        ReflectionReflectFactory reflectFactory = new ReflectionReflectFactory();
        CopyStrategyLibrary copyStrategyLibrary = new CopyStrategyLibrary(reflectFactory);

        TypeSerializationLibrary typeSerializationLibrary = TypeSerializationLibrary.createDefaultLibrary(reflectFactory, copyStrategyLibrary);
        typeSerializationLibrary.addTypeHandler(EntityRef.class, new EntityRefTypeHandler((EngineEntityManager) entityManager));
        typeSerializationLibrary.addTypeHandler(MouseAxisEvent.MouseAxis.class, new EnumTypeHandler<>(MouseAxisEvent.MouseAxis.class));
        typeSerializationLibrary.addTypeHandler(ButtonState.class, new EnumTypeHandler<>(ButtonState.class));
        typeSerializationLibrary.addTypeHandler(Keyboard.Key.class, new EnumTypeHandler<>(Keyboard.Key.class));
        typeSerializationLibrary.addTypeHandler(MouseInput.class, new EnumTypeHandler<>(MouseInput.class));
        typeSerializationLibrary.addTypeHandler(MovementMode.class, new EnumTypeHandler<>(MovementMode.class));

        ClassLoader[] classLoaders = ReflectionUtil.getComprehensiveEngineClassLoaders(moduleEnvironment);

        this.recordedEventListTypeHandler = typeSerializationLibrary.getTypeHandler(
                new TypeInfo<List<RecordedEvent>>() {}, classLoaders).get();
    }

    /**
     * Serializes RecordedEvent's list.
     *
     * @param events RecordedEvent's list.
     * @param filePath path where the data should be saved.
     */
    public void serializeRecordedEvents(List<RecordedEvent> events, String filePath) {
        GsonPersistedDataSerializer serializationContext = new GsonPersistedDataSerializer();
        GsonPersistedData data = (GsonPersistedData) recordedEventListTypeHandler.serialize(events, serializationContext);

        try (Writer writer = new FileWriter(filePath)) {
            Gson gson = new GsonBuilder().create();
            gson.toJson(data.getElement(), writer);
        } catch (IOException e) {
            logger.error("Error while serializing recorded events", e);
        }
    }

    /**
     * Deserializes RecordedEvent's list.
     *
     * @param filePath path where the data should be saved.
     */
    public List<RecordedEvent> deserializeRecordedEvents(String filePath) {
        List<RecordedEvent> events = new ArrayList<>();

        try (Reader reader = new FileReader(filePath)) {
            Gson gson = new GsonBuilder().create();
            JsonElement jsonElement = gson.fromJson(reader, JsonElement.class);
            PersistedData persistedData = new GsonPersistedData(jsonElement);

            Optional<List<RecordedEvent>> recordedEvents = recordedEventListTypeHandler.deserialize(persistedData);
            recordedEvents.ifPresent(events::addAll);

            if (!recordedEvents.isPresent()) {
                logger.error("Some problem occurred during deserialization, no recorded events was found");
            }
        } catch (IOException e) {
            logger.error("Error while serializing recorded events", e);
        }

        return events;
    }
}

@@ -629,109 +629,8 @@
 g;%0A%0A
-import com.google.gson.Gson;%0Aimport com.google.gson.GsonBuilder;%0Aimport com.google.gson.JsonElement;%0A
 impo
@@ -890,255 +890,94 @@
 ogy.
-input.ButtonState;%0Aimport org.terasology.input.Keyboard;%0Aimport org.terasology.input.MouseInput;%0Aimport org.terasology.input.events.MouseAxisEvent;%0Aimport org.terasology.logic.characters.MovementMode;%0Aimport org.terasology.module.ModuleEnvironment
+module.ModuleEnvironment;%0Aimport org.terasology.persistence.serializers.GsonSerializer
 ;%0Aim
@@ -1173,82 +1173,8 @@
 ry;%0A
-import org.terasology.persistence.typeHandling.coreTypes.EnumTypeHandler;%0A
 impo
@@ -1257,160 +1257,8 @@
 er;%0A
-import org.terasology.persistence.typeHandling.gson.GsonPersistedData;%0Aimport org.terasology.persistence.typeHandling.gson.GsonPersistedDataSerializer;%0A
 impo
@@ -1490,91 +1490,12 @@
 .io.
-Reader;%0Aimport java.io.FileReader;%0Aimport java.io.Writer;%0Aimport java.io.FileWriter
+File
 ;%0Aim
@@ -1781,24 +1781,90 @@
 er.class);%0A%0A
+    private GsonSerializer gsonSerializer = new GsonSerializer();%0A
     private 
@@ -2480,586 +2480,8 @@
 r));
-%0A        typeSerializationLibrary.addTypeHandler(MouseAxisEvent.MouseAxis.class, new EnumTypeHandler%3C%3E(MouseAxisEvent.MouseAxis.class));%0A        typeSerializationLibrary.addTypeHandler(ButtonState.class, new EnumTypeHandler%3C%3E(ButtonState.class));%0A        typeSerializationLibrary.addTypeHandler(Keyboard.Key.class, new EnumTypeHandler%3C%3E(Keyboard.Key.class));%0A        typeSerializationLibrary.addTypeHandler(MouseInput.class, new EnumTypeHandler%3C%3E(MouseInput.class));%0A        typeSerializationLibrary.addTypeHandler(MovementMode.class, new EnumTypeHandler%3C%3E(MovementMode.class));
 %0A%0A  
@@ -3020,376 +3020,97 @@
     
-GsonPersistedDataSerializer serializationContext = new GsonPersistedDataSerializer();%0A        GsonPersistedData data = (GsonPersistedData) recordedEventListTypeHandler.serialize(events, serializationContext);%0A%0A        try (Writer writer = new FileWriter(filePath)) %7B%0A            Gson gson = new GsonBuilder().create();%0A            gson.toJson(data.getElement(), writer
+try %7B%0A            gsonSerializer.writeJson(events, recordedEventListTypeHandler, filePath
 );%0A 
@@ -3505,260 +3505,107 @@
 try 
-(Reader reader = new FileReader(filePath)) %7B%0A            Gson gson = new GsonBuilder().create();%0A            JsonElement jsonElement = gson.fromJson(reader, JsonElement.class);%0A            PersistedData persistedData = new GsonPersistedData(jsonElement
+%7B%0A            PersistedData persistedData = gsonSerializer.persistedDatafromJson(new File(filePath)
 );%0A%0A

Use GsonSerializer in RecordedEventSerializer