	package com.bernard.greposimu.engine.json;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;

public class MapJsonDeserializer extends StdDeserializer<Map<String,?>> implements ContextualDeserializer{
	
	private static final long serialVersionUID = -888029778299077908L;
	private JavaType type;	

	public MapJsonDeserializer() {
		super(Object.class);
	}
	
	@Override
	public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException{
		MapJsonDeserializer deserializer = new MapJsonDeserializer();
		if(property != null)
			deserializer.type = property.getType().containedType(1);
		else
			deserializer.type = ctxt.getContextualType();
        return deserializer;
    }

    @Override
    public Map<String,?> deserialize(JsonParser parser, DeserializationContext deserializationContext) throws IOException {
    	JsonNode node = parser.getCodec().readTree(parser);
    	if(node.isNull() || (node.isArray() && node.isEmpty()))
    		return new HashMap<>();
    	else if(node.isObject()) {
	        ObjectCodec codec = parser.getCodec();
	        Map<String,Object> output = new HashMap<>();
	        java.util.Iterator<Entry<String, JsonNode>> it = node.fields();
	        while(it.hasNext()) {
	        	Entry<String, JsonNode> entry = it.next();
	        	output.put(entry.getKey(), entry.getValue().traverse(codec).readValueAs(this.type.getRawClass()));
            }
	        return output;
    	} else
    		throw MismatchedInputException.from(parser, Map.class, "JSON is neither an empty array nor a map");
    }

}
