package cn.hmsoft.helper;

import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.reflect.TypeToken;


/*****************************
 * @note JSON工具，使用GSON
 * @author revisit@126.com
 * @Company: www.hmsoft.cn
 * @create 2017-05-04 23:38:33
 * @version 4.0.0
 */
public abstract class JsonHelper {
	static class ParameterizedTypeImpl implements ParameterizedType {
		private final Class<?> raw;
		private final Type[] args;

		public ParameterizedTypeImpl(Class<?> raw, Type[] args) {
			this.raw = raw;
			this.args = args != null ? args : new Type[0];
		}

		@Override
		public Type[] getActualTypeArguments() {
			return args;
		}

		@Override
		public Type getRawType() {
			return raw;
		}

		@Override
		public Type getOwnerType() {
			return null;
		}
	}
	
	public static Gson createJson() {
		return new GsonBuilder().disableHtmlEscaping()
				.registerTypeAdapter(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
			@Override
			public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
				return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
			}
		}).registerTypeAdapter(LocalDate.class, new JsonSerializer<LocalDate>() {
			@Override
			public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
				return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
			}
		}).registerTypeAdapter(LocalTime.class, new JsonSerializer<LocalTime>() {
			@Override
			public JsonElement serialize(LocalTime src, Type typeOfSrc, JsonSerializationContext context) {
				return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("HH:mm:ss")));
			}
		}).registerTypeAdapter(java.sql.Timestamp.class, new JsonSerializer<java.sql.Timestamp>() {
			@Override
			public JsonElement serialize(java.sql.Timestamp src, Type typeOfSrc, JsonSerializationContext context) {
				return new JsonPrimitive(src.toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
			}
		}).registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
			@Override
			public LocalDateTime deserialize(JsonElement json, Type type,
					JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
				String datetime = json.getAsJsonPrimitive().getAsString();
				return LocalDateTime.parse(datetime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
			}
		}).registerTypeAdapter(LocalDate.class, new JsonDeserializer<LocalDate>() {
			@Override
			public LocalDate deserialize(JsonElement json, Type type,
					JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
				String datetime = json.getAsJsonPrimitive().getAsString();
				return LocalDate.parse(datetime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
			}
		}).registerTypeAdapter(LocalTime.class, new JsonDeserializer<LocalTime>() {
			@Override
			public LocalTime deserialize(JsonElement json, Type type,
					JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
				String datetime = json.getAsJsonPrimitive().getAsString();
				return LocalTime.parse(datetime, DateTimeFormatter.ofPattern("HH:mm:ss"));
			}
		}).create();
	}

	

	public static Gson GSON_FULL_TIME = new GsonBuilder()
			.registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
				@Override
				public LocalDateTime deserialize(JsonElement json, Type type,
						JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
					String datetime = json.getAsJsonPrimitive().getAsString();
					return LocalDateTime.parse(datetime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
				}
			}).registerTypeAdapter(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
				@Override
				public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
					return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
				}
			}).registerTypeAdapter(LocalDate.class, new JsonDeserializer<LocalDate>() {
				@Override
				public LocalDate deserialize(JsonElement json, Type type,
						JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
					String datetime = json.getAsJsonPrimitive().getAsString();
					return LocalDate.parse(datetime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
				}
			}).registerTypeAdapter(LocalDate.class, new JsonSerializer<LocalDate>() {
				@Override
				public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
					return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
				}
			}).registerTypeAdapter(LocalTime.class, new JsonDeserializer<LocalTime>() {
				@Override
				public LocalTime deserialize(JsonElement json, Type type,
						JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
					String time = json.getAsJsonPrimitive().getAsString();
					return LocalTime.parse(time, DateTimeFormatter.ofPattern("HH:mm:ss"));
				}
			}).setDateFormat("yyyy-MM-dd HH:mm:ss").create();

	// 时间格式是 yyyy-MM-dd
	public static Gson GSON_SHORT_DATE = new GsonBuilder()
			.registerTypeAdapter(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
				@Override
				public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
					return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
				}
			}).registerTypeAdapter(LocalDate.class, new JsonSerializer<LocalDate>() {
				@Override
				public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
					return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
				}
			}).registerTypeAdapter(LocalTime.class, new JsonSerializer<LocalTime>() {
				@Override
				public JsonElement serialize(LocalTime src, Type typeOfSrc, JsonSerializationContext context) {
					return new JsonPrimitive(src.format(DateTimeFormatter.ofPattern("HH:mm:ss")));
				}
			}).setDateFormat("yyyy-MM-dd").create();

	/*******************************************
	 * JSON字符串到数组,长时间格式
	 */
	public static <T> List<T> fromJson(String json, Class<T> clazz) {
		Type type = new ParameterizedTypeImpl(List.class, new Class[] { clazz });
		return GSON_FULL_TIME.fromJson(json, type);
	}

	/*******************************************
	 * JSON字符串到数组,长时间格式
	 */
	public static <T> List<T> fromJson(Reader reader, Class<T> clazz) {
		Type type = new ParameterizedTypeImpl(List.class, new Class[] { clazz });
		return GSON_FULL_TIME.fromJson(reader, type);
	}

	/*******************************************
	 * JSON字符串到数组,长时间格式
	 */
	public static <T> List<T> fromJsonWithShortDate(String json, Class<T> clazz) {
		Type type = new ParameterizedTypeImpl(List.class, new Class[] { clazz });
		return GSON_SHORT_DATE.fromJson(json, type);
	}

	/*******************************************
	 * JSON字符串到数组,长时间格式
	 */
	public static <T> List<T> fromJsonWithShortDate(Reader reader, Class<T> clazz) {
		Type type = new ParameterizedTypeImpl(List.class, new Class[] { clazz });
		return GSON_SHORT_DATE.fromJson(reader, type);
	}

	/****************************************
	 * 将一个对象重新转换为Json串,日期为长时间格式
	 */
	public static String fromObject(Object o) {
		return GSON_FULL_TIME.toJson(o);
	}

	/****************************************
	 * 将一个对象重新转换为Json串,日期为短日期格式
	 */
	public static String fromObjectWithShortDate(Object o) {
		return GSON_SHORT_DATE.toJson(o);
	}

	/****************************************
	 * 将一个对象重新转换为Json串,不替换特殊字符,长时间格式
	 */
	public static String fromObjectWithChar(Object o) {
		Gson gs = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
		return gs.toJson(o);
	}

	/**
	 * 将JSON字符串转换为一个JavaBean对象
	 */
	public static <T> T toObject(String json, Class<T> cls) {
		return GSON_FULL_TIME.fromJson(json, cls);
	}

	/**
	 * 将JSON字符串转换为一个JavaBean对象
	 */
	public static <T> T toObjectWithShortDate(String json, Class<T> cls) {
		return GSON_SHORT_DATE.fromJson(json, cls);
	}

	/**********************************
	 * 将json字符串转换到Map中
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Map<String, String> toMap(String json) {
		Type t = (new TypeToken<HashMap<String, String>>() {
		}).getType();
		Map r = (Map) GSON_FULL_TIME.fromJson(json, t);
		return r;
	}
	
	/**********************************
	 * 将json字符串转换到List中
	 * @param <T>
	 */
	public static <T> List<T> toList(String json,Type type) {
		List<T> l = GSON_FULL_TIME.fromJson(json, type);
		return l;
	}
	

	/**********************************
	 * 将json字符串转换到Map中
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static <T, K> Map<T, K> toMap(String json, Type type) {
		Map r = (Map) GSON_FULL_TIME.fromJson(json, type);
		return r;
	}

	/**********************************
	 * 将json字符串转换到Map中
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Map<String, String> toMapWithShortDate(String json) {
		Type t = (new TypeToken<HashMap<String, String>>() {
		}).getType();
		Map r = (Map) GSON_SHORT_DATE.fromJson(json, t);
		return r;
	}

	/**********************************
	 * 将json字符串转换到Map中
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static <T, K> Map<T, K> toMapWithShortDate(String json, Type type) {
		Map r = (Map) GSON_SHORT_DATE.fromJson(json, type);
		return r;
	}

}
