package org.jboss.resteasy.test.providers;

import org.codehaus.jettison.json.JSONObject;
import org.codehaus.jettison.mapped.Configuration;
import org.codehaus.jettison.mapped.MappedNamespaceConvention;
import org.codehaus.jettison.mapped.MappedXMLStreamReader;
import org.codehaus.jettison.mapped.MappedXMLStreamWriter;
import org.jboss.resteasy.plugins.providers.jaxb.JAXBXmlTypeProvider;
import org.jboss.resteasy.test.providers.namespace.mapping.NamespaceMappingTestBase;
import org.jboss.resteasy.test.providers.namespace.mapping.NamespaceMappingTestExtends;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import static org.hamcrest.CoreMatchers.containsString;

/**
 * @tpSubChapter Providers
 * @tpChapter Unit tests
 * @tpTestCaseDetails Namespace mapping test for jettison provider
 * @tpSince RESTEasy 3.0.16
 */
public class NamespaceMappingTest {
   static JAXBContext ctx = null;
   static Unmarshaller unmarshaller = null;
   static Marshaller marshaller = null;

   @BeforeClass
   public static void setup() throws Exception {
      ctx = JAXBContext.newInstance("org.jboss.resteasy.test.providers.namespace.mapping");
      unmarshaller = ctx.createUnmarshaller();
      marshaller = ctx.createMarshaller();
   }

   /**
    * @tpTestDetails Marshalling and unmarshalling test
    * @tpSince RESTEasy 3.0.16
    */
   @Test
   public void testManual() throws Exception {
      String marshallError = "Wrong marshalling";
      String unmarshallError = "Wrong unmarshaling";

      String str = marshall();
      Assert.assertThat(marshallError, str, containsString("12121"));
      Assert.assertThat(marshallError, str, containsString("\"Test\""));
      Assert.assertThat(marshallError, str, containsString("\"Desc\""));
      Assert.assertThat(marshallError, str, containsString("\"test\""));
      Assert.assertThat(marshallError, str, containsString("\"element2\":\"Test\""));
      NamespaceMappingTestExtends val = unmarshall(str);
      Assert.assertEquals(unmarshallError, val.getId(), "12121");
      Assert.assertEquals(unmarshallError, val.getName(), "Test");
      Assert.assertEquals(unmarshallError, val.getDesc(), "Desc");
      Assert.assertEquals(unmarshallError, val.getSomeMoreEl(), "test");
      Assert.assertEquals(unmarshallError, val.getElement2(), "Test");
   }

   private String marshall() throws JAXBException {
      JAXBContext jc = JAXBContext.newInstance(NamespaceMappingTestExtends.class, NamespaceMappingTestBase.class);

      NamespaceMappingTestExtends result = new NamespaceMappingTestExtends();
      result.setId("12121");
      result.setName("Test");
      result.setDesc("Desc");
      result.setElement2("Test");
      result.setSomeMoreEl("test");

      Configuration config = new Configuration();
      Map<String, String> xmlToJsonNamespaces = new HashMap<String, String>(1);
      xmlToJsonNamespaces.put("http://www.example.org/b/Test", "test");
      xmlToJsonNamespaces.put("http://www.example.org/a/TestCanonical", "can");
      config.setXmlToJsonNamespaces(xmlToJsonNamespaces);
      MappedNamespaceConvention con = new MappedNamespaceConvention(config);
      StringWriter writer = new StringWriter();
      XMLStreamWriter xmlStreamWriter = new MappedXMLStreamWriter(con, writer);

      Marshaller marshaller = jc.createMarshaller();
      marshaller.marshal(JAXBXmlTypeProvider.wrapInJAXBElement(result, NamespaceMappingTestExtends.class), xmlStreamWriter);
      return writer.toString();
   }

   private NamespaceMappingTestExtends unmarshall(String output) throws Exception {
      JAXBContext jc = JAXBContext.newInstance("org.jboss.resteasy.test.providers.namespace.mapping");
      Configuration config = new Configuration();
      Map<String, String> xmlToJsonNamespaces = new HashMap<String, String>(1);
      xmlToJsonNamespaces.put("http://www.example.org/b/Test", "test");
      xmlToJsonNamespaces.put("http://www.example.org/a/TestCanonical", "can");
      config.setXmlToJsonNamespaces(xmlToJsonNamespaces);
      MappedNamespaceConvention con = new MappedNamespaceConvention(config);
      XMLStreamReader xmlStreamReader = new MappedXMLStreamReader(new JSONObject(output), con);

      Unmarshaller unmarshaller = jc.createUnmarshaller();
      @SuppressWarnings(value = "unchecked")
      JAXBElement<NamespaceMappingTestExtends> val = (JAXBElement<NamespaceMappingTestExtends>) unmarshaller.unmarshal(xmlStreamReader);
      return val.getValue();
   }
}
