package com.opslab.helper;

import com.opslab.bean.BeanStruct;
import com.opslab.functions.PropertyFilter;
import com.opslab.util.CheckUtil;
import com.opslab.util.algorithmImpl.BeanFactory;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * JavaBean相关的一些操作
 */
public class BeanHepler {

    private static Map<String, BeanStruct> simpleProperties(Object obj) {
        return BeanFactory.BEAN_SIMPLE_PROPERTIES.get(obj.getClass().getName());
    }

    private static Map<String, BeanStruct> simplePropertiesIgnore(Object obj) {
        return BeanFactory.BEAN_SIMPLE_PROPERTIESIGNORE.get(obj.getClass().getName());
    }

    private static Method getReadMethod(Object obj, String pro) {
        BeanStruct st = simpleProperties(obj).get(pro);
        return st.getReadMethod();
    }

    private static Method getWriteMethod(Object obj, String pro) {
        BeanStruct st = simpleProperties(obj).get(pro);
        return st.getWriteMethod();
    }

    private static Method getReadMethodIgnore(Object obj, String pro) {
        BeanStruct st = simplePropertiesIgnore(obj).get(pro);
        return st.getReadMethod();
    }

    private static Method getWriteMethodIgnore(Object obj, String pro) {
        BeanStruct st = simplePropertiesIgnore(obj).get(pro);
        return st.getWriteMethod();
    }

    private static Object readMethod(Object bean,
                                     Method readMethod) throws InvocationTargetException, IllegalAccessException {
        return readMethod.invoke(bean);
    }

    private static void writeMethod(Object bean, Method writeMethod,
                                    Object value) throws InvocationTargetException, IllegalAccessException {
        writeMethod.invoke(bean, value);
    }


    /**
     * 添加Bean到BeanFactory的解析范围中
     *
     * @param obj 将目标obj加入到BeanFactory的解析范围中
     */
    public static void add(Object obj) {
        try {
            BeanFactory.add(obj);
        } catch (IntrospectionException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加Bean到BeanFactory的解析范围中
     *
     * @param clazz 将目标clazz加入到BeanFactory的解析范围中
     */
    public static void add(Class clazz) {
        try {
            BeanFactory.add(clazz);
        } catch (IntrospectionException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    /**
     * 判断属性是否存在
     *
     * @param bean 判断的目标bean
     * @param pro  判断的属性
     * @return 是否存在
     */
    public static boolean hasProperty(Object bean, String pro) {
        add(bean);
        Map map = simpleProperties(bean);
        return map.containsKey(pro);
    }


    /**
     * 判断自己定义的而非继承的属性pro是否存在
     *
     * @param bean 判断的目标bean
     * @param pro  判断的属性
     * @return 是否存在
     */
    public static boolean hasDeclaredProperty(Object bean, String pro) {
        add(bean);
        Map map = simpleProperties(bean);
        BeanStruct st = (BeanStruct) map.get(pro);
        return CheckUtil.valid(st) && st.isDeclared();
    }

    /**
     * 判断属性是否存在忽略大小写
     *
     * @param bean 判断的目标bean
     * @param pro  判断的属性
     * @return 是否存在
     */
    public static boolean hasPropertyIgnoreCase(Object bean, String pro) {
        add(bean);
        Map map = simplePropertiesIgnore(bean);
        return map.containsKey(pro.toLowerCase());
    }


    /**
     * 使用自定义的过滤器
     *
     * @param bean   判断的目标bean
     * @param pro    判断的属性
     * @param filter 自定义的属性过滤函数
     * @return 是否存在
     */
    public static boolean hasPropertyFilter(Object bean, String pro, PropertyFilter filter) {
        add(bean);
        pro = filter.Properties(pro);
        Map<String, BeanStruct> map = simpleProperties(bean);
        if (CheckUtil.valid(map)) {
            Set<String> set = map.keySet();
            for (String s : set) {
                if (pro.equals(filter.Properties(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取对象的属性
     *
     * @param bean 判断的目标bean
     * @param pro  判断的属性
     * @return 属性对应的值
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object getProperty(Object bean, String pro) throws InvocationTargetException, IllegalAccessException {
        add(bean);
        return readMethod(bean, getReadMethod(bean, pro));
    }

    /**
     * 获取对象的属性
     *
     * @param bean 操作的Bean
     * @param pro  类型属性
     * @return 返回属性的值如果发生异常返回空
     */
    public static Object getPropertyPeaceful(Object bean, String pro) {
        add(bean);
        Object result = null;
        try {
            result = readMethod(bean, getReadMethod(bean, pro));
        } catch (InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 获取对象的属性(忽略属性名字大小写)
     *
     * @param bean 操作的Bean
     * @param pro  类型属性
     * @return 返回属性的值如果发生异常返回空
     */
    public static Object getPropertyIgnoreCase(Object bean,
                                               String pro) throws InvocationTargetException, IllegalAccessException {
        add(bean);
        return readMethod(bean, getReadMethodIgnore(bean, pro));
    }

    /**
     * 获取对象的属性(忽略属性名字大小写)
     *
     * @param bean 操作的Bean
     * @param pro  类型属性
     * @return 返回属性的值如果发生异常返回空
     */
    public static Object getPropertyIgnoreCasePeaceful(Object bean, String pro) {
        add(bean);
        Object result = null;
        try {
            result = readMethod(bean, getReadMethodIgnore(bean, pro));
        } catch (InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 使用自定义的过滤器获取对象的属性获取对象的属性
     *
     * @param bean   操作的Bean
     * @param pro    类型属性
     * @param filter 自定义的过滤函数
     * @return 返回属性的值如果发生异常返回空
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object getPropertyFilter(Object bean, String pro,
                                           PropertyFilter filter) throws InvocationTargetException, IllegalAccessException {
        add(bean);
        Object result = null;
        pro = filter.Properties(pro);
        Map<String, BeanStruct> map = simpleProperties(bean);
        if (CheckUtil.valid(map)) {
            Set<String> set = map.keySet();
            for (String s : set) {
                if (pro.equals(filter.Properties(s))) {
                    result = readMethod(bean, getReadMethod(bean, s));
                }
            }
        }
        return result;
    }

    /**
     * 使用自定义的过滤器获取对象的属性
     *
     * @param bean   操作的Bean
     * @param pro    类型属性
     * @param filter 自定义的过滤函数
     * @return 返回属性的值如果发生异常返回空
     */
    public static Object getPropertyFilterPeaceful(Object bean, String pro, PropertyFilter filter) {
        add(bean);
        Object result = null;
        pro = filter.Properties(pro);
        Map<String, BeanStruct> map = simpleProperties(bean);
        if (CheckUtil.valid(map)) {
            Set<String> set = map.keySet();
            try {
                for (String s : set) {
                    if (pro.equals(filter.Properties(s))) {
                        result = readMethod(bean, getReadMethod(bean, s));
                    }
                }
            } catch (InvocationTargetException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return result;
    }


    /**
     * 设置对象的属性
     *
     * @param bean  操作的Bean
     * @param pro   类型属性
     * @param value 设置属性的值
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void setProperty(Object bean, String pro,
                                   Object value) throws InvocationTargetException, IllegalAccessException {
        add(bean);
        writeMethod(bean, getWriteMethod(bean, pro), value);
    }

    /**
     * 设置对象的属性
     *
     * @param bean  操作的Bean
     * @param pro   类型属性
     * @param value 设置属性的值
     */
    public static void setPropertyPeaceful(Object bean, String pro, Object value) {
        add(bean);
        try {
            writeMethod(bean, getWriteMethod(bean, pro), value);
        } catch (InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    /**
     * 设置对象的属性忽略大小写
     *
     * @param bean  操作的Bean
     * @param pro   类型属性
     * @param value 设置属性的值
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void setPropertyIgnoreCase(Object bean, String pro,
                                             Object value) throws InvocationTargetException, IllegalAccessException {
        add(bean);
        writeMethod(bean, getWriteMethodIgnore(bean, pro), value);
    }

    /**
     * 设置对象的属性忽略大小写
     *
     * @param bean  操作的Bean
     * @param pro   类型属性
     * @param value 设置属性的值
     */
    public static void setPropertyIgnoreCasePeaceful(Object bean, String pro, Object value) {
        add(bean);
        try {
            writeMethod(bean, getWriteMethodIgnore(bean, pro), value);
        } catch (InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    /**
     * 使用自定义的filter进行属性设值
     *
     * @param bean   操作的Bean
     * @param pro    类型属性
     * @param value  设置属性的值
     * @param filter 自定义的函数
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void setPropertyFilter(Object bean, String pro, Object value,
                                         PropertyFilter filter) throws InvocationTargetException, IllegalAccessException {
        add(bean);
        pro = filter.Properties(pro);
        Map<String, BeanStruct> map = simpleProperties(bean);
        if (CheckUtil.valid(map)) {
            Set<String> set = map.keySet();
            for (String s : set) {
                if (pro.equals(filter.Properties(s))) {
                    writeMethod(bean, getWriteMethodIgnore(bean, pro), value);
                }
            }

        }
    }

    /**
     * 使用自定义的filter进行属性设值
     *
     * @param bean   操作的Bean
     * @param pro    类型属性
     * @param value  设置属性的值
     * @param filter 自定义的函数
     */
    public static void setPropertyFilterPeaceful(Object bean, String pro, Object value, PropertyFilter filter) {
        add(bean);
        pro = filter.Properties(pro);
        Map<String, BeanStruct> map = simpleProperties(bean);
        if (CheckUtil.valid(map)) {
            Set<String> set = map.keySet();
            try {
                for (String s : set) {
                    if (pro.equals(filter.Properties(s))) {
                        writeMethod(bean, getWriteMethodIgnore(bean, pro), value);
                    }
                }
            } catch (InvocationTargetException | IllegalAccessException e) {
                e.printStackTrace();
            }

        }
    }


    /**
     * 拷贝对象指定的属性
     *
     * @param srcBean  源Bean
     * @param destBean 目标Bean
     * @param pros     copy的属性
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void copyProperty(Object srcBean, Object destBean,
                                    String[] pros) throws InvocationTargetException, IllegalAccessException {
        add(srcBean);
        add(destBean);
        if (CheckUtil.valid(pros)) {
            for (String s : pros) {
                Object value = readMethod(srcBean, getReadMethod(srcBean, s));
                writeMethod(destBean, getWriteMethod(destBean, s), value);
            }
        }
    }

    /**
     * 拷贝对象指定的属性
     *
     * @param srcBean  源Bean
     * @param destBean 目标Bean
     * @param pros     copy的属性
     */
    public static void copyPropertyPeaceful(Object srcBean, Object destBean, String[] pros) {
        add(srcBean);
        add(destBean);
        if (CheckUtil.valid(pros)) {
            try {
                for (String s : pros) {
                    Object value = readMethod(srcBean, getReadMethod(srcBean, s));
                    writeMethod(destBean, getWriteMethod(destBean, s), value);
                }
            } catch (InvocationTargetException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 复制同名属性
     *
     * @param srcBean  源Bean
     * @param destBean 目标Bean
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void copyProperties(Object srcBean,
                                      Object destBean) throws InvocationTargetException, IllegalAccessException {
        add(srcBean);
        add(destBean);
        Map<String, BeanStruct> srcMap = simpleProperties(srcBean);
        Map<String, BeanStruct> dstMap = simpleProperties(destBean);
        Map<String, BeanStruct> intersection = CollectionHelper.intersection(srcMap, dstMap);
        for (Map.Entry<String, BeanStruct> entry : intersection.entrySet()) {
            String key = entry.getKey();
            Object value = readMethod(srcBean, getReadMethod(srcBean, key));
            writeMethod(destBean, getWriteMethod(destBean, key), value);
        }
    }

    /**
     * 复制同名属性
     *
     * @param srcBean  源Bean
     * @param destBean 目标Bean
     */
    public static void copyPropertiesPeaceful(Object srcBean, Object destBean) {
        add(srcBean);
        add(destBean);
        Map<String, BeanStruct> srcMap = simpleProperties(srcBean);
        Map<String, BeanStruct> dstMap = simpleProperties(destBean);
        Map<String, BeanStruct> intersection = CollectionHelper.intersection(srcMap, dstMap);
        for (Map.Entry<String, BeanStruct> entry : intersection.entrySet()) {
            String key = entry.getKey();
            try {
                //为什么会将try写在里面而不是foreach的外面？
                //如果你想尽可能多的复制属性的话你可以
                Object value = readMethod(srcBean, getReadMethod(srcBean, key));
                writeMethod(destBean, getWriteMethod(destBean, key), value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 复制同名属性(忽略大小写)
     *
     * @param srcBean  原Bean
     * @param destBean 目标Bean
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void copyPropertiesIgnoreCase(Object srcBean,
                                                Object destBean) throws InvocationTargetException, IllegalAccessException {
        add(srcBean);
        add(destBean);
        Map<String, BeanStruct> srcMap = simplePropertiesIgnore(srcBean);
        Map<String, BeanStruct> dstMap = simplePropertiesIgnore(destBean);
        Map<String, BeanStruct> intersection = CollectionHelper.intersection(srcMap, dstMap);
        for (Map.Entry entry : intersection.entrySet()) {
            String key = (String) entry.getKey();
            Object value = readMethod(srcBean, getReadMethodIgnore(srcBean, key));
            writeMethod(destBean, getWriteMethodIgnore(destBean, key), value);
        }
    }

    /**
     * 复制同名属性(忽略大小写)
     *
     * @param srcBean  原Bean
     * @param destBean 目标Bean
     */
    public static void copyPropertiesIgnoreCasePeaceful(Object srcBean, Object destBean) {
        add(srcBean);
        add(destBean);
        Map<String, BeanStruct> srcMap = simplePropertiesIgnore(srcBean);
        Map<String, BeanStruct> dstMap = simplePropertiesIgnore(destBean);
        Map<String, BeanStruct> intersection = CollectionHelper.intersection(srcMap, dstMap);
        for (Map.Entry entry : intersection.entrySet()) {
            String key = (String) entry.getKey();
            Object value = null;
            try {
                value = readMethod(srcBean, getReadMethodIgnore(srcBean, key));
                writeMethod(destBean, getWriteMethodIgnore(destBean, key), value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 使用自定义的属性过滤函数
     *
     * @param srcBean  原Bean
     * @param destBean 目标bean
     * @param filter   自定义的过滤函数
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void copyProperties(Object srcBean, Object destBean,
                                      PropertyFilter filter) throws InvocationTargetException, IllegalAccessException {
        add(srcBean);
        add(destBean);
        Map<String, BeanStruct> srcMap = simpleProperties(srcBean);
        Map<String, BeanStruct> dstMap = simpleProperties(destBean);
        if (CheckUtil.valid(srcMap, dstMap)) {
            Map<String, String> srcMapFilter = new HashMap<>();
            Map<String, String> dstMapFilter = new HashMap<>();
            for (Map.Entry<String, BeanStruct> entry : srcMap.entrySet()) {
                srcMapFilter.put(filter.Properties(entry.getKey()), entry.getKey());
            }
            for (Map.Entry<String, BeanStruct> entry : dstMap.entrySet()) {
                dstMapFilter.put(filter.Properties(entry.getKey()), entry.getKey());
            }
            Map<String, String> intersection = CollectionHelper.intersection(srcMapFilter, dstMapFilter);
            if (CheckUtil.valid(intersection)) {
                for (Map.Entry<String, String> entry : intersection.entrySet()) {
                    String key = entry.getKey();
                    String srcKey = srcMapFilter.get(key);
                    String dstKey = dstMapFilter.get(key);
                    Object value = readMethod(srcBean, getReadMethod(srcBean, srcKey));
                    writeMethod(destBean, getWriteMethod(destBean, dstKey), value);
                }
            }
        }
    }

    /**
     * 使用自定义的属性过滤函数
     *
     * @param srcBean  原Bean
     * @param destBean 目标bean
     * @param filter   自定义的过滤函数
     */
    public static void copyPropertiesPeaceful(Object srcBean, Object destBean, PropertyFilter filter) {
        add(srcBean);
        add(destBean);
        Map<String, BeanStruct> srcMap = simpleProperties(srcBean);
        Map<String, BeanStruct> dstMap = simpleProperties(destBean);
        if (CheckUtil.valid(srcMap, dstMap)) {
            Map<String, String> srcMapFilter = new HashMap<>();
            Map<String, String> dstMapFilter = new HashMap<>();
            for (Map.Entry<String, BeanStruct> entry : srcMap.entrySet()) {
                srcMapFilter.put(filter.Properties(entry.getKey()), entry.getKey());
            }
            for (Map.Entry<String, BeanStruct> entry : dstMap.entrySet()) {
                dstMapFilter.put(filter.Properties(entry.getKey()), entry.getKey());
            }
            Map<String, String> intersection = CollectionHelper.intersection(srcMapFilter, dstMapFilter);
            if (CheckUtil.valid(intersection)) {
                for (Map.Entry<String, String> entry : intersection.entrySet()) {
                    String key = entry.getKey();
                    String srcKey = srcMapFilter.get(key);
                    String dstKey = dstMapFilter.get(key);
                    try {
                        Object value = readMethod(srcBean, getReadMethod(srcBean, srcKey));
                        writeMethod(destBean, getWriteMethod(destBean, dstKey), value);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
