package com.cyksj.common.util;


import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.TypeFactory;

import java.util.*;

/**
 * @author valor
 * @date 2018/9/25 16:48
 */
public class Jsons {

    private Jsons() { }

    private static ObjectMapper mapper;

    /**
     * @return parser
     */
    public static ObjectMapper parser() {
        return mapper;
    }

    /**
     *
     * @return typeFactory
     */
    public static TypeFactory javaType() {
        return TypeFactory.defaultInstance();
    }

    static {
        mapper = new ObjectMapper();

        // 注册自定义序列化方案 (null值处理)
//        mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new CustomizeBeanSerializerModifier()));
        // 在序列化时忽略值为 null 的属性
//        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        // 序列化时不包括没有@JsonView注解的属性
        mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
        // 在反序列化时忽略在 json 中存在但 Java 对象不存在的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 将日期转为时间戳
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    /**
     * format entity to json.
     *
     * @return String 「Json」
     */
    public static String toJson(Object o) throws Exception {
        return parser().writeValueAsString(o);
    }

    /**
     * parse json and get child integer by key.
     *
     * @return integer 「value」
     */
    public static Integer parseGetInteger(String json, String key) throws Exception {
        JsonNode node = parser().readTree(json).findValue(key);
        if (null == node || node.isNull()) {
            return null;
        } else if (node.canConvertToInt()) {
            return node.asInt();
        }
        return null;
    }

    /**
     * parse bytes and get child integer by key.
     *
     * @return integer 「value」
     */
    public static Integer parseGetInteger(byte[] bytes, String key) throws Exception {
        JsonNode node = parser().readTree(bytes).findValue(key);
        if (null == node || node.isNull()) {
            return null;
        } else if (node.canConvertToInt()) {
            return node.asInt();
        }
        return null;
    }

    /**
     * parse json to map.
     *
     * @return Map<String, T> 「HashMap」
     */
    public static <T> Map<String, T> toMap(String json) throws Exception {
        JavaType type = javaType().constructMapType(HashMap.class, String.class, Object.class);
        return parser().readValue(json, type);
    }

    /**
     * format entity to map.
     *
     * @return Map<String, T> 「HashMap」
     */
    public static <T> Map<String, T> toMap(Object o) {
        JavaType type = javaType().constructMapType(HashMap.class, String.class, Object.class);
        return parser().convertValue(o, type);
    }

    /**
     * parse json to entity.
     *
     * @return T 「entity」
     */
    public static <T> T parseObject(String json, Class<T> clazz) throws Exception {
        return parser().readValue(json, clazz);
    }

    /**
     * parse json to entity.
     *
     * @return T 「entity」
     */
    public static <T> T parseObject(String json, JavaType javaType) throws Exception {
        return parser().readValue(json, javaType);
    }

    /**
     * parse json to entity.
     *
     * @return T 「entity」
     */
    public static <T> T parseObject(byte[] bytes, Class<T> clazz) throws Exception {
        return parser().readValue(bytes, clazz);
    }

    /**
     * parse bytes to entity.
     *
     * @return T 「entity」
     */
    public static <T> T parseObject(byte[] bytes, JavaType javaType) throws Exception {
        return parser().readValue(bytes, javaType);
    }

    /**
     * parse json to entity.
     *
     * @return T 「entity」
     */
    public static <T> T parseObject(Object o, Class<T> clazz) {
        return parser().convertValue(o, clazz);
    }

    /**
     * parse json to entity.
     *
     * @return T 「entity」
     */
    public static <T> T parseObject(Object o, JavaType javaType) {
        return parser().convertValue(o, javaType);
    }


    public static <T> Set<T> parseSet(String json, Class<T> clazz) throws Exception {
        JavaType type = parser().getTypeFactory().constructCollectionType(Set.class, clazz);
        return parser().readValue(json, type);
    }

    /**
     * parse json to ArrayList.
     *
     * @return List<T> 「ArrayList」
     */
    public static <T> List<T> parseList(String json, Class<T> clazz) throws Exception {
        JavaType type = parser().getTypeFactory().constructCollectionType(ArrayList.class, clazz);
        return parser().readValue(json, type);
    }

    /**
     * parse json to ArrayList.
     *
     * @return List<T> 「ArrayList」
     */
    public static <T> List<T> parseList(String json, JavaType javaType) throws Exception {
        JavaType type = parser().getTypeFactory().constructCollectionType(ArrayList.class, javaType);
        return parser().readValue(json, type);
    }

    /**
     * parse json to ArrayList.
     *
     * @return List<T> 「ArrayList」
     */
    public static <T> List<T> parseList(byte[] bytes, Class<T> clazz) throws Exception {
        JavaType type = parser().getTypeFactory().constructCollectionType(ArrayList.class, clazz);
        return parser().readValue(bytes, type);
    }

    /**
     * parse json to ArrayList.
     *
     * @return List<T> 「ArrayList」
     */
    public static <T> List<T> parseList(byte[] bytes, JavaType javaType) throws Exception {
        JavaType type = parser().getTypeFactory().constructCollectionType(ArrayList.class, javaType);
        return parser().readValue(bytes, type);
    }

    /**
     * parse json to ArrayList.
     *
     * @return List<T> 「ArrayList」
     */
    public static <T> List<T> parseList(Object o, Class<T> clazz) {
        JavaType type = parser().getTypeFactory().constructCollectionType(ArrayList.class, clazz);
        return parser().convertValue(o, type);
    }

    /**
     * parse json to ArrayList.
     *
     * @return List<T> 「ArrayList」
     */
    public static <T> List<T> parseList(Object o, JavaType javaType) {
        JavaType type = parser().getTypeFactory().constructCollectionType(ArrayList.class, javaType);
        return parser().convertValue(o, type);
    }

}
