package com.community.commom.utils;

import jodd.bean.BeanCopy;
import jodd.typeconverter.TypeConverterManager;
import org.apache.commons.collections.BeanMap;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.Assert;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;

@SuppressWarnings("deprecation")
public final class BeanTools {

    private static Map<String, Object> toBeanMethodMap = new HashMap<String, Object>();

    /**
     * <pre>
     * 功能：实现BEAN的属性对拷
     * 创建人：JokenWang
     * </pre>
     *
     * @param fromBean        待转换的源bean
     * @param toBeanClassName 转换成目标bean的名称 形如：ItemSeries.class.getName()
     * @return 目标BEAN类
     */
    public static <T> T convertBean(Object fromBean, Class<T> toBeanClassName) {
        T toBean = null;
        try {
            toBean = getBeanInstance(toBeanClassName.getName());
            return convertBean(fromBean, toBean);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return toBean;
    }

    private static <T> T convertBean(Object fromBean, T toBean) {
        TypeConverterManager.register(String.class, new StringConverter());
        BeanCopy.beans(fromBean, toBean).copy();
        return toBean;
    }

    public static Method getDeclaredMethod(Object object, String methodName, Class<?>... parameterTypes) {
        Method method;
        for (Class<?> clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                method = clazz.getDeclaredMethod(methodName, parameterTypes);
                return method;
            } catch (Exception ignored) {

            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBeanInstance(String clazzName)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {

        return (T) Class.forName(clazzName).newInstance();
    }

    public static Map<String, Object> toBeanMethodMap(String toBean)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {

        Class<?> toBeanClazz = getBeanInstance(toBean).getClass();
        Method[] toBeanMethods = toBeanClazz.getDeclaredMethods();
        if (!toBeanClazz.isInstance(Object.class))// 非超类Object
        {
            for (Method method : toBeanMethods) {
                String methodName = method.getName();
                toBeanMethodMap.put(methodName, method);
            }

            Class<?> toBeanSuperclazz = toBeanClazz.getSuperclass();// 获取父类
            toBeanMethodMap(toBeanSuperclazz.getName());
        }

        return toBeanMethodMap;
    }

    public static Map<String, Object> toMap(Object object) {
        Map<String, Object> map = new HashMap<String, Object>();

        if (object == null) {
            return map;
        }

        BeanMap beanMap;
        beanMap = new BeanMap(object);
        @SuppressWarnings("unchecked")
        Iterator<String> it = beanMap.keyIterator();
        while (it.hasNext()) {
            String name = it.next();
            Object value = beanMap.get(name);
            // 转换时会将类名也转换成属性，此处去掉
            if (value != null && !name.equals("class")) {
                map.put(name, value);
            }
        }

        return map;
    }

    public static Map<String, Object> toMap(Object... objs) {
        Map<String, Object> map = new HashMap<>();
        for (Object object : objs) {
            if (object != null) {
                map.putAll(toMap(object));
            }
        }
        return map;
    }

    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 copyProperties(Object src, Object target) {
        BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
    }

}
