package com.lyndir.love.webapp.util;

import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;

import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import com.google.common.io.OutputSupplier;
import com.google.gson.*;
import com.google.inject.Singleton;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.*;


/**
 * @author lhunath, 2013-10-19
 */
@Provider
@Singleton
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public class GsonJsonProvider implements MessageBodyReader<Object>, MessageBodyWriter<Object> {

    private static final Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
                                                      .serializeNulls()
                                                      .setPrettyPrinting()
                                                      .disableHtmlEscaping()
                                                      .registerTypeHierarchyAdapter( Enum.class, new JsonSerializer<Enum<?>>() {
                                                          @Override
                                                          public JsonElement serialize(final Enum<?> src, final Type typeOfSrc,
                                                                                       final JsonSerializationContext context) {
                                                              return new JsonPrimitive( src.ordinal() );
                                                          }
                                                      } )
                                                      .create();

    public static Gson getGson() {
        return gson;
    }

    @Override
    public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
        return true;
    }

    @Override
    public Object readFrom(final Class<Object> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType,
                           final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream)
            throws IOException, WebApplicationException {
        return gson.fromJson( new InputStreamReader( entityStream, charsetFromMediaType( mediaType ) ),
                              ifNotNullElse( genericType, type ) );
    }

    private Charset charsetFromMediaType(final MediaType mediaType) {
        String charsetName = mediaType.getParameters().get( MediaType.CHARSET_PARAMETER );
        return charsetName == null? Charsets.UTF_8: Charset.forName( charsetName );
    }

    @Override
    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
        return true;
    }

    @Override
    public long getSize(final Object o, final Class<?> type, final Type genericType, final Annotation[] annotations,
                        final MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(final Object o, final Class<?> type, final Type genericType, final Annotation[] annotations,
                        final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
            throws IOException, WebApplicationException {
        // TODO
        String json = gson.toJson( o, ifNotNullElse( genericType, type ) );
        CharStreams.write( json, CharStreams.newWriterSupplier( new OutputSupplier<OutputStream>() {
            @Override
            public OutputStream getOutput()
                    throws IOException {
                return entityStream;
            }
        }, Charsets.UTF_8 ) );
        //gson.toJson( o, ifNotNullElse( genericType, type ), new OutputStreamWriter( entityStream, charsetFromMediaType( mediaType ) ) );
    }
}

@@ -2462,41 +2462,22 @@
 am, 
-c
+C
 harset
-FromMediaType( mediaType )
+s.UTF_8
  ),%0A
@@ -2555,260 +2555,8 @@
  %7D%0A%0A
-    private Charset charsetFromMediaType(final MediaType mediaType) %7B%0A        String charsetName = mediaType.getParameters().get( MediaType.CHARSET_PARAMETER );%0A        return charsetName == null? Charsets.UTF_8: Charset.forName( charsetName );%0A    %7D%0A%0A
     

Fix JAX-WS 2.0 API misuse.