package com.bcxin.ars.util;

import com.bcxin.ars.exception.ArsException;
import com.bcxin.ars.model.CityConfig;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
 * @ClassName：BeanUtils
 * @Decription:复制方法的扩张
 * @author：zhongjianhui
 * @date：2018/6/9 15:17
 */
public class BeanUtils implements Serializable{
    /**
     * @param source   传入的类
     * @param needNull 是否需要排除空值，true：找到空值的对象 flase：返回不是空值的对象
     * @return java.lang.String[]
     * @Decription:两种用法： 一：找到要复制的类的空值，不复制到目标类
     * 二：找到目标类的非空对象，然后这些对象不需要复制
     * @author：zhongjianhui
     * @method getPropertyNames
     * @date：2018/6/8 17:11
     * @params：
     */
    public static String[] getPropertyNames(Object source, Object validateExist, Boolean needNull, String[] needCopyArr) {
        final BeanWrapper src = new BeanWrapperImpl(source);

        final BeanWrapper validate = new BeanWrapperImpl(validateExist);
        //找到类的所有属性
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        java.beans.PropertyDescriptor[] pdValidate = validate.getPropertyDescriptors();

        //空值的属性名称
        Set<String> emptyNames = new HashSet<String>();
        //有值的属性名称
        Set<String> notEmptyNames = new HashSet<String>();
        //需要忽略的属性名称
        Set<String> ignorePropertiesNames = new HashSet<String>();
        //需要拷贝的属性的长度
        int length = needCopyArr.length;
        //未找到值

        if (length > 0) {
            int pdLength = length;
            int validateLength = length;

            for (String needCopyStr : needCopyArr) {

                //判断被复制的对象有没有存在这个属性
                for (java.beans.PropertyDescriptor pd : pdValidate) {
                    if (needCopyStr.equals(pd.getName())) {
                        validateLength--;
                        break;
                    }
                }
                //目标无需被复制时校验，无需被复制的属性是否存在
                if (!needNull) {
                    for (java.beans.PropertyDescriptor pd : pds) {
                        if (needCopyStr.equals(pd.getName())) {
                            pdLength--;
                            break;
                        }
                    }
                }
            }
            if (!needNull) {
                if (pdLength > 0) {
                    throw new ArsException("目标的对象有不存在的属性，请校验名称是否写错！");
                }
            }
            if (validateLength > 0) {
                throw new ArsException("复制的对象有不存在的属性，请校验名称是否写错！");
            }


        }
        //如果不存在则报错

        //获取所有属性名称
        for (java.beans.PropertyDescriptor pd : pds) {


            //如果需要拷贝的值为空，则
            if (length <= 0) {
                //对象的值
                Object srcValue = src.getPropertyValue(pd.getName());
                if (srcValue == null || "".equals(srcValue)) {
                    //加入需要忽略复制空值的属性名字集合：src
                    emptyNames.add(pd.getName());
                } else {
                    //加入需要忽略目标有值的属性名字集合：desc
                    notEmptyNames.add(pd.getName());
                }
            } else {

                boolean flag = false;
                //遍历所有需要拷贝的属性数组
                for (String needCopyStr : needCopyArr) {
                    //如果属性名不等于拷贝的属性名则添加进入忽略的数组
                    if (needCopyStr.equals(pd.getName())) {
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    ignorePropertiesNames.add(pd.getName());
                }

            }
        }
        //定义返回的小
        String[] resultEmpty = new String[emptyNames.size()];
        String[] resultNotEmpty = new String[notEmptyNames.size()];
        String[] resultIgnoreProperties = new String[ignorePropertiesNames.size()];
        if (length <= 0) {
            if (needNull) {
                return emptyNames.toArray(resultEmpty);
            } else {
                return notEmptyNames.toArray(resultNotEmpty);
            }
        } else {
            //不需要复制到目标的属性
            if (needNull){
                return needCopyArr;
            }else {
                return ignorePropertiesNames.toArray(resultIgnoreProperties);
            }
        }
    }

    /**
     * @param src        要被复制的对象 A
     * @param target     目标对象 B
     * @param ignoreNull 是否需要排除空值
     *                   A复制给B
     *                   A的值赋值给B
     *                  src的值赋值给target
     *                   true：找到要 复制的对象src 的所有空值的属性，不复制到 目标对象target
     *                   false：找到目标对象target的非空属性，然后这些对象不需被复制
     *                   ex：被复制的对象：src：name="aaa" id="213213" version=""
     *                   目标对象：target: name="bbb" version="1.0"--->
     *                   ignoreNull=true   result: target:name="aaa" id="213213" version="1.0" （src为空不复制）
     *                   ignoreNull=false   result: target:name="bbb" id="213213" version="1.0" (target有值不替换)
     * @return void
     * @Decription:拷贝的时候排除
     * @author：zhongjianhui
     * @method copyPropertiesIgnoreNull
     * @date：2018/6/8 17:05
     * @params：
     */
    public static void copyPropertiesIgnore(Object src, Object target, Boolean ignoreNull) {
        Object ignoreObject = src;
        if (!ignoreNull) {
            ignoreObject = target;
        }
        org.springframework.beans.BeanUtils.copyProperties(src, target, getPropertyNames(ignoreObject, src, ignoreNull, new String[0]));
    }

    /**
     * @param src                 要被复制的对象
     * @param target              目标对象
     * @param propertieNameString 需要操作的属性名称，用英文,隔开，格式:"path,size"
     * @param needIgnore          需要排除？ true :拷贝的时候忽略这些值不拷贝到目标中去， false： 拷贝的时候只拷贝propertieNameString的值到目标文件
     * @return void
     * @Decription:拷贝的时候排除传入的字符串
     * @author：zhongjianhui
     * @method copyPropertiesIgnoreNull
     * @date：2018/6/8 17:05
     * @params：
     */
    public static void copyPropertiesIgnore(Object src, Object target, String propertieNameString, Boolean needIgnore) {
        //属性名称的数组
        String[] propertieNameArr = new String[50];
        if (!StringUtils.isEmpty(propertieNameString)) {
            propertieNameArr = propertieNameString.split(",");
        }
            org.springframework.beans.BeanUtils.copyProperties(src, target, getPropertyNames(src, src, needIgnore, propertieNameArr));
            //拷贝排除

    }


    /**
     * @param src    要被拷贝的对象
     * @param target 目标对象
     * @return void
     * @Decription: 拷贝方法且不排除
     * @author：zhongjianhui
     * @method copyPropertiesIgnore
     * @date：2018/6/9 9:20
     * @params：
     */
    public static void copyPropertiesIgnore(Object src, Object target) {
        org.springframework.beans.BeanUtils.copyProperties(src, target);
    }

    public static void main(String[] args) {
        CityConfig cityConfig = new CityConfig();
        cityConfig.setName("复制名称");
        cityConfig.setRestURL("复制地址");
        cityConfig.setNativeCode("1231221");
        cityConfig.setActive(true);
        cityConfig.setVersion("");
        CityConfig target = new CityConfig();
        target.setName("目标名称");
        target.setVersion("目标版本");
        String ignore = "name,restURL,nativeCode";
        System.out.println("复制类" + cityConfig.toString());
        System.out.println("目标类（未复制）" + target.toString());
        copyPropertiesIgnore(cityConfig, target, true);
        System.out.println("目标类（已复制）" + target.toString());
    }
}