package com.conveyal.gtfs.util.json;

import com.conveyal.geojson.GeoJsonModule;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;

import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Map;

/**
 * Helper methods for writing REST API routines
 * @author mattwigway
 *
 */
public class JsonManager<T> {
    private ObjectWriter ow;
    private ObjectMapper om;

    /**
     * Create a new JsonManager
     * @param theClass The class to create a json manager for (yes, also in the diamonds).
     * @param view The view to use
     */
    public JsonManager (Class<T> theClass) {
        this.theClass = theClass;
        this.om = new ObjectMapper();
        om.addMixInAnnotations(Rectangle2D.class, Rectangle2DMixIn.class);
        om.registerModule(new GeoJsonModule());
        SimpleModule deser = new SimpleModule();

        deser.addDeserializer(LocalDate.class, new JacksonSerializers.LocalDateStringDeserializer());
        deser.addSerializer(LocalDate.class, new JacksonSerializers.LocalDateStringSerializer());

        deser.addDeserializer(Rectangle2D.class, new Rectangle2DDeserializer());
        om.registerModule(deser);
        om.getSerializerProvider().setNullKeySerializer(new JacksonSerializers.MyDtoNullKeySerializer());
        SimpleFilterProvider filters = new SimpleFilterProvider();
        filters.addFilter("bbox", SimpleBeanPropertyFilter.filterOutAllExcept("west", "east", "south", "north"));
        this.ow = om.writer(filters);
    }

    private Class<T> theClass;

    /**
     * Add an additional mixin for serialization with this object mapper.
     */
    public void addMixin(Class target, Class mixin) {
        om.addMixInAnnotations(target, mixin);
    }

    public String write(Object o) throws JsonProcessingException {
        if (o instanceof String) {
            return (String) o;
        }
        return ow.writeValueAsString(o);
    }

    public String writePretty(Object o) throws JsonProcessingException {
        if (o instanceof String) {
            return (String) o;
        }
        return om.writerWithDefaultPrettyPrinter().writeValueAsString(o);
    }

    /**
     * Convert an object to its JSON representation
     * @param o the object to convert
     * @return the JSON string
     * @throws JsonProcessingException
     */
    /*public String write (T o) throws JsonProcessingException {
        return ow.writeValueAsString(o);
    }*/

    /**
     * Convert a collection of objects to their JSON representation.
     * @param c the collection
     * @return A JsonNode representing the collection
     * @throws JsonProcessingException
     */
    public String write (Collection<T> c) throws JsonProcessingException {
        return ow.writeValueAsString(c);
    }

    public String write (Map<String, T> map) throws JsonProcessingException {
        return ow.writeValueAsString(map);
    }

    public T read (String s) throws JsonParseException, JsonMappingException, IOException {
        return om.readValue(s, theClass);
    }

    public T read (JsonParser p) throws JsonParseException, JsonMappingException, IOException {
        return om.readValue(p, theClass);
    }

    public T read(JsonNode asJson) {
        return om.convertValue(asJson, theClass);
    }
}

@@ -925,18 +925,22 @@
 tWriter 
-o
 w
+riter
 ;%0A    pr
@@ -958,18 +958,56 @@
 tMapper 
-o
 m
+apper;%0A    SimpleFilterProvider filters
 ;%0A%0A    /
@@ -1136,43 +1136,8 @@
 s).%0A
-     * @param view The view to use%0A
     
@@ -1232,18 +1232,22 @@
    this.
-o
 m
+apper
  = new O
@@ -1261,34 +1261,38 @@
 pper();%0A        
-o
 m
+apper
 .addMixInAnnotat
@@ -1340,34 +1340,38 @@
 class);%0A        
-o
 m
+apper
 .registerModule(
@@ -1732,18 +1732,22 @@
         
-o
 m
+apper
 .registe
@@ -1770,18 +1770,22 @@
         
-o
 m
+apper
 .getSeri
@@ -1880,37 +1880,16 @@
         
-SimpleFilterProvider 
 filters 
@@ -2049,15 +2049,23 @@
 his.
-ow = om
+writer = mapper
 .wri
@@ -2269,18 +2269,22 @@
         
-o
 m
+apper
 .addMixI
@@ -2469,34 +2469,38 @@
 %0A        return 
-o
 w
+riter
 .writeValueAsStr
@@ -2678,18 +2678,22 @@
  return 
-o
 m
+apper
 .writerW
@@ -2718,16 +2718,30 @@
 inter().
+with(filters).
 writeVal
@@ -3010,34 +3010,38 @@
 %0A        return 
-o
 w
+riter
 .writeValueAsStr
@@ -3348,34 +3348,38 @@
 %0A        return 
-o
 w
+riter
 .writeValueAsStr
@@ -3486,18 +3486,22 @@
  return 
-o
 w
+riter
 .writeVa
@@ -3624,34 +3624,38 @@
 %0A        return 
-o
 m
+apper
 .readValue(s, th
@@ -3781,18 +3781,22 @@
  return 
-o
 m
+apper
 .readVal
@@ -3871,18 +3871,22 @@
  return 
-o
 m
+apper
 .convert

Fix #46 - Use filter when writing pretty print JSON