package com.kmall.common.utils;

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * map bean 相互转换
 *
 * @author Scott Chen
 * @version 1.0
 * 2017-09-19 16:58
 */
public class MapBeanUtil {
    private static final Logger logger = LoggerFactory.getLogger(MapBeanUtil.class);


    /**
     * map 转 bean by BeanUtils
     * @param map
     * @param beanClass
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T toObject(Map<String, Object> map, Class<T> beanClass) throws Exception {
        T bean;
        if (map == null) {
            return null;
        }
        bean = beanClass.newInstance();
        BeanUtils.populate(bean, map);

        return bean;
    }

    /**
     * bean 转 map   by Introspector
     *
     * @param bean
     * @return
     */
    public static <T> Map<String, Object> fromObject(T bean) {
        if (bean == null) {
            return null;
        }
        return fromObjectByIntrospector(bean);
    }

    //----------  使用Introspector进行转换 ----------

    /**
     * map 转 bean by Introspector
     * @param map
     * @param beanClass
     * @param <T>
     * @return
     */
    public static <T> T toObjectByIntrospector(Map<String, Object> map, Class<T> beanClass) {
        if (map == null) {
            return null;
        }
        T obj = null;

        try {
            obj = beanClass.newInstance();

            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                Method setter = property.getWriteMethod();
                if (setter != null) {
                    setter.invoke(obj, map.get(property.getName()));
                }
            }
        } catch (InstantiationException e) {
            String info = "[toObjectByIntrospector] InstantiationException::Map转换Bean失败";
            logger.error(info);
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            String info = "[toObjectByIntrospector] IllegalAccessException::Map转换Bean失败";
            logger.error(info);
            e.printStackTrace();
        } catch (IntrospectionException e) {
            String info = "[toObjectByIntrospector] IntrospectionException::Map转换Bean失败";
            logger.error(info);
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            String info = "[toObjectByIntrospector] InvocationTargetException::Map转换Bean失败";
            logger.error(info);
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * bean 转 map   by Introspector
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> Map<String, Object> fromObjectByIntrospector(T obj) {
        if (obj == null) {
            return null;
        }

        Map<String, Object> map = new HashMap<String, Object>();

        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (key.compareToIgnoreCase("class") == 0) {
                    continue;
                }
                Method getter = property.getReadMethod();
                Object value = getter != null ? getter.invoke(obj) : null;
                map.put(key, value);
            }
        } catch (IntrospectionException e) {
            String info = "[fromObjectByIntrospector] IntrospectionException::Bean转换Map失败";
            logger.error(info);
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            String info = "[fromObjectByIntrospector] InvocationTargetException::Bean转换Map失败";
            logger.error(info);
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            String info = "[fromObjectByIntrospector] IllegalArgumentException::Bean转换Map失败,";
            logger.error(info);
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            String info = "[fromObjectByIntrospector] IllegalAccessException::Bean转换Map失败";
            logger.error(info);
            e.printStackTrace();
        }

        return map;
    }

    //----------  使用reflect进行转换 ----------

    /**
     * map 转 bean  by Reflect
     * @param map
     * @param beanClass
     * @param <T>
     * @return
     */
    public static <T> T toObjectByReflect(Map<String, Object> map, Class<T> beanClass) {
        if (map == null) {
            return null;
        }

        T obj = null;
        try {
            obj = beanClass.newInstance();

            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                    continue;
                }

                field.setAccessible(true);
                field.set(obj, map.get(field.getName()));
            }
        }catch (InstantiationException e) {
            String info = "[toObjectByReflect] InstantiationException::Map转换Bean失败";
            logger.error(info);
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            String info = "[toObjectByReflect] IllegalAccessException::Map转换Bean失败";
            logger.error(info);
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * bean 转 map   by Reflect
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> Map<String, Object> fromObjectByReflect(T obj) {
        if (obj == null) {
            return null;
        }

        Map<String, Object> map = new HashMap<String, Object>();

        try{
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (IllegalAccessException e) {
            String info = "[fromObjectByReflect] IllegalAccessException::Bean转换Map失败";
            logger.error(info);
            e.printStackTrace();
        }

        return map;
    }


}
