package com.bocloud.ims.service.utils;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

public class BeanUtils {

    public static Field findField(Class<?> clazz, String name) {
        try {
            return clazz.getField(name);
        } catch (NoSuchFieldException ex) {
            return findDeclaredField(clazz, name);
        }
    }

    public static Field findDeclaredField(Class<?> clazz, String name) {
        try {
            return clazz.getDeclaredField(name);
        } catch (NoSuchFieldException ex) {
            if (clazz.getSuperclass() != null) {
                return findDeclaredField(clazz.getSuperclass(), name);
            }
            return null;
        }
    }

    public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
        try {
            return clazz.getMethod(methodName, paramTypes);
        } catch (NoSuchMethodException ex) {
            return findDeclaredMethod(clazz, methodName, paramTypes);
        }
    }

    public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
        try {
            return clazz.getDeclaredMethod(methodName, paramTypes);
        } catch (NoSuchMethodException ex) {
            if (clazz.getSuperclass() != null) {
                return findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes);
            }
            return null;
        }
    }

    public static Object getProperty(Object obj, String name) throws NoSuchFieldException {
        Object value = null;
        Field field = findField(obj.getClass(), name);
        if (field == null) {
            throw new NoSuchFieldException("no such field [" + name + "]");
        }
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        try {
            value = field.get(obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        field.setAccessible(accessible);
        return value;
    }

    public static void setProperty(Object obj, String name, Object value) throws NoSuchFieldException {
        Field field = findField(obj.getClass(), name);
        if (field == null) {
            throw new NoSuchFieldException("no such field [" + name + "]");
        }
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        try {
            field.set(obj, value);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        field.setAccessible(accessible);
    }

    public static Map<String, Object> obj2Map(Object obj, Map<String, Object> map) {
        if (map == null) {
            map = new HashMap<String, Object>();
        }
        if (obj != null) {
            try {
                Class<?> clazz = obj.getClass();
                do {
                    Field[] fields = clazz.getDeclaredFields();
                    for (Field field : fields) {
                        int mod = field.getModifiers();
                        if (Modifier.isStatic(mod)) {
                            continue;
                        }
                        boolean accessible = field.isAccessible();
                        field.setAccessible(true);
                        map.put(field.getName(), field.get(obj));
                        field.setAccessible(accessible);
                    }
                    clazz = clazz.getSuperclass();
                } while (clazz != null);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return map;
    }

    /**
     * 获得父类集合，包含当前class
     *
     * @param clazz
     * @return
     */
    public static List<Class<?>> getSuperclassList(Class<?> clazz) {
        List<Class<?>> clazzes = new ArrayList<Class<?>>(3);
        clazzes.add(clazz);
        clazz = clazz.getSuperclass();
        while (clazz != null) {
            clazzes.add(clazz);
            clazz = clazz.getSuperclass();
        }
        return Collections.unmodifiableList(clazzes);
    }

    /**
     * 获取某个对象的属性 必须有get方法
     *
     * @param provide
     * @param property
     * @return
     */
    public static Object getProperties(Object provide, String property) {
        Object tempValue = null;
        Method[] mm = provide.getClass().getMethods();
        for (int i = 0; i < mm.length; i++) {
            if (mm[i].getName().toUpperCase().equals("GET" + property.toUpperCase())) {
                Method cm = mm[i];
                try {
                    Object[] args = null;
                    tempValue = cm.invoke(provide, args);
                } catch (IllegalAccessException ex) {
                } catch (IllegalArgumentException ex) {
                } catch (InvocationTargetException ex) {
                }
                break;
            }
        }
        return tempValue;
    }

    public static void setProperties(Object accept, Object data, String property) {
        Method[] mm = accept.getClass().getMethods();
        for (int i = 0; i < mm.length; i++) {
            if (mm[i].getName().toUpperCase().equals("SET" + property.toUpperCase())) {
                Method cm = mm[i];
                Class[] acls = cm.getParameterTypes();
                if (acls.length != 1) {
                    continue;
                }
                Class cls = acls[0];
                // 实在是不知道下面这行infoEncode是啥意思，相关人员也离职了
                //Object val = infoEncode(data, cls);
                //Object[] args = {val};
                Object[] args = {data};
                try {
                    cm.invoke(accept, args);
                } catch (IllegalAccessException ex) {
                } catch (IllegalArgumentException ex) {
                } catch (InvocationTargetException ex) {
                }
                break;
            }
        }
    }

    /**
     * 将Object obj转换成需要的Class类型
     */
    public static Object infoEncode(Object obj, Class cls) {
        String pVal = String.valueOf(obj);
        return infoEncode(pVal, cls);
    }

    public static String[] getNullPropertyNames (Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    public static void copyPropertiesIgnoreNull(Object src, Object target){
        org.springframework.beans.BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
    }

}