package cn.hmsoft.helper;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**********************
 * Bean 辅助类 ，使用Apache的BeanUtils
 * 
 * @author zxq
 * @create 2019-05-06 09:24:00
 * @version 2.0.0
 * @email: revisit@126.com
 * @Company: www.hmsoft.cn
 */
public class BeanHelper {

	/*********************
	 * 
	 * @param entity
	 * @param class_name
	 *            是否转换成tableName格式
	 * @return
	 */
	public static Map<String, String> toStringMap(Object entity, boolean class_name) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		Class<?> clazz = entity.getClass();
		while (!clazz.getSimpleName().equalsIgnoreCase("Object")) {
			for (Field f : clazz.getDeclaredFields()) {
				// 只处理private 修饰符
				// if (f.getModifiers() != 2)
				// continue;
				f.setAccessible(true);
				try {
					Object o = f.get(entity);
					if (o == null)
						continue;
					map.put(class_name ? StringHelper.toClassName(f.getName()) : f.getName(), o.toString());
				} catch (Exception e) {
				}
			}
			clazz = clazz.getSuperclass();
		}

		return map;
	}

	public static Map<String, String> toStringMap(Object entity) {
		return toStringMap(entity, false);
	}

	/********************************************************
	 * 将实体类的所有protected属性放置到map中，属性值为null的排除在外
	 * 
	 * @param entity
	 *            表对应的实体类
	 */
	public static Map<String, Object> toMap(Object entity) {
		return toMap(entity, false);
	}

	/**************************************************************
	 * 将实体类的所有protected属性放置到map中，属性值为null的排除在外
	 * 
	 * @param entity
	 *            表对应的实体类
	 * @param nullable
	 *            是否包含值为null的属性
	 * @return
	 */
	public static Map<String, Object> toMap(Object entity, boolean nullable) {
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		if (entity == null)
			return map;
		// 递归获取父类
		Class<?> clazz = entity.getClass();
		while (!clazz.getSimpleName().equalsIgnoreCase("Object")) {
			for (Field f : clazz.getDeclaredFields()) {
				// 只处理private 修饰符
				if (f.getModifiers() != 2)
					continue;
				f.setAccessible(true);
				try {
					Object o = f.get(entity);
					if (o == null && !nullable)
						continue;
					map.put(f.getName(), o);
				} catch (Exception e) {
				}
			}
			clazz = clazz.getSuperclass();
		}

		return map;
	}

	public static <T> T fromMap(Map<String, Object> map, Class<T> clazz) {
		T entity = null;
		try {
			entity = (T) clazz.newInstance();
		} catch (Exception e) {
		}
		if (entity == null)
			return null;
		for (Field f : clazz.getDeclaredFields()) {
			// 只处理private 修饰符
			if (f.getModifiers() != 2)
				continue;
			if (!map.containsKey(f.getName()))
				continue;
			f.setAccessible(true);
			try {
				Object o = map.get(f.getName());
				if (o == null)
					continue;
				setFiledValue(entity, f, o);
			} catch (Exception e) {
			}
		}
		return entity;
	}

	/**********************************
	 * 拷贝属性
	 */
	public static <T> T copy(Class<T> clazz, Object object) {
		T entity = null;
		try {
			entity = clazz.newInstance();
		} catch (Exception e) {
		}
		if (entity == null)
			return null;
		if (object == null)
			return entity;
		for (Field field : object.getClass().getDeclaredFields()) {
			Field cField = null;
			try {
				cField = clazz.getDeclaredField(field.getName());
			} catch (Exception e) {
			}
			if (cField == null)
				continue;
			field.setAccessible(true);
			cField.setAccessible(true);
			try {
				cField.set(entity, field.get(object));
			} catch (Exception e) {

			}
		}
		return entity;
	}

	/************************************************************
	 * 设置clazz类型的静态变量
	 */
	public static void setStaticFields(Class<?> clazz, Map<String, ?> paramMap) {
		// 递归对父类进行赋值
		Class<?> superClass = clazz.getSuperclass();
		if (!superClass.equals(Object.class)) {
			setStaticFields(superClass, paramMap);
		}
		// 设置自身的类型
		// Class.getFields(): 获取类中public类型的属性，返回一个包含某些 Field 对象的数组，该数组包含此 Class
		// 对象所表示的类或接口的所有可访问公共字段
		// getDeclaredFields(): 获取类中所有的属性(public、protected、default、private)，但不包括继承的属性，返回
		// Field 对象的一个数组
		for (Field field : clazz.getDeclaredFields()) {
			if ((field.getModifiers() == 9 || field.getModifiers() == 10) && paramMap.containsKey(field.getName())) {
				// 设置为可修改属性
				try {
					setFiledValue(null, field, paramMap.get(field.getName()));
				} catch (Exception e) {

				}
			}
		}

	}

	/***********
	 * 通过方法设置属性值
	 * 
	 * @param entity
	 * @param fieldName
	 * @param value
	 */
	public static void beanFromDataRecord(Object entity, String fieldName, Object value) {
		Field field = null;
		Class<?> clazz = entity.getClass();
		// 一直追溯到object
		while (field == null && !clazz.equals(Object.class)) {
			try {
				field = entity.getClass().getDeclaredField(fieldName);
			} catch (Exception e) {

			}
			clazz = clazz.getSuperclass();
		}

		if (field == null) {
			// 没有设置字段对应的属性
			return;
		}
		setFiledValue(entity, field, value);

	}

	/*******************
	 * 设置对象属性值
	 * 
	 * @param object
	 *            对象
	 * @param field
	 *            属性
	 * @param value
	 *            值
	 */
	public static void setFiledValue(Object object, Field field, Object value) {
		setFiledValue(object, field, value, false);
	}

	/***********************************************************************************
	 * 反射设置属性值
	 * 
	 * @param object
	 *            需要设置的对象
	 * @param field
	 *            属性
	 * @param value
	 *            值
	 * @param nullable
	 *            是否允许设置空值
	 */

	public static void setFiledValue(Object object, Field field, Object value, boolean nullable) {

		try {
			field.setAccessible(true);
		} catch (Exception e) {

		}
		// 判断是否允许设置null值
		if (value == null) {
			if (nullable)
				try {
					field.set(object, null);
				} catch (Exception e) {

				}
			return;
		}

		try {
			Class<?> fClass = field.getType();
			// 如果类型相同，纸质设置
			if (fClass.equals(value.getClass())) {
				field.set(object, value);
				return;
			}
			String vValue = value.toString();
			if (fClass.equals(String.class)) {
				field.set(object, vValue);
				return;
			}

			if (fClass.equals(Integer.class) || fClass.equals(int.class)) {
				field.set(object, Integer.parseInt(vValue));
				return;
			}

			if (fClass.equals(Float.class) || fClass.equals(float.class)) {
				field.set(object, Float.parseFloat(vValue));
				return;
			}

			if (fClass.equals(Double.class) || fClass.equals(double.class)) {
				field.set(object, Double.parseDouble(vValue));
				return;
			}
			if (fClass.equals(BigDecimal.class)) {
				field.set(object, BigDecimal.valueOf(Double.parseDouble(vValue)));
				return;
			}
			if (fClass.equals(Boolean.class) || fClass.equals(boolean.class)) {
				String v = value.toString();
				if (v.equalsIgnoreCase("false")) {
					field.set(object, false);
					return;
				}
				if (v.equalsIgnoreCase("true")) {
					field.set(object, true);
					return;
				}
				// 其他字符，大于0的数字为true，其他全部设置为false
				double sValue = 0;
				try {
					sValue = Double.parseDouble(value.toString());
				} catch (Exception e) {
					sValue = 0;
				}
				if (sValue > 0)
					field.set(object, true);
				else
					field.set(object, false);
				return;
			}
			// 直接设置
			// try {
			// field.set(object, value);
			// return;
			// } catch (Exception e) {
			// e.printStackTrace();
			// }

			// 传统日期
			if (fClass.equals(Date.class)) {
				// 日期格式
				// 20190101 8位长度
				// 2019-01-01 10位
				// 20190101000000 14位
				// 2019-01-01 00:00:00 19位
				// 1557131260099 13位 毫秒
				// 没有分隔符
				if (vValue.length() == 8)
					field.set(object, DateHelper.getFormatter(DateHelper.ShortDateStringWithoutSplit).parse(vValue));
				else if (vValue.length() == 10)
					field.set(object, DateHelper.getFormatter(DateHelper.ShortDateString).parse(vValue));
				else if (vValue.length() == 13)
					field.set(object, new Date(Long.parseLong(vValue)));
				else if (vValue.length() == 14)
					field.set(object, DateHelper.getFormatter(DateHelper.LongDateStringWithoutSplit).parse(vValue));
				else if (vValue.length() == 19)
					field.set(object, DateHelper.getFormatter(DateHelper.LongDateString).parse(vValue));
				return;
			}

			// 1.8 的LocalDateTime
			if (fClass.equals(LocalDateTime.class)) {
				// 20190101 8位长度
				// 2019-01-01 10位
				// 20190101000000 14位
				// 2019-01-01 10位
				// 2019-01-01 00:00:00 19位
				// 1557131260099 13位 毫秒
				if (vValue.indexOf("T") > -1) {
					if (vValue.length() == 23) {
						// 2020-02-22T14:27:21.650
						field.set(object, LocalDateHelper.parseDateTime(vValue.replace("T", ""),
								LocalDateHelper.ISO8061Formatter));
					} else if (vValue.length() == 19) {
						// 2020-02-22T14:27:21
						field.set(object, LocalDateHelper.parseDateTime(vValue.replace("T", " ")));
					} else if (vValue.length() == 16) {
						// 2020-02-23T01:13
						field.set(object, LocalDateHelper.parseDateTime(vValue.replace("T", " ") + ":00"));
					}

				} else if (vValue.length() == 8)
					field.set(object,
							LocalDateHelper.toLocalDateTime(LocalDateHelper.parseDateNoSplit(vValue), LocalTime.MIN));
				else if (vValue.length() == 10)
					field.set(object,
							LocalDateHelper.toLocalDateTime(LocalDateHelper.parseDate(vValue), LocalTime.MIN));
				else if (vValue.length() == 13)
					field.set(object, LocalDateHelper.fromMillis(Long.parseLong(vValue)));
				else if (vValue.length() == 14)
					field.set(object, LocalDateHelper.parseDateTimeNoSplit(vValue));
				else if (vValue.length() == 19)
					field.set(object, LocalDateHelper.parseDateTime(vValue));

				return;
			}
			if (fClass.equals(LocalDate.class)) {
				if (vValue.length() == 8)
					field.set(object, LocalDateHelper.parseDateNoSplit(vValue));
				else if (vValue.length() == 10)
					field.set(object, LocalDateHelper.parseDate(vValue));
				else if (vValue.length() == 13)
					field.set(object, LocalDateHelper.fromMillis(Long.parseLong(vValue)).toLocalDate());
				else if (vValue.length() == 14)
					field.set(object, LocalDateHelper.parseDateTimeNoSplit(vValue).toLocalDate());
				else if (vValue.length() == 19)
					field.set(object, LocalDateHelper.parseDateTime(vValue).toLocalDate());
				return;

			}
			if (fClass.equals(LocalTime.class)) {
				// 00:00:00
				if (vValue.length() == 8)
					field.set(object, LocalDateHelper.parseTime(vValue));
				else if (vValue.length() == 13)
					field.set(object, LocalDateHelper.fromMillis(Long.parseLong(vValue)).toLocalTime());
				else if (vValue.length() == 14)
					field.set(object, LocalDateHelper.parseDateTimeNoSplit(vValue).toLocalTime());
				else if (vValue.length() == 19)
					field.set(object, LocalDateHelper.parseDateTime(vValue).toLocalTime());
				return;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
