package io.cloudslang.lang.entities;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.cloudslang.lang.entities.bindings.*;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import java.io.IOException;

import static org.junit.Assert.*;

public class DeserializeTest {

    private ObjectMapper mapper;
    private Gson gson;

    @Before
    public void setUp() throws Exception {
        mapper = new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(Input.class, new GsonStringInputDeserializer());
        gson = gsonBuilder.create();
    }

    private <T> void testToAndFromJson(Object objToTest, Class<T> type) throws IOException {
        //jackson
        String objAsString = mapper.writeValueAsString(objToTest);
        T objAfterDeserialize = mapper.readValue(objAsString, type);
        assertEquals(objToTest, objAfterDeserialize);

        //gson
        String json = gson.toJson(objToTest);
        T fromJson = gson.fromJson(json, type);
        assertEquals(objToTest, fromJson);
    }

    @Test
    public void testDeserializeInput() throws IOException {
        Input input = new Input(
                "new_input",
                "some_expression",
                true,
                true,
                true,
                "system_property_ok_a_kind");
        testToAndFromJson(input, Input.class);
    }

    @Ignore // TODO: adapter
    @Test
    public void testDeserializeArgument() throws IOException {
        Argument argument = new Argument(
                "new_argument",
                "some_expression"
        );
        testToAndFromJson(argument, Argument.class);
    }

    @Ignore // TODO: adapter
    @Test
    public void testDeserializeOutput() throws IOException {
        Output output = new Output(
                "new_output",
                "some_expression");
        testToAndFromJson(output, Output.class);
    }

    @Ignore // TODO: adapter
    @Test
    public void testDeserializeResult() throws IOException {
        Result result = new Result(
                "new_result",
                "some_expression");
        testToAndFromJson(result, Result.class);
    }

    @Test
    public void testDeserializeResultNavigation() throws IOException {
        ResultNavigation resultNavigation = new ResultNavigation(
                1L,
                "a preset result");
        testToAndFromJson(resultNavigation, ResultNavigation.class);
    }

    @Test
    public void testDeserializeListForLoopStatement() throws IOException {
        LoopStatement listForLoopStatement = new ListForLoopStatement("varName", "expression");
        testToAndFromJson(listForLoopStatement, ListForLoopStatement.class);
    }

    @Test
    public void testDeserializeMapForLoopStatement() throws IOException {
        MapForLoopStatement mapForLoopStatement = new MapForLoopStatement("keyName", "valueName", "expression");
        testToAndFromJson(mapForLoopStatement, MapForLoopStatement.class);
    }

    @Test
    public void testDeserializeAsyncLoopStatement() throws IOException {
        AsyncLoopStatement asyncLoopStatement = new AsyncLoopStatement("varName", "expression");
        testToAndFromJson(asyncLoopStatement, AsyncLoopStatement.class);
    }

    private class GsonStringInputDeserializer extends TypeAdapter<Input> {

        @Override
        public void write(JsonWriter out, Input input) throws IOException {
            out.beginObject();
            out.name("name").value(input.getName());
            out.name("expression").value(String.valueOf(input.getValue()));
            out.name("encrypted").value(input.isEncrypted());
            out.name("required").value(input.isRequired());
            out.name("overridable").value(input.isOverridable());
            out.name("systemPropertyName").value(input.getSystemPropertyName());
            out.endObject();
        }

        @Override
        public Input read(JsonReader in) throws IOException {
            String name = null;
            String expression = null;
            boolean encrypted = false;
            boolean required = false;
            boolean overridable = false;
            String systemPropertyName = null;

            in.beginObject();
            while (in.hasNext()) {
                String property = in.nextName();
                switch (property) {
                    case "name":
                        name = in.nextString();
                        break;
                    case "expression":
                        expression = in.nextString();
                        break;
                    case "required":
                        encrypted = in.nextBoolean();
                        break;
                    case "overridable":
                        required = in.nextBoolean();
                        break;
                    case "encrypted":
                        overridable = in.nextBoolean();
                        break;
                    case "systemPropertyName":
                        systemPropertyName = in.nextString();
                        break;
                    default:
                        throw new RuntimeException("Deserialization error: property '" + property + "' is not valid");
                }
            }
            in.endObject();
            return new Input(name, expression, encrypted, required, overridable, systemPropertyName);
        }
    }

}

@@ -94,184 +94,156 @@
 ort 
-com.google.gson.Gson;%0Aimport com.google.gson.GsonBuilder;%0Aimport com.google.gson.TypeAdapter;%0Aimport com.google.gson.stream.JsonReader;%0Aimport com.google.gson.stream.JsonWriter
+io.cloudslang.lang.entities.bindings.Argument;%0Aimport io.cloudslang.lang.entities.bindings.Input;%0Aimport io.cloudslang.lang.entities.bindings.Output
 ;%0Aim
@@ -284,17 +284,22 @@
 indings.
-*
+Result
 ;%0Aimport
@@ -321,33 +321,8 @@
 re;%0A
-import org.junit.Ignore;%0A
 impo
@@ -405,9 +405,20 @@
 ert.
-*
+assertEquals
 ;%0A%0Ap
@@ -484,31 +484,8 @@
 per;
-%0A    private Gson gson;
 %0A%0A  
@@ -635,188 +635,8 @@
 AL);
-%0A%0A        GsonBuilder gsonBuilder = new GsonBuilder();%0A        gsonBuilder.registerTypeAdapter(Input.class, new GsonStringInputDeserializer());%0A        gson = gsonBuilder.create();
 %0A   
@@ -943,161 +943,8 @@
 ze);
-%0A%0A        //gson%0A        String json = gson.toJson(objToTest);%0A        T fromJson = gson.fromJson(json, type);%0A        assertEquals(objToTest, fromJson);
 %0A   
@@ -1284,37 +1284,8 @@
  %7D%0A%0A
-    @Ignore // TODO: adapter%0A
     
@@ -1536,37 +1536,8 @@
  %7D%0A%0A
-    @Ignore // TODO: adapter%0A
     
@@ -1765,37 +1765,8 @@
  %7D%0A%0A
-    @Ignore // TODO: adapter%0A
     
@@ -3077,2184 +3077,6 @@
  %7D%0A%0A
-    private class GsonStringInputDeserializer extends TypeAdapter%3CInput%3E %7B%0A%0A        @Override%0A        public void write(JsonWriter out, Input input) throws IOException %7B%0A            out.beginObject();%0A            out.name(%22name%22).value(input.getName());%0A            out.name(%22expression%22).value(String.valueOf(input.getValue()));%0A            out.name(%22encrypted%22).value(input.isEncrypted());%0A            out.name(%22required%22).value(input.isRequired());%0A            out.name(%22overridable%22).value(input.isOverridable());%0A            out.name(%22systemPropertyName%22).value(input.getSystemPropertyName());%0A            out.endObject();%0A        %7D%0A%0A        @Override%0A        public Input read(JsonReader in) throws IOException %7B%0A            String name = null;%0A            String expression = null;%0A            boolean encrypted = false;%0A            boolean required = false;%0A            boolean overridable = false;%0A            String systemPropertyName = null;%0A%0A            in.beginObject();%0A            while (in.hasNext()) %7B%0A                String property = in.nextName();%0A                switch (property) %7B%0A                    case %22name%22:%0A                        name = in.nextString();%0A                        break;%0A                    case %22expression%22:%0A                        expression = in.nextString();%0A                        break;%0A                    case %22required%22:%0A                        encrypted = in.nextBoolean();%0A                        break;%0A                    case %22overridable%22:%0A                        required = in.nextBoolean();%0A                        break;%0A                    case %22encrypted%22:%0A                        overridable = in.nextBoolean();%0A                        break;%0A                    case %22systemPropertyName%22:%0A                        systemPropertyName = in.nextString();%0A                        break;%0A                    default:%0A                        throw new RuntimeException(%22Deserialization error: property '%22 + property + %22' is not valid%22);%0A                %7D%0A            %7D%0A            in.endObject();%0A            return new Input(name, expression, encrypted, required, overridable, systemPropertyName);%0A        %7D%0A    %7D%0A%0A
 %7D%0A

remove gson serialization