package com.yiqiniu.easytrans.util;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;

import org.springframework.util.StringUtils;

public class ObjectDigestUtil {
	
	private ObjectDigestUtil(){
	}
	
	private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
           "8", "9", "a", "b", "c", "d", "e", "f"};

   
//   private static Logger LOG = LoggerFactory.getLogger(MD5.class);
   
   /**
    * 转换字节数组为16进制字串
    * @param b 字节数组
    * @return 16进制字串
    */
   private static String byteArrayToHexString(byte[] b) {
       StringBuilder resultSb = new StringBuilder();
       for (byte aB : b) {
           resultSb.append(byteToHexString(aB));
       }
       return resultSb.toString();
   }

   /**
    * 转换byte到16进制
    * @param b 要转换的byte
    * @return 16进制格式
    */
   private static String byteToHexString(byte b) {
       int n = b;
       if (n < 0) {
           n = 256 + n;
       }
       int d1 = n / 16;
       int d2 = n % 16;
       return hexDigits[d1] + hexDigits[d2];
   }
	
	public static String getObjectMD5(Object obj) {
		return MD5Encode(getObjectString(obj));
	}

	/**
	 * MD5编码
	 * 
	 * @param origin
	 *            原始字符串
	 * @return 经过MD5加密之后的结果
	 */
	public static String MD5Encode(String origin) {
		String resultString = null;
		try {
			resultString = origin;
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(resultString.getBytes("UTF-8"));
			resultString = byteArrayToHexString(md.digest());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return resultString;
	}

	/**
	 * 将Object按照key1=value1&key2=value2的形式拼接起来，程序不递归。Value需为基本类型，
	 * 或者其toString方法能表示其实际的值
	 * 
	 * @param o
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static String getObjectString(Object o) {

		if (isBasicType(o)) {
			return o.toString();
		} else if (o.getClass().isArray()) {
			return getArrayValue((Object[]) o);
		} else if (o instanceof Iterable) {
			Iterable itrPropertie = (Iterable) o;
			return getItrValue(itrPropertie);
		} else if (o instanceof Map) {
			return getOrderedMapString((Map) o);
		} else {
			return getComlpexObjectOrderedString(o);
		}
	}

	private static String getComlpexObjectOrderedString(Object o) {
		ArrayList<String> list = new ArrayList<String>();
		try {
			// LOG.error("检测：" + JSONUtil.toJson(o));
			PropertyDescriptor[] propertyDescriptors = Introspector
					.getBeanInfo(o.getClass(), Object.class)
					.getPropertyDescriptors();
			for (PropertyDescriptor f : propertyDescriptors) {

				Object propertie = f.getReadMethod().invoke(o);
				if (propertie != null) {
					String objectString = getObjectString(propertie);
					if (!StringUtils.isEmpty(objectString)) {
						list.add(f.getName() + "=" + objectString + "&");
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}

		return "{" + sb.toString() + "}";
	}

	@SuppressWarnings("rawtypes")
	private static String getItrValue(Iterable propertie) {

		StringBuilder result = new StringBuilder();
		result.append("[");

		Iterator iterator = propertie.iterator();
		while (iterator.hasNext()) {
			Object next = iterator.next();
			result.append(getObjectString(next) + ",");
		}
		result.append("]");

		return result.toString();
	}

	private static String getArrayValue(Object[] propertie) {
		StringBuilder result = new StringBuilder();
		result.append("[");
		for (Object o : propertie) {
			result.append(getObjectString(o) + ",");
		}
		result.append("]");
		return result.toString();
	}

	/**
	 * 将Object按照key1=value1&key2=value2的形式拼接起来，程序不递归。Value需为基本类型，
	 * 或者其toString方法能表示其实际的值
	 * 
	 * @param o
	 * @return
	 */
	private static String getOrderedMapString(Map<Object, Object> map) {
		ArrayList<String> list = new ArrayList<String>();
		for (Map.Entry<Object, Object> entry : map.entrySet()) {
			if (entry.getValue() != null) {
				Object key = entry.getKey();
				Object value = entry.getValue();
				String objectString = getObjectString(value);
				if (!StringUtils.isEmpty(objectString)) {
					list.add(getObjectString(key) + "=" + objectString + "&");
				}

			}
		}
		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}
		return "{" + sb.toString() + "}";
	}

	private static boolean isBasicType(Object o) {
		if (o instanceof String) {
			return true;
		}
		if (o instanceof Integer) {
			return true;
		}
		if (o instanceof Long) {
			return true;
		}
		if (o instanceof Float) {
			return true;
		}
		if (o instanceof Double) {
			return true;
		}
		if (o instanceof Byte) {
			return true;
		}
		if (o instanceof Boolean) {
			return true;
		}
		if (o instanceof Enum) {
			return true;
		}
		if (o instanceof BigDecimal) {
			return true;
		}
		return false;
	}

}

@@ -276,16 +276,40 @@
 il.Map;%0D
+%0Aimport java.util.Date;%0D
 %0A%0D%0Aimpor
@@ -2398,24 +2398,84 @@
 ((Map) o);%0D%0A
+%09%09%7D else if (o instanceof Date) %7B%0D%0A%09%09%09return o.toString();%0D%0A
 %09%09%7D else %7B%0D%0A

修复消息实体类中包含java.sql.Date类型时报错的问题