
package com.heyu.api.data.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.slf4j.LoggerFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;


/**
 * @author 苏伟丽 2016年10月31日 下午7:02:15
 * @类描述：
 * @注意：本内容仅限于杭州霖梓网络科技有限公司内部传阅，禁止外泄以及用于其他的商业目的
 */
@Slf4j
public class BeanUtil {


    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(BeanUtil.class);

    public static HashMap<String, Object> beanToMap(Object obj) {
        HashMap<String, Object> params = new HashMap<String, Object>(0);
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);
            for (int i = 0; i < descriptors.length; i++) {
                String name = descriptors[i].getName();
                if (!"class".equals(name)) {
                    params.put(name, propertyUtilsBean.getNestedProperty(obj, name));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return params;
    }

    public static Map<String, String> beanToStrMap(Object obj) {
        return objMapToStrMap(beanToMap(obj));
    }


    public static Map<String, String> objMapToStrMap(Map<String, Object> strMap) {
        Map<String, String> map = new HashMap<String, String>();
        Iterator<Map.Entry<String, Object>> it = strMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = it.next();
            if (entry.getValue() != null) {
                map.put(entry.getKey(), entry.getValue().toString());
            }
        }
        return map;
    }


    /**
     * 将map转换成Bean，Bean的属性名与map的key值对应时不区分大小写，并对map中key做忽略OMIT_REG正则处理
     *
     * @param <E>
     * @param cla
     * @param map
     * @return
     */
    public static <E> E toBean(Class<E> cla, Map<String, Object> map) {
        // 创建对象
        E obj = null;
        try {
            obj = cla.newInstance();
        } catch (Exception e) {


            return null;
        }
        // 进行值装入
        Method[] ms = cla.getMethods();
        for (Method method : ms) {
            String name = method.getName();
            String mname = name.substring(0, 1).toUpperCase() + name.substring(1); // 将属性的首字符大写，方便构造get，set方法
            if (mname.startsWith("set") || mname.startsWith("Set")) {
                Class[] clas = method.getParameterTypes();
                String a = mname.substring(3, mname.length());
                a = captureName(a);
                Object v = map.get(a);
                if (v != null && clas.length == 1) {
                    try {
                        method.invoke(obj, v);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return obj;
    }

    public static String captureName(String name) {
        char[] cs = name.toCharArray();
        cs[0] += 32;
        return String.valueOf(cs);
    }



    public static String fistToUpperCase(String name) {
        String a = name.substring(0,1);
        return a.toUpperCase() + name.substring(1);
    }

    public static void main(String[] args) {
        System.out.println(fistToUpperCase("gmtStart"));
    }


    public static void copy(Object source, Object target) {
        copy(source, target, null, null);
    }

    public static void copy(Object source, Object target, String property) {
        copy(source, target, property, null);
    }

    public static void copy(Object source, Object target, String property, Object defaultValue) {
        if(source == null && defaultValue == null){
            return;
        }
        if (source == null ) {
            source = defaultValue;
        }
        // 进行值装入
        Method[] ms = target.getClass().getMethods();
        for (Method method : ms) {
            try {
                String name = method.getName();
                String mname = name.substring(0, 1).toUpperCase() + name.substring(1); // 将属性的首字符大写，方便构造get，set方法
                if (mname.startsWith("set") || mname.startsWith("Set")) {
                    Class[] clas = method.getParameterTypes();
                    String a = mname.substring(3, mname.length());
                    a = captureName(a);
                    if (StringUtils.isNotEmpty(property) && !a.equals(property)) {
                        continue;
                    }
                    if(isBasicDataTypes(source.getClass())){
                        method.invoke(target, parseBasicTypeWrapper(clas[0], source));
                    }else{
                        Field field = null;
                        try {
                            field = source.getClass().getDeclaredField(a);
                        } catch (NoSuchFieldException e) {
                            try {
                                field = source.getClass().getField(a);
                            } catch (Exception e1 ) {
                            }
                        } catch (SecurityException e) {
                            log.error("bbbb", e);
                        }
                        if (field != null) {
                            field.setAccessible(true);
                            Object v = field.get(source);
                            if (clas.length == 1) {
                                if(v != null  ){
                                    method.invoke(target, parseBasicTypeWrapper(clas[0], v));
                                }else{
                                    method.invoke(target, parseBasicTypeWrapper(clas[0], defaultValue));
                                }

                            }
                        }else{
                            method.invoke(target, parseBasicTypeWrapper(clas[0], defaultValue));
                        }
                    }

                }
            } catch (Exception e) {
                log.error("xx", e);
            }
        }
    }

    /**
     * 基本类型包装类解析
     */
    public static Object parseBasicTypeWrapper(Class<?> parameterType, Object value) {
        if (Number.class.isAssignableFrom(parameterType)) {
            if (parameterType == Integer.class || parameterType == int.class) {
                return NumberUtils.objToIntDefault(value, null);
            } else if (parameterType == Short.class || parameterType == short.class) {
                return NumberUtils.objToShortDefault(value, null);
            } else if (parameterType == Long.class || parameterType == long.class) {
                return NumberUtils.objToLongDefault(value, null);
            } else if (parameterType == Float.class || parameterType == float.class) {
                return NumberUtils.objToFloatDefault(value, null);
            } else if (parameterType == Double.class || parameterType == double.class) {
                return NumberUtils.objToDoubleDefault(value, null);
            } else if (parameterType == Byte.class || parameterType == byte.class) {
                return NumberUtils.objToByteDefault(value, null);
            }   else if (parameterType == BigDecimal.class) {
                return NumberUtils.objToBigDecimalDefault(value, null);
            }
        } else if (parameterType == Boolean.class || parameterType == boolean.class) {
            return NumberUtils.objToBooleanDefault(value, null);
        } else if (parameterType == Character.class || parameterType == char.class) {
            return NumberUtils.objToCharacterDefault(value, null);
        } else if (parameterType == String.class) {
            return value !=null ? value.toString() : null ;
        }else if (parameterType == Date.class && value instanceof Date){
            return value;
        } else if (parameterType == Date.class && value instanceof String) {
            Object target = DateUtils.parseStr2Date((String) value, YYYY_MM_DD_HH_MM_SS);
            if (target == null) {
                target = DateUtils.parseStr2Date((String) value, YYYY_MM_DD);
                if(target == null){
                    target = DateUtils.parseStr2Date((String) value, YYYY);
                    if(target == null){
                        target = DateUtils.parseStr2Date((String) value, YYYY_MM);
                        if(target == null){
                            target = DateUtils.parseStr2Date((String) value, YYYY_MM_DD_HH);
                            if(target == null){
                                target = DateUtils.parseStr2Date((String) value, YYYY_MM_DD_HH_MM);
                            }
                        }
                    }
                }
            }
            return target;
        }
        return null;
    }

    public static String YYYY = "yyyy";
    public static String YYYY_MM = "yyyy-MM";
    public static String YYYY_MM_DD = "yyyy-MM-dd";
    public static String YYYY_MM_DD_HH = "yyyy-MM-dd HH";
    public static String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static final List<Class<?>> primitiveTypes = new ArrayList<>(32);

    static {
        primitiveTypes.add(Boolean.class);
        primitiveTypes.add(Byte.class);
        primitiveTypes.add(Character.class);
        primitiveTypes.add(Double.class);
        primitiveTypes.add(Float.class);
        primitiveTypes.add(Integer.class);
        primitiveTypes.add(Long.class);
        primitiveTypes.add(Short.class);
        primitiveTypes.add(BigDecimal.class);

        primitiveTypes.add(boolean.class);
        primitiveTypes.add(byte.class);
        primitiveTypes.add(char.class);
        primitiveTypes.add(double.class);
        primitiveTypes.add(float.class);
        primitiveTypes.add(int.class);
        primitiveTypes.add(long.class);
        primitiveTypes.add(short.class);
        primitiveTypes.add(String.class);
        primitiveTypes.add(Date.class);
    }

    public static boolean isBasicDataTypes(Class clazz) {
        return primitiveTypes.contains(clazz) ? true : false;
    }

}
