/*
 * Copyright 2019 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.dialogs.action;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.nio.file.ShrinkWrapFileSystems;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Before;
import org.junit.Test;
import org.terasology.engine.module.ModuleManager;
import org.terasology.engine.paths.PathManager;
import org.terasology.module.DependencyResolver;
import org.terasology.module.ModuleEnvironment;
import org.terasology.module.ResolutionResult;
import org.terasology.naming.Name;
import org.terasology.persistence.ModuleContext;
import org.terasology.persistence.typeHandling.TypeHandler;
import org.terasology.persistence.typeHandling.TypeHandlerLibrary;
import org.terasology.persistence.typeHandling.gson.GsonPersistedData;
import org.terasology.persistence.typeHandling.gson.GsonPersistedDataSerializer;
import org.terasology.reflection.TypeInfo;
import org.terasology.testUtil.ModuleManagerFactory;

import java.nio.file.FileSystem;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;

public class PlayerActionSerializationTest {
    public static final GsonPersistedDataSerializer SERIALIZER = new GsonPersistedDataSerializer();
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
    private TypeHandler<PlayerAction> playerActionTypeHandler;

    @Before
    public void setUp() throws Exception {
        final JavaArchive homeArchive = ShrinkWrap.create(JavaArchive.class);
        final FileSystem vfs = ShrinkWrapFileSystems.newFileSystem(homeArchive);
        PathManager.getInstance().useOverrideHomePath(vfs.getPath(""));

        ModuleManager moduleManager = ModuleManagerFactory.create();

        DependencyResolver resolver = new DependencyResolver(moduleManager.getRegistry());
        ResolutionResult result = resolver.resolve(Lists.newArrayList(new Name("engine"),
            new Name("Dialogs"),
            new Name("unittest")));

        assumeTrue(result.isSuccess());

        ModuleEnvironment environment = moduleManager.loadEnvironment(result.getModules(), true);

        ModuleContext.setContext(environment.get(new Name("Dialogs")));

        TypeHandlerLibrary typeHandlerLibrary = new TypeHandlerLibrary(moduleManager);
        playerActionTypeHandler = typeHandlerLibrary.getBaseTypeHandler(TypeInfo.of(PlayerAction.class));
    }

    @Test
    public void testCloseDialogAction() {
        CloseDialogAction action = new CloseDialogAction();
        String json = serialize(action);
        String expected = "{\n" +
                              "  \"class\": \"Dialogs:CloseDialogAction\"\n" +
                              "}";

        assertEquals(expected, json);

        final String CONTEXT_BASED_JSON = "{\n" +
                                              "\"class\": \"CloseDialogAction\"\n" +
                                              "}";

        action = deserialize(CONTEXT_BASED_JSON, CloseDialogAction.class);

        assertNotNull(action);
    }

    @Test
    public void testChangeDialogAction() {
        ChangeDialogAction action = new ChangeDialogAction("$prefab");
        String json = serialize(action);
        String expected = "{\n" +
                              "  \"class\": \"Dialogs:ChangeDialogAction\",\n" +
                              "  \"prefab\": \"$prefab\"\n" +
                              "}";

        assertEquals(expected, json);

        final String CONTEXT_BASED_JSON = "{\n" +
                                              "\"class\": \"ChangeDialogAction\",\n" +
                                              "\"prefab\": \"$prefab\"\n" +
                                              "}";

        action = deserialize(CONTEXT_BASED_JSON, ChangeDialogAction.class);

        assertNotNull(action);
        assertEquals("$prefab", action.getPrefab());
    }

    @Test
    public void testNewDialogAction() {
        NewDialogAction action = new NewDialogAction("$$$");
        String json = serialize(action);
        String expected = "{\n" +
                              "  \"class\": \"Dialogs:NewDialogAction\",\n" +
                              "  \"target\": \"$$$\"\n" +
                              "}";

        assertEquals(expected, json);

        final String CONTEXT_BASED_JSON = "{\n" +
                                              "  \"class\": \"NewDialogAction\",\n" +
                                              "  \"target\": \"$$$\"\n" +
                                              "}";

        action = deserialize(CONTEXT_BASED_JSON, NewDialogAction.class);

        assertNotNull(action);
        assertEquals("$$$", action.getTarget());
    }

    private <T extends PlayerAction> String serialize(T action) {
        GsonPersistedData serialized =
            (GsonPersistedData) playerActionTypeHandler.serialize(action, SERIALIZER);
        return GSON.toJson(serialized.getElement());
    }

    private <T extends PlayerAction> T deserialize(String json, Class<T> clazz) {
        GsonPersistedData data = new GsonPersistedData(GSON.fromJson(json, JsonElement.class));
        PlayerAction playerAction = playerActionTypeHandler.deserializeOrThrow(data);

        assertTrue(clazz.isInstance(playerAction));
        return clazz.cast(playerAction);
    }
}

@@ -634,48 +634,8 @@
 n;%0A%0A
-import com.google.common.collect.Lists;%0A
 impo
@@ -747,442 +747,61 @@
 rg.j
-boss.shrinkwrap.api.ShrinkWrap;%0Aimport org.jboss.shrinkwrap.api.nio.file.ShrinkWrapFileSystems;%0Aimport org.jboss.shrinkwrap.api.spec.JavaArchive;%0Aimport org.junit.Before;%0Aimport org.junit.Test;%0Aimport org.terasology.engine.module.ModuleManager;%0Aimport org.terasology.engine.paths.PathManager;%0Aimport org.terasology.module.DependencyResolver;%0Aimport org.terasology.module.ModuleEnvironment;%0Aimport org.terasology.module.ResolutionResul
+unit.Test;%0Aimport org.terasology.ModuleEnvironmentTes
 t;%0Ai
@@ -1208,95 +1208,8 @@
 nfo;
-%0Aimport org.terasology.testUtil.ModuleManagerFactory;%0A%0Aimport java.nio.file.FileSystem;
 %0A%0Aim
@@ -1343,51 +1343,8 @@
 rue;
-%0Aimport static org.junit.Assume.assumeTrue;
 %0A%0Apu
@@ -1384,16 +1384,46 @@
 ionTest 
+extends ModuleEnvironmentTest 
 %7B%0A    pu
@@ -1674,13 +1674,15 @@
    @
-Befor
+Overrid
 e%0A  
@@ -1702,666 +1702,48 @@
  set
-U
+u
 p() 
-throws Exception %7B%0A        final JavaArchive homeArchive = ShrinkWrap.create(JavaArchive.class);%0A        final FileSystem vfs = ShrinkWrapFileSystems.newFileSystem(homeArchive);%0A        PathManager.getInstance().useOverrideHomePath(vfs.getPath(%22%22));%0A%0A        ModuleManager moduleManager = ModuleManagerFactory.create();%0A%0A        DependencyResolver resolver = new DependencyResolver(moduleManager.getRegistry());%0A        ResolutionResult result = resolver.resolve(Lists.newArrayList(new Name(%22engine%22),%0A            new Name(%22Dialogs%22),%0A            new Name(%22unittest%22)));%0A%0A        assumeTrue(result.isSuccess());%0A%0A        ModuleEnvironment environment = 
+%7B%0A        ModuleContext.setContext(
 modu
@@ -1756,12 +1756,11 @@
 ger.
-load
+get
 Envi
@@ -1771,81 +1771,9 @@
 ent(
-result.getModules(), true);%0A%0A        ModuleContext.setContext(environment
+)
 .get
@@ -1881,16 +1881,30 @@
 eManager
+, typeRegistry
 );%0A     

Make PlayerActionSerializationTest extend ModuleEnvironmentTest