/*
 * Copyright 2016 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *      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.kie.server.api.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.kie.server.api.marshalling.Marshaller;
import org.kie.server.api.marshalling.MarshallerFactory;
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.api.marshalling.objects.PojoA;
import org.kie.server.api.marshalling.objects.PojoB;
import org.kie.server.api.marshalling.objects.PojoC;

public class MarshallingRoundTripCustomClassListTest {

    private static PojoA createTestObject() {
        PojoA pojoA = new PojoA( "A" );
        PojoB pojoB1 = new PojoB( "B1" );
        PojoB pojoB2 = new PojoB( "B2" );
        PojoC pojoC1 = new PojoC( "C1" );
        PojoC pojoC2 = new PojoC( "C2" );
        PojoC pojoC3 = new PojoC( "C3" );

        List<PojoC> pojoCList1 = new ArrayList<PojoC>();
        pojoCList1.add( pojoC1 );
        pojoCList1.add( pojoC2 );
        pojoB1.setPojoCList( pojoCList1 );

        List<PojoC> pojoCList2 = new ArrayList<PojoC>();
        pojoCList2.add( pojoC3 );
        pojoB2.setPojoCList( pojoCList2 );

        List<PojoB> pojoBList = new ArrayList<PojoB>();
        pojoBList.add( pojoB1 );
        pojoBList.add( pojoB2 );
        pojoA.setPojoBList( pojoBList );

        List<String> stringList = new ArrayList<String>();
        stringList.add( "Hello" );
        stringList.add( "Bye" );
        pojoA.setStringList( stringList );

        return pojoA;
    }

    private Set<Class<?>> getCustomClasses() {
        HashSet<Class<?>> classes = new HashSet<Class<?>>();
        classes.add( PojoA.class );
        classes.add( PojoB.class );
        classes.add( PojoC.class );
        return classes;
    }

    @Test
    public void testJaxb() {
        Marshaller marshaller = MarshallerFactory.getMarshaller( getCustomClasses(), MarshallingFormat.JAXB, getClass().getClassLoader() );
        verifyMarshallingRoundTrip( marshaller, createTestObject() );
    }

    @Test
    public void testXStream() {
        Marshaller marshaller = MarshallerFactory.getMarshaller( getCustomClasses(), MarshallingFormat.XSTREAM, getClass().getClassLoader() );
        verifyMarshallingRoundTrip( marshaller, createTestObject() );

    }

    @Test
    public void testJSON() {
        Marshaller marshaller = MarshallerFactory.getMarshaller( getCustomClasses(), MarshallingFormat.JSON, getClass().getClassLoader() );
        verifyMarshallingRoundTrip( marshaller, createTestObject() );
    }

    private void verifyMarshallingRoundTrip( Marshaller marshaller, Object inputObject ) {
        String rawContent = marshaller.marshall( inputObject );
        Object testObjectAfterMarshallingTurnAround = marshaller.unmarshall( rawContent, inputObject.getClass() );
        Assertions.assertThat( testObjectAfterMarshallingTurnAround ).isEqualTo( inputObject );
    }

    @Test
    public void testJSONTypeInfoTopLevelOnly() {
        Marshaller marshaller = MarshallerFactory.getMarshaller( getCustomClasses(), MarshallingFormat.JSON, getClass().getClassLoader() );
        String rawContent = "{\"org.kie.server.api.marshalling.objects.PojoA\": "
                + "{\"name\": \"A\","
                + " \"pojoBList\":"
                + " [{\"name\": \"B1\","
                + "   \"pojoCList\":"
                + "    ["
                + "      {\"name\": \"C1\"}, "
                + "      {\"name\": \"C2\"}"
                + "    ]"
                + "  },"
                + "  {\"name\": \"B2\","
                + "   \"pojoCList\":"
                + "    ["
                + "     {\"name\": \"C3\"}"
                + "    ]"
                + "  }"
                + " ],"
                + " \"stringList\":"
                + "  [\"Hello\", \"Bye\"]"
                + "}}";

        Object unmarshalledObject = marshaller.unmarshall( rawContent, PojoA.class );
        Assertions.assertThat( unmarshalledObject ).isEqualTo( createTestObject() );
    }
}
