package com.persagy.framework.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.DoubleConverter;
import org.apache.commons.beanutils.converters.FloatConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;

@SuppressWarnings({"rawtypes", "unchecked"})
public class BeanUtils {

	protected static final Log logger = LogFactory.getLog(BeanUtils.class);


	/**
	 * 通过get、set方法复制类属性，不复制为值null的属性
	 * @param fromObj
	 * @param toObj
	 * @throws Exception
	 */
	public static void copyBean(Object fromObj, Object toObj) throws Exception{
		Map<String, Object> mname_value = new HashMap<>();
		Map<String, Class> mname_Type = new HashMap<>();
		
		
		for(Method m : fromObj.getClass().getDeclaredMethods()) {
			String mname = m.getName();
			if(mname.startsWith("get") && m.getParameterTypes().length == 0) {
				mname = "set" + mname.substring(3);
				Object value = m.invoke(fromObj);
				if(value != null) {
					mname_value.put(mname, value);
					mname_Type.put(mname, value.getClass());
				}
			}
		}
		
		if(!mname_value.isEmpty()) {
			Class toClass = toObj.getClass();
			for(String setName : mname_value.keySet()) {
				Method m = toClass.getDeclaredMethod(setName, mname_Type.get(setName));
				if(m != null) {
					m.invoke(toObj, mname_value.get(setName));
				}
			}
		}
	}
	
	/**
	 * 按Filed的类型取得Field列表.
	 */
	public static List<Field> getFieldsByType(Object object, Class<?> type) {
		List<Field> list = new ArrayList<Field>();
		Field[] fields = object.getClass().getDeclaredFields();
		for (Field field : fields) {
			if (field.getType().isAssignableFrom(type)) {
				list.add(field);
			}
		}
		return list;
	}

	/**
	 * 获得field的getter函数名称.
	 */
	public static String getGetterName(Class<?> type, String fieldName) {
		Assert.notNull(type, "Type required");
		Assert.hasText(fieldName, "FieldName required");

		if (type.getName().equals("boolean")) {
			return "is" + StringUtils.capitalize(fieldName);
		} else {
			return "get" + StringUtils.capitalize(fieldName);
		}
	}

	/**
	 * 获得field的getter函数,如果找不到该方法,返回null.
	 */
	public static Method getGetterMethod(Class<?> type, String fieldName) {
		try {
			return type.getMethod(getGetterName(type, fieldName));
		} catch (NoSuchMethodException e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * bean属性复制
	 * @param dest 目的
	 * @param orig 源
	 * @return
	 */
	public static final Object copyProperties(Object dest, Object orig) {
		ConvertUtils.register(new DoubleConverter(null), Double.class);
		ConvertUtils.register(new FloatConverter(null), Float.class);
		ConvertUtils.register(new IntegerConverter(null), Integer.class);
		ConvertUtils.register(new LongConverter(null), Long.class);
		ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);
		if (orig != null) {
			try {
				org.apache.commons.beanutils.BeanUtils.copyProperties(dest, orig);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			dest = null;
		}
		return dest;
	}

	/**
	 * Bean属性复制，如果源对象的属性值为空，此方法会将空值复制到目标对象的相应属性上。
	 *
	 * @param dest 目标对象
	 * @param origi 源对象
	 */
	public static void copyPropertysWithNull(Object dest,Object origi){
		ConvertUtils.register(new DoubleConverter(null), Double.class);
		ConvertUtils.register(new FloatConverter(null), Float.class);
		ConvertUtils.register(new IntegerConverter(null), Integer.class);
		ConvertUtils.register(new LongConverter(null), Long.class);
		PropertyDescriptor[] destDescriptors=PropertyUtils.getPropertyDescriptors(dest);
	    PropertyDescriptor[] origiDescriptors=PropertyUtils.getPropertyDescriptors(origi);
	    List<String> origiPropertyNames=new ArrayList<String>();
	    for (int i=0; i<origiDescriptors.length; i++) {
	      origiPropertyNames.add(origiDescriptors[i].getName());
	    }
	    for (int i=0; i<destDescriptors.length; i++) {
	        PropertyDescriptor destProperty=destDescriptors[i];
	        String name=destProperty.getName();

	        try {
	            if (origiPropertyNames.contains(name)) {
	                Object value=PropertyUtils.getSimpleProperty(origi,name);
	                PropertyUtils.setSimpleProperty(dest,name,value);
	            }
	        }
	        catch (Exception ex) {
//	        	ex.printStackTrace();
	        }
	    }
	}
	/**
	 * Bean属性复制，如果源对象的属性值为" 非空"，此方法会将空值复制到目标对象的相应属性上
	 * @param dest
	 * @param origi
	 */
	public static void copyPropertysWithoutNull(Object dest,Object origi)
	{
		ConvertUtils.register(new DoubleConverter(null), Double.class);
		ConvertUtils.register(new FloatConverter(null), Float.class);
		ConvertUtils.register(new IntegerConverter(null), Integer.class);
		ConvertUtils.register(new LongConverter(null), Long.class);
		PropertyDescriptor[] destDescriptors=PropertyUtils.getPropertyDescriptors(dest);
	    PropertyDescriptor[] origiDescriptors=PropertyUtils.getPropertyDescriptors(origi);
	    List<String> origiPropertyNames=new ArrayList<String>();
	    for (int i=0; i<origiDescriptors.length; i++) {
	      origiPropertyNames.add(origiDescriptors[i].getName());
	    }
	    for (int i=0; i<destDescriptors.length; i++) {
	        PropertyDescriptor destProperty=destDescriptors[i];
	        String name=destProperty.getName();

	        try {
	            if (origiPropertyNames.contains(name)) {
	                Object value=PropertyUtils.getSimpleProperty(origi,name);
	                if(value!=null)//只复制非空值
	                	PropertyUtils.setSimpleProperty(dest,name,value);
	            }
	        }
	        catch (Exception ex) {
//	        	ex.printStackTrace();
	        }
	    }
	}
	/**
	 * 根据属性名和值在beanList中查找bean的位置,未找到时返回-1
	 * @param beanList list of bean
	 * @param propertyName 属性
	 * @param value 值
	 * @return
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 */
	public static int findInList(List<?> beanList,String propertyName,Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
	  for(int i=0;i<beanList.size();i++){
	    Object bean = beanList.get(i);
	    Object tmpValue = PropertyUtils.getProperty(bean,propertyName);
	    if (tmpValue == null){
	      if(value==null){
	        return i;
	      }
	    }else if(tmpValue.equals(value)){
	      return i;
	    }
	  }
	  return -1;
	}
  /**
   * 根据属性名和值在beanList中查找bean,未找到时返回null
   * @param beanList list of bean
   * @param propertyName 属性
   * @param value 值
   * @return
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   * @throws IllegalAccessException
   */
  public static Object findBean(List<?> beanList,String propertyName,Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
    for(int i=0;i<beanList.size();i++){
      Object bean = beanList.get(i);
      Object tmpValue = PropertyUtils.getProperty(bean,propertyName);
      if (tmpValue == null){
        if(value==null){
          return bean;
        }
      }else if(tmpValue.equals(value)){
        return bean;
      }
    }
    return null;
  }
  /**
   * 根据属性名和值在Collection中查找bean,未找到时返回null
   * @param collection Collection of bean
   * @param propertyName 属性
   * @param value 值
   * @return Object
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   * @throws IllegalAccessException
   */
  public static Object findBean(Collection<?> collection,String propertyName,Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
    for(Object bean : collection){
      Object tmpValue = PropertyUtils.getProperty(bean,propertyName);
      if (tmpValue == null){
        if(value==null){
          return bean;
        }
      }else if(tmpValue.equals(value)){
        return bean;
      }
    }
    return null;
  }

//  /**
//   * 判断string是否在集合中，只对Set<String>有效
//   * @return
//   */
//  public static boolean isStringInSet(Set<String> set, String string) {
//    boolean isIn=false;
//    for (String tmp : set) {
//      if (com.syswin.crm.framework.common.util.StringUtils.equalsWithNull(tmp,string)) {
//        isIn=true;
//        return isIn;
//      }
//    }
//    return isIn;
//  }
  /**
   * 判断Object是否在集合中，只对实现了equals方法的类有效
   * @return
   */
  public static boolean isObjectInSet(Set<Object> set, Object object) {
    boolean isIn=false;
    for (Object tmp : set) {
      if (object==null) {
        if (tmp==null) {
          return true;
        }
      }
      else if (tmp.equals(object)) {
        isIn=true;
        return isIn;
      }
    }
    return isIn;
  }

  /**
   * 根据属性名和值在Collection中查找bean,未找到时返回null
   * @param collection Collection of bean
   * @param propertyName 属性
   * @param value 值
   * @return Object
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   * @throws IllegalAccessException
   */
  public static Object findBean(Collection<?> collection,String[] propertyNameArray,Object[] valueArray) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
	  for(Object bean : collection){
		  boolean isEqual=true;
		  for(int i=0;i<propertyNameArray.length;i++){
			  String propertyName = propertyNameArray[i];
			  Object value = valueArray[i];

		      Object tmpValue = PropertyUtils.getProperty(bean,propertyName);
		      if (tmpValue == null){
		        if(value==null){
		          continue;
		        }else{
		          isEqual=false;
		          break;
		        }
		      }else if(tmpValue.equals(value)){
		        continue;
		      }else{
		    	  isEqual=false;
		    	  break;
		      }
		  }
		  if (isEqual){
			  return bean;
		  }
	}
	return null;
  }

}