/**
 *
 */
package com.lz.common.utils.json;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.lz.common.utils.Constant;
import com.lz.common.utils.MapUtil;
import com.lz.common.utils.NumberUtil;
import com.lz.common.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @类描述：
 * @author suweili 2017年3月4日下午2:57:14
 * @注意：本内容仅限于杭州霖梓网络科技有限公司内部传阅，禁止外泄以及用于其他的商业目的
 */
public class JsonUtil {
    public static final Logger logger = LoggerFactory.getLogger(JsonUtil.class);

    private static ObjectMapper mapper = new ObjectMapper();
    private static ObjectMapper mapperWithYMDDate = new ObjectMapper();

    static {
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); //去掉默认的时间戳格式
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); //单引号处理
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //反序列化时，属性不存在的兼容处理
        mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false); //设置不写NULLmap值
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); //空值不序列化
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); //序列化时，日期的统一格式

        mapperWithYMDDate.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapperWithYMDDate.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        mapperWithYMDDate.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapperWithYMDDate.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapperWithYMDDate.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
    }


    public JsonUtil() {
    }

    public static String toJSONString(Object jsonObj) {
        return JSON.toJSONString(jsonObj);
    }

    public static String get(String jsonStr, String key) {
        if (!StringUtil.isBlank(jsonStr) && !StringUtil.isBlank(key)) {
            try {
                JSONObject obj = JSONObject.parseObject(jsonStr);
                return null == obj ? "" : StringUtil.isNull(obj.getString(key));
            } catch (Exception var3) {
                logger.error("转换JSON异常：" + jsonStr);
                return "";
            }
        } else {
            return "";
        }
    }

    public static String stringToJson(String s) {
        if (s == null) {
            return "{}";
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append("{\"");
            s = StringUtil.replace(s, "=", "\":\"");
            s = StringUtil.replace(s, "&", "\",\"");
            sb.append(s);
            sb.append("\"}");
            return sb.toString();
        }
    }

    public static String getTarget(String result) {
        String url = null;
        if (StringUtil.isNotEmpty(result) && result.contains("result")
                && result.contains("code") && result.contains("url")) {
            JSONObject obj = JSONObject.parseObject(result);
            String a = obj.get("result").toString();
            JSONObject b = JSONObject.parseObject(a);
            String c = b.get("code").toString();
            if ("1000".equals(c)) {
                String e = b.get("data").toString();
                JSONObject data = JSONObject.parseObject(e);
                url = data.get("url").toString();
            }
        }
        return url;
    }


    public static ObjectMapper getJsonMapper() {
        return mapper;
    }

    @SuppressWarnings("unchecked")
    public static <T> T parse(String value, Class<T> clz) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        try {
            T obj = mapper.readValue(value, clz);
            if (obj instanceof Map) {
                return (T) MapUtil.removeEmptyStr((Map<String, Object>) obj);
            }
            return obj;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static <T> T parseWithOnlyYMDDate(String value, Class<T> clz) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        try {
            return mapperWithYMDDate.readValue(value, clz);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static <T> T parse(byte[] bytes, Class<T> clz) {
        try {
            return mapper.readValue(bytes, clz);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static <T> T parse(InputStream ins, Class<T> clz) {
        try {
            return mapper.readValue(ins, clz);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static <T> T parse(Reader reader, Class<T> clz) {
        try {
            return mapper.readValue(reader, clz);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    @SuppressWarnings("unchecked")
    public static <T> T parse(String value, JavaType javaType) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }

        try {
            return (T) mapper.readValue(value, javaType);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T update(String value, T object) {
        try {
            return (T) mapper.readerForUpdating(object).readValue(value);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> domainToMap(Object o) {
        try {
            String str = mapper.writeValueAsString(o);
            return parse(str, Map.class);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static String writeValueAsString(Object o) {
        try {
            return mapper.writeValueAsString(o);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static void writeJson(Object obj, HttpServletResponse resp) {
        try {
            resp.setContentType("application/json");
            resp.setCharacterEncoding("utf8");
            PrintWriter pw = resp.getWriter();
            String str;
            if (!(obj instanceof String)) {
                str = toString(obj);
            } else {
                str = obj.toString();
            }
            pw.print(str);
            pw.flush();
            pw.close();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

    public static void write(OutputStream outs, Object o) {
        try {
            mapper.writeValue(outs, o);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static void write(Writer writer, Object o) {
        try {
            mapper.writeValue(writer, o);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static void writeWithOnlyYMDDate(Writer writer, Object o) {
        try {
            mapperWithYMDDate.writeValue(writer, o);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static String toString(Object o) {
        try {
            return mapper.writeValueAsString(o);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    public static byte[] toBytes(Object o) {
        try {
            return mapper.writeValueAsBytes(o);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 获取json字符串的值
     * @param json
     * @param key
     * @return
     */
    public static int getInt(String jsonStr, String key) {
        return NumberUtil.getInt(StringUtil.isNull(getValue(jsonStr, key)));
    }

    /**
     * 获取json字符串中的值
     * @param jsonStr
     * @param key
     * @return
     */
    public static double getDouble(String jsonStr, String key) {
        return NumberUtil.getDouble(StringUtil.isNull(getValue(jsonStr, key)));
    }

    private static Object getValue(String jsonStr, String key) {
        JSONObject json = null;
        try {
            json = JSON.parseObject(jsonStr);
            return json.get(key);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return "";
    }

    private JSONObject jsonObject;

    public static JsonUtil newJson() {
        JsonUtil jsonUtil = new JsonUtil();
        jsonUtil.jsonObject = new JSONObject();
        jsonUtil.jsonObject.put("message", Constant.OPERATION_SUCCESS);
        jsonUtil.jsonObject.put("code", Constant.SUCCEED_CODE_VALUE);
        return jsonUtil;
    }

    public static JsonUtil newFailJson() {
        JsonUtil jsonUtil = new JsonUtil();
        jsonUtil.jsonObject = new JSONObject();
        jsonUtil.jsonObject.put("message", Constant.OPERATION_FAIL);
        jsonUtil.jsonObject.put("code", Constant.FAIL_CODE_VALUE);
        return jsonUtil;
    }

    public JsonUtil addData(String key, Object value) {
        this.jsonObject.put(key, value);
        return this;
    }

    public JsonUtil addMessage(Object value) {
        this.jsonObject.put("message", value);
        return this;
    }

    public JsonUtil addCode(Object value) {
        this.jsonObject.put("code", value);
        return this;
    }

    public String toJsonString() {
        return this.jsonObject.toJSONString();
    }


    public JSON toJson() {
        return this.jsonObject;
    }

    public static <T> JavaType newListJavaType(Class<T> clz) {
        return getJsonMapper().getTypeFactory().constructParametricType(List.class, clz);
    }

    public static <T> JavaType newSetJavaType(Class<T> clz) {
        return getJsonMapper().getTypeFactory().constructParametricType(Set.class, clz);
    }

    public static <T, V> JavaType newMapJavaType(Class<T> keyClz, Class<V> valueClz) {
        return getJsonMapper().getTypeFactory().constructParametricType(Map.class, keyClz, valueClz);
    }


}
