/*
 * $Id: JacksonUtil.java,v 1.0 2016/08/02 01:54:21 wangqx Exp $ *
 */
package cn.com.liandisys.ycjt.ggcx.common.util;

import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.ser.BeanPropertyFilter;
import org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter;
import org.codehaus.jackson.map.ser.impl.SimpleFilterProvider;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.codehaus.jackson.type.TypeReference;


/**
 * @author wangqx
 * 2016-8-02
 */
public class JacksonUtil
{
	private static ObjectMapper om = new ObjectMapper();
	static
	{
		/*设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性*/
		om.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES)
			.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
	}
	
	public static JsonNode toJsonNode(Object bean) throws IOException
	{
		if(bean != null)
		{
			if(bean instanceof String)
				return bean.equals("") ? null : om.readTree((String)bean);
			
			return readBean(bean);
		}
		return null;
	}
	
	public static JsonNode toJsonNode(Object bean, Map<String, String[]> exceptFilterPropMaps) throws IOException
	{
		if(bean != null)
		{
			if(MapUtils.isNotEmpty(exceptFilterPropMaps))
			{
				Map<String, BeanPropertyFilter> filterMap = new HashMap<String, BeanPropertyFilter>();
				for(String fileterName : exceptFilterPropMaps.keySet())
				{
					SimpleBeanPropertyFilter f = SimpleBeanPropertyFilter.serializeAllExcept(exceptFilterPropMaps.get(fileterName));
					filterMap.put(fileterName, f);
				}
				SimpleFilterProvider p = new SimpleFilterProvider(filterMap);
				om.setFilters(p);
			}
			return readBean(bean);
		}
		return null;
	}
	
	public static JsonNode toJsonNode(Object bean, String filterName, String... propNames) throws IOException
	{
		if(bean != null)
		{
			if(StringUtil.isNotEmpty(filterName))
			{
				SimpleBeanPropertyFilter f = SimpleBeanPropertyFilter.serializeAllExcept(propNames);
				SimpleFilterProvider p = new SimpleFilterProvider().addFilter(filterName, f);
				om.setFilters(p);
			}
			return readBean(bean);
		}
		return null;
	}
	
	public static <T> T toBean(JsonNode node, Class<T> cls) throws Exception
	{
		if(node == null)
			return null;
		return om.readValue(node, cls);
	}
	
	public static <T> Map<String, T> toMap(ObjectNode node, Class<T> valueCls) throws Exception
	{
		if(node == null)
			return null;
		return om.readValue(node, new TypeReference<LinkedHashMap<String, T>>(){});
	}
	
	public static String serializeString(String str) throws Exception
	{
		if(StringUtils.isEmpty(str))
			return StringUtils.EMPTY;
		
		return om.writeValueAsString(str);
	}
	
	private static JsonNode readBean(Object bean) throws IOException, JsonGenerationException, JsonMappingException, JsonProcessingException
	{
		StringWriter writer = new StringWriter();
		JsonGenerator jg = om.getJsonFactory().createJsonGenerator(writer);
		om.writeValue(jg, bean);
		jg.close();
		return om.readTree(writer.toString());
	}

	/**
	 * @param pArr
	 * @param key
	 * @param valueCls
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> Set<T> findValuesByKey(ArrayNode pArr, String key, Class<T> valueCls)
	{
		Set<T> set = new LinkedHashSet<T>();
		Iterator<JsonNode> it = pArr.getElements();
		while (it.hasNext())
		{
			JsonNode json = it.next();
			if(json.has(key) && json.get(key) != null)
				set.add((T) json.get(key).asText());
		}
		return set;
	}
}