/**
 * 描述:
 * 版本信息: 版本1.0
 * 日期:2019/1/1010:31
 * Copyright
 */
package com.artfess.base.trans;


import com.artfess.base.trans.other.Avgs;
import com.artfess.base.trans.other.Compute;
import com.artfess.base.trans.other.ReFilter;
import com.artfess.base.trans.other.Recurrence;
import com.artfess.base.trans.other.RepetitionSourceToTarget;
import com.artfess.base.trans.other.RepetitionToStr;
import com.artfess.base.trans.other.Trans;
import com.artfess.base.util.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @describe:对象转换工具类，调用时需要注意标注源对象和目标对象
 * @author: jiahong.xing/
 * @version: v1.0
 * @date 2019/1/1010:31
 */
public class TransitionUtil {

    /**
     * 对象1转换到对象2
     *
     * @param tsource
     * @param ttargetClass
     * @param trans
     * @param <Tsource>
     * @param <Ttarget>
     * @return
     */
    public static <Tsource, Ttarget> Ttarget copy(Tsource tsource, Class<Ttarget> ttargetClass, Trans<Tsource, Ttarget>... trans) {
        if (null == tsource) {
            return null;
        }

        //再调用方法默认实现方法
        Ttarget target = null;
        try {
            target = ttargetClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        BeanUtils.copyProperties(tsource, target);
        if (null != trans && trans.length > 0) {
            trans[0].copy(tsource, target);
        }
        return target;
    }


    /**
     * 转换类的源数据,可以从对象1转换到对象2，单线程处理方式
     *
     * @param tsourceList  原列表数据
     * @param ttargetClass 目标Class文件
     * @param trans        转换接口，如果是有的，则进行转换
     * @param <Tsource>
     * @param <Ttarget>
     * @return
     */
    public static <Tsource, Ttarget> List<Ttarget> copyList(List<Tsource> tsourceList, Class<Ttarget> ttargetClass, Trans<Tsource, Ttarget>... trans) {
        List<Ttarget> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(tsourceList)) {
            return targetList;
        }
        if (null == ttargetClass) {
            return targetList;
        }
        for (Tsource source : tsourceList) {
            if (null == source) {
                continue;
            }
            //再调用方法默认实现方法
            Ttarget target = null;
            try {
                target = ttargetClass.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
            BeanUtils.copyProperties(source, target);
            if (CollectionUtils.isNotEmpty(trans)) {
                trans[0].copy(source, target);
            }
            targetList.add(target);
        }
        return targetList;
    }

    //多线程优化版
    public static <Tsource, Ttarget> List<Ttarget> copyListThread(List<Tsource> tsourceList, Class<Ttarget> ttargetClass, Trans<Tsource, Ttarget>... trans) {
        List<Ttarget> targetList = Collections.synchronizedList(new ArrayList<>());
        if (CollectionUtils.isEmpty(tsourceList)) {
            return targetList;
        }
        tsourceList.parallelStream().forEach(source -> {
            if (null == source) {
                return;
            }
            //再调用方法默认实现方法
            Ttarget target = null;
            try {
                target = ttargetClass.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }

            BeanUtils.copyProperties(source, target);
            if (CollectionUtils.isNotEmpty(trans)) {
                trans[0].copy(source, target);
            }
            targetList.add(target);
        });
        return targetList;
    }

    //转换
    //对象转换
    public static <Tsource, Ttarget> Ttarget[] listToArray(List<Tsource> tsourceList, Class<? extends Ttarget[]> newType, RepetitionSourceToTarget<Tsource, Ttarget>... repetition) {
        //参考的ArrayList源码里面的list转数组
        Ttarget[] ttargets = ((Object) newType == (Object) Object[].class)
                ? (Ttarget[]) new Object[tsourceList.size()]
                : (Ttarget[]) Array.newInstance(newType.getComponentType(), tsourceList.size());
        if (CollectionUtils.isEmpty(tsourceList)) {
            return ttargets;
        }
        for (int i = 0; i < tsourceList.size(); i++) {
            Tsource source = tsourceList.get(i);
            //再调用方法默认实现方法
            if (CollectionUtils.isNotEmpty(repetition)) {
                Ttarget target = repetition[0].deRepetition(source);
                ttargets[i] = target;
            }
        }
        return ttargets;
    }

    /**
     * 进行自定义去重转换
     *
     * @param tsourceList      原数据
     * @param repetitionToStrs 转换接口
     * @param <Tsource>
     * @return
     */
    public static <Tsource, Target> List<Tsource> deRepetition(Collection<Tsource> tsourceList, RepetitionSourceToTarget<Tsource, Target>... repetitionToStrs) {
        if (CollectionUtils.isEmpty(tsourceList)) {
            return new ArrayList<>(tsourceList);
        }

        //去重
        Map<Target, Tsource> map = new LinkedHashMap<>();
        for (Tsource source : tsourceList) {
            if (null == source) {
                continue;
            }
            Target target = null;
            if (CollectionUtils.isNotEmpty(repetitionToStrs)) {
                target = repetitionToStrs[0].deRepetition(source);
            }
            //判断去重
            if (!map.containsKey(target)) {
                map.put(target, source);
            }
        }
        //
        List<Tsource> targetList = new ArrayList<>();
        Set<Target> keySet = map.keySet();
        for (Target target : keySet) {
            targetList.add(map.get(target));
        }
        return targetList;
    }

    /**
     * list对象转map对象，根据自定义的类型
     *
     * @param tsourceList              原数据对象
     * @param repetitionSourceToTarget 转换对象
     * @param <TKay>                   键
     * @param <Tsource>                值
     * @return
     */
    public static <TKay, Tsource> Map<TKay, Tsource> listToMap(Collection<Tsource> tsourceList, RepetitionSourceToTarget<Tsource, TKay> repetitionSourceToTarget) {
        Map<TKay, Tsource> map = new HashMap<>();
        if (CollectionUtils.isEmpty(tsourceList)) {
            return map;
        }
        for (Tsource source : tsourceList) {
            if (null == source) {
                continue;
            }
            TKay key = repetitionSourceToTarget.deRepetition(source);
            map.put(key, source);
        }
        return map;
    }

    //根据某个字段来进行分组，然后得出这个数据多少，比如1,2,3,2,3,1；；分组结果为123
    public static <Tsource, Target> int groupFiled(Collection<Tsource> tsourceList, RepetitionSourceToTarget<Tsource, Target> repetition) {
        if (CollectionUtils.isEmpty(tsourceList)) {
            return 0;
        }
        Set<Target> set = new HashSet();
        for (Tsource source : tsourceList) {
            if (null == source) {
                continue;
            }
            Target target = repetition.deRepetition(source);
            set.add(target);
        }
        return set.size();
    }

    //根据某个字段来进行分组，参考mysql的group by  字段以及count(*)
    public static <Tsource, Target> Map<Target, List<Tsource>> groupFiledMap(Collection<Tsource> tsourceList, RepetitionSourceToTarget<Tsource, Target> repetition) {
        Map<Target, List<Tsource>> map = new HashMap<>();
        if (CollectionUtils.isEmpty(tsourceList)) {
            return map;
        }

        for (Tsource source : tsourceList) {
            if (null == source) {
                continue;
            }
            Target target = repetition.deRepetition(source);
            List<Tsource> list = map.get(target);
            if (null == list) {
                list = new ArrayList<>();
            }
            list.add(source);

            map.put(target, list);
        }
        return map;
    }

    /**
     * 数组转换非相同对象  FIXME 未测试
     *
     * @param tsources
     * @param repetition
     * @param <Tsource>
     * @return
     */
    public static <Tsource, Target> List<Target> arrayToList(Tsource[] tsources, RepetitionSourceToTarget<Tsource, Target> repetition) {
        List<Target> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(tsources)) {
            return targetList;
        }
        for (Tsource source : tsources) {
            if (null == source) {
                continue;
            }
            Target target = repetition.deRepetition(source);
            targetList.add(target);
        }
        return targetList;
    }




    /**
     * 根据传入列表对象的某一个字段 ,取出来对应成一个集合
     *
     * @param tsourceList
     * @param repetition
     * @param <Tsource>
     * @return
     */
    public static <Tsource, Target> List<Target> listFiledToList(Collection<Tsource> tsourceList, RepetitionSourceToTarget<Tsource, Target> repetition) {
        List<Target> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(tsourceList)) {
            return targetList;
        }
        for (Tsource source : tsourceList) {
            targetList.add(repetition.deRepetition(source));
        }
        return targetList;
    }



    /**
     * 计算操作，可以将集合内的对象根据某个字段进行整合
     *
     * @param tsourceList 数据集合
     * @param compute     计算的函数
     * @param <Sum>
     * @param <Tsource>
     * @return
     */
    public static <Sum, Tsource> Sum sum(Collection<Tsource> tsourceList, Sum start, Compute<Sum, Tsource> compute) {
        if (CollectionUtils.isEmpty(tsourceList)) {
            return start;
        }
        for (Tsource source : tsourceList) {
            start = compute.compute(start, source);
        }
        return start;
    }


    /**
     * 从某一层级对象，无限网上走，走到最顶层后，根据某个字段对象连接并返回,比如查找武侯区的，就为 中国-四川-成都-武侯区,有几级，就做几级
     *
     * @param tsource         最底层对象
     * @param split           连接符
     * @param recurrence      得到本对象的操作
     * @param repetitionToStr 得到对象内某个字段的操作
     * @param <Tsource>
     * @return
     */
    public static <Tsource> String recurrenceUpToString(Tsource tsource, String split, Recurrence<Tsource> recurrence, RepetitionToStr<Tsource> repetitionToStr) {
        String upstr = "";
        if (null == tsource) {
            return upstr;
        }
        if (null == split) {
            split = "";
        }

        StringBuffer stringBuffer = new StringBuffer();

        //本对象的内容
        String tStr = repetitionToStr.deRepetition(tsource);
        if (null == tStr) {
            return upstr;
        }
        stringBuffer.append(tStr);


        //上级对象
        Tsource tsource2 = recurrence.recurrence(tsource);
        //如果是有，则循环
        if (null != tsource2) {
            String tStr2 = recurrenceUpToString(tsource2, split, recurrence, repetitionToStr);
            if (StringUtils.isNotEmpty(tStr2)) {
                stringBuffer.insert(0, split).insert(0, tStr2);
            }
        }
        return stringBuffer.toString();
    }

    //平均分配到字段上
    public static <Tsource> void average(List<Tsource> tsourceList, int oc, Avgs<Integer, Tsource> avgs) {
        if (CollectionUtils.isEmpty(tsourceList)) {
            return;
        }

        //先平均分配
        int avs[] = CollectionUtils.average(oc, tsourceList.size());
        for (int i = 0; i < tsourceList.size(); i++) {
            Tsource tsource = tsourceList.get(i);
            avgs.setData(avs[i], tsource);
        }
    }

    /**
     * 过滤某些数据
     *
     * @param tsourceList
     * @param reFilters
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(List<T> tsourceList, ReFilter<T> reFilters) {
        List<T> targetList = new ArrayList<>();
        if (CollectionUtils.isEmpty(tsourceList)) {
            return targetList;
        }
        for (T source : tsourceList) {
            if (null == source) {
                continue;
            }
            boolean isok = reFilters.filter(source);
            if (isok) {
                targetList.add(source);
            }
        }
        return targetList;
    }

    /**
     * 得到map值的列表
     *
     * @param <T>
     * @param map
     * @return
     */
    public static <T> List<T> mapValueList(Map<String, T> map) {
        List<T> list = new ArrayList<>();
        if (CollectionUtils.isEmpty(map)) {
            return list;
        }

        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            list.add(map.get(key));
        }

        return list;
    }

    /**
     * 从原始里面里面，根据某一个字段，把包含的，未包含的找出来
     *
     * @param data_list       原始数据
     * @param stringSet       需要过滤的数据
     * @param repetitionToStr 过滤算法
     * @param has             true 为包含
     * @param <T>             has
     * @return
     */
    public static <T> List<T> listHashSet(List<T> data_list, Set<String> stringSet, RepetitionToStr<T> repetitionToStr, boolean has) {
        if (CollectionUtils.isEmpty(data_list) || null == repetitionToStr) {
            return new ArrayList<>();
        }
        if (CollectionUtils.isEmpty(stringSet)) {
            if (has) {
                return new ArrayList<>();
            } else {
                return data_list;
            }
        }
        List<T> list = new ArrayList<>();

        for (T t : data_list) {
            String ds = repetitionToStr.deRepetition(t);
            if (has) {
                if (stringSet.contains(ds)) {
                    list.add(t);
                }
            } else {
                if (!stringSet.contains(ds)) {
                    list.add(t);
                }
            }
        }
        return list;
    }

    //同下，默认为新增
    public static <T, E> List<T> newObject(List<T> oldList, List<T> newList, RepetitionSourceToTarget<T, E> repetitionSourceToTarget) {
        return newObject(oldList, newList, repetitionSourceToTarget, false);
    }

    /**
     * 从新旧集合里面根据某个字段来得出多余的数据
     *
     * @param oldList                  旧的集合
     * @param newList                  新的集合
     * @param repetitionSourceToTarget 取得某个字段来对比
     * @param in                       如果为false，则得到新的比旧的新增的，如果为true,则得到两个都有的
     * @param <T>                      集合泛型
     * @param <E>                      字段泛型
     * @return
     */
    public static <T, E> List<T> newObject(List<T> oldList, List<T> newList, RepetitionSourceToTarget<T, E> repetitionSourceToTarget, boolean in) {
        if (CollectionUtils.isEmpty(oldList)) {
            return newList;
        }
        if (CollectionUtils.isEmpty(newList)) {
            return newList;
        }
        //旧数据
        Map<E, T> oldMap = new HashMap<>();
        for (T t : oldList) {
            E e = repetitionSourceToTarget.deRepetition(t);
            oldMap.put(e, t);
        }
        List<T> list = new ArrayList<>();
        for (T t : newList) {
            E e = repetitionSourceToTarget.deRepetition(t);
            if (in == oldMap.containsKey(e)) {
                list.add(t);
            }
        }

        return list;
    }

    /**
     * 根据字段匹配数据，仅取第一个
     *
     * @param ts                       数据
     * @param filed                    字段
     * @param repetitionSourceToTarget 返回的对象
     * @param <T>                      返回对象
     * @param <E>                      字段
     * @return
     */
    public static <T, E> T equalsObjFiled(T[] ts, E filed, RepetitionSourceToTarget<T, E> repetitionSourceToTarget) {
        if (CollectionUtils.isEmpty(ts) || null == filed || null == repetitionSourceToTarget) {
            return null;
        }
        for (T t : ts) {
            E e = repetitionSourceToTarget.deRepetition(t);
            if (filed.equals(e)) {
                return t;
            }
        }
        return null;
    }


}
