package xiaoqu.home.open.utils;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.swagger.annotations.ApiModelProperty;
import xiaoqu.home.open.model.db1.User;

public class ClassCompareUtil {
	public static void main(String[] args) {
		User User1 = new User();
		User1.setName("开心就安徽");
		User1.setMobile("1581093427");
		User User2 = new User();
		User2.setName("开心就安徽2222");
		User2.setMobile("158109342722");
		System.out.println(compareFields(User1, User2, null));
//		User2.setCreateTime(new Date());
//		System.out.println(compareFields(User1, User2,null));
	}

	/**
	 * 比较两个实体属性值，返回一个boolean,true则表时两个对象中的属性值无差异
	 * 
	 * @param oldObject 进行属性比较的对象1
	 * @param newObject 进行属性比较的对象2
	 * @return 属性差异比较结果Map
	 */
	public static boolean compareObject(String mac, Object oldObject, Object newObject, List<String> excludeParams) {
		Map<String, Object> returnMap = new HashMap<String, Object>();
		Map<String, Map<String, Object>> resultMap = compareFields(oldObject, newObject, excludeParams);
		returnMap.put("resultMap", resultMap);
		if (resultMap.size() > 0) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 比较两个实体属性值，返回一个map以有差异的属性名为key，value为一个Map分别存oldObject,newObject此属性名的值
	 * 
	 * @param oldObject 进行属性比较的对象1
	 * @param newObject 进行属性比较的对象2
	 * @return 属性差异比较结果map
	 */
	@SuppressWarnings("rawtypes")
	public static Map<String, Map<String, Object>> compareFields(Object oldObject, Object newObject, List<String> excludeParams) {
		Map<String, Map<String, Object>> map = null;

		try {
			/**
			 * 只有两个对象都是同一类型的才有可比性
			 */
			if (oldObject.getClass() == newObject.getClass()) {
				map = new HashMap<String, Map<String, Object>>();

				Class clazz = oldObject.getClass();
				// 获取object的所有属性
				PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors();
				Field[] allFields = clazz.getDeclaredFields();
				Map<String, String> nameToChineseName = new HashMap<String, String>();
				for (Field field : allFields) {
					ApiModelProperty attr = field.getAnnotation(ApiModelProperty.class);
					if (attr != null) {
						nameToChineseName.put(field.getName(), attr.value());
					}
				}

				for (PropertyDescriptor pd : pds) {
					// 遍历获取属性名
					String name = pd.getName();
					if (name.equals("id") ||name.equals("createId") ||name.equals("createTime") || name.equals("createName")
							||name.equals("modifyId")|| name.equals("modifyTime") || name.equals("modifyName")
							||name.equals("softDelete")) {
						//上述字段不比较
						continue;
					}

					if (excludeParams != null && excludeParams.contains(name)) {
						continue;
					}

					// 获取属性的get方法
					Method readMethod = pd.getReadMethod();

					// 在oldObject上调用get方法等同于获得oldObject的属性值
					Object oldValue = readMethod.invoke(oldObject);
					// 在newObject上调用get方法等同于获得newObject的属性值
					Object newValue = readMethod.invoke(newObject);

					if (oldValue instanceof List) {
						continue;
					}

					if (newValue instanceof List) {
						continue;
					}

					if (oldValue instanceof Timestamp) {
						oldValue = new Date(((Timestamp) oldValue).getTime());
					}

					if (newValue instanceof Timestamp) {
						newValue = new Date(((Timestamp) newValue).getTime());
					}

					if (oldValue == null && newValue == null) {
						continue;
					} else if (oldValue == null && newValue != null) {
						Map<String, Object> valueMap = new HashMap<String, Object>();
						valueMap.put("修改前", oldValue);
						valueMap.put("修改后", newValue);
						map.put(nameToChineseName.get(name), valueMap);
						continue;
					}
					if (!oldValue.equals(newValue)) {// 比较这两个值是否相等,不等就可以放入map了
						Map<String, Object> valueMap = new HashMap<String, Object>();
						valueMap.put("修改前", oldValue);
						valueMap.put("修改后", newValue);
						map.put(nameToChineseName.get(name), valueMap);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}
}
