package com.energy.manage.common.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Collection;
import java.util.Map;

/**
 * Created by lt on 2017/5/22.
 */
public class JSONMapper {

  private static Logger logger = LoggerFactory.getLogger(JSONMapper.class);

  private ObjectMapper objectMapper = null;

  public JSONMapper() {
    this(null);
  }

  public JSONMapper(JsonInclude.Include include) {
    objectMapper = new ObjectMapper();
    // 设置输出时包含属性的风格
    if (include != null) {
      objectMapper.setSerializationInclusion(include);
    }
    // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
    objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
  }

  /**
   * 创建只输出非Null且非Empty(如List.isEmpty)的
   * 属性到Json字符串的Mapper,建议在外部接口中使用.
   */
  public static JSONMapper nonEmptyMapper() {
    return new JSONMapper(JsonInclude.Include.NON_EMPTY);
  }

  /**
   * 创建只输出初始值被改变的属性到Json字符串的Mapper,
   * 最节约的存储方式，建议在内部接口中使用。
   */
  public static JSONMapper nonDefaultMapper() {
    return new JSONMapper(JsonInclude.Include.NON_DEFAULT);
  }

  /**
   * Object可以是POJO，也可以是Collection或数组。
   * 如果对象为Null, 返回"null".
   * 如果集合为空集合, 返回"[]".
   */
  public String toJSon(Object object) {
    try {
      return objectMapper.writeValueAsString(object);
    } catch (Exception e) {
      logger.warn("write to json string error:" + object, e);
    }
    return null;
  }

  /**
   * 反序列化POJO或简单Collection如List<String>.
   * <p>
   * 如果JSON字符串为Null或"null"字符串, 返回Null.
   * 如果JSON字符串为"[]", 返回空集合.
   * <p>
   * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String, JavaType)
   *
   * @see #fromJson(String, JavaType)
   */
  public <T> T fromJson(String jsonString, Class<T> clazz) {
    return this.fromJson(jsonString.getBytes(), clazz);
  }

  /**
   * 反序列化复杂Collection如List<Bean>, 先使用createCollectionType()
   * 或contructMapType()构造类型, 然后调用本函数.
   */
  public <T> T fromJson(String jsonString, JavaType javaType) {
    if (StringTools.isEmpty(jsonString)) {
      return null;
    }

    try {
      return (T) objectMapper.readValue(jsonString, javaType);
    } catch (IOException e) {
      logger.warn("parse json string error:" + jsonString, e);
      return null;
    }
  }

  public <T> T fromJson(byte[] jsonByteArray, Class<T> clazz) {
    if (jsonByteArray.length <= 0) {
      return null;
    }

    try {
      return (T) objectMapper.readValue(jsonByteArray, clazz);
    } catch (IOException e) {
      logger.warn("parse json byteArray error:" + clazz.getName(), e);
      return null;
    }
  }

  /**
   * 构造Collection类型.
   */
  public JavaType contructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
    return objectMapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
  }

  /**
   * 构造Map类型.
   */
  public JavaType contructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
    return objectMapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
  }
}
