package com.xjrsoft.common.utils;

import cn.hutool.core.util.StrUtil;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.model.tree.ITreeNode;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: tzx
 * @Date:2022/3/7 15:45
 */
public class TreeUtil {


    public TreeUtil() {
    }

    /**
     * 构建树结构
     * @param items
     * @return
     * @param <T>
     */
    public static <T extends ITreeNode<T,V>,V> List<T> build(List<T> items) {

        List<String> notParents = new ArrayList<>();

        items.forEach((node) -> {
            V parentId = node.getParentId();

            if(node.getChildren() == null){
                node.setChildren(new ArrayList<>());
            }

            //如果在List里面 找不到当前节点的父节点，则当前节点为顶级节点
            if (items.stream().noneMatch(x -> StrUtil.equals(x.getId().toString(), String.valueOf(parentId)))) {
                notParents.add(node.getId().toString());
            }

            if (!StrUtil.isEmptyIfStr(parentId) || !StrUtil.equals(String.valueOf(parentId), String.valueOf(GlobalConstant.FIRST_NODE_VALUE))) {
                items.stream().filter(x -> StrUtil.equals(x.getId().toString(), String.valueOf(parentId)))
                        .findAny()
                        .ifPresent(parentNode -> {
                            //如果子级为空 需要使用setChildren实例化一个空列表
                            if(parentNode.getChildren() == null){
                                parentNode.setChildren(new ArrayList<>());
                            }
                            parentNode.getChildren().add(node);
                        });
            }

        });

        return items.stream().filter(x -> StrUtil.isEmptyIfStr(x.getParentId()) || StrUtil.equals(String.valueOf(x.getParentId()), String.valueOf(GlobalConstant.FIRST_NODE_VALUE)) || notParents.contains(x.getId().toString())).collect(Collectors.toList());
    }

    /**
     * 构建树结构（目前最快的构建方式）
     */
    public static <T extends ITreeNode<T,V>,V> List<T> buildMapTree(List<T> list, V parentId) {
        // 存放按parentId分组的数据
        Map<V, List<T>> map = new LinkedHashMap<>();

        list.forEach(node -> {
            if (node.getParentId() == null){
                node.setParentId(parentId);
            }
            // 取出同一个父亲下的兄弟
            List<T> brotherList = map.get(node.getParentId());
            // 判断非空
            brotherList = brotherList == null ? new LinkedList<>() : brotherList;
            // 加入到兄弟里面
            brotherList.add(node);
            // 把兄弟们重新放到map里面
            map.put(node.getParentId(), brotherList);
        });

        list.forEach(node -> {
            // 去map找它孩子
            List<T> childrenList = map.get(node.getId());
            // 把它的孩子丢进去
            node.setChildren(childrenList);
        });
        return map.get(parentId);
    }


    /**
     *  根据每一个顶级节点（根节点）进行构建树形结构
     *  @return  构建整棵树
     */
    public static <T extends ITreeNode<T,V>,V> List<T> buildTree(List<T> list, V parentId){
        // treeNodes：保存一个顶级节点所构建出来的完整树形
        List<T> treeNodes = new ArrayList<T>();
        // getRootNode()：获取所有的根节点
        for (T treeRootNode : getRootNode(list,parentId)) {

            // 将顶级节点进行构建子树
            treeRootNode = buildChildTree(treeRootNode,list);
            // 完成一个顶级节点所构建的树形，增加进来
            treeNodes.add(treeRootNode);
        }
        return treeNodes;
    }

    /**
     *   获取需构建的所有根节点（顶级节点）
     *   @return 所有根节点List集合
     */
    private static <T extends ITreeNode<T,V>,V> List<T> getRootNode(List<T> nodeList, V parentId){
        // 保存所有根节点（所有根节点的数据）
        List<T> rootNodeList = new ArrayList<>();
        // treeNode：查询出的每一条数据（节点）
        for (T treeNode : nodeList){
            if (treeNode.getParentId() == null){
                treeNode.setParentId(parentId);
            }
            // 判断当前节点是否为根节点，此处注意：若parentId类型是String，则要采用equals()方法判断。
            if (treeNode.getParentId() == parentId) {
                rootNodeList.add(treeNode);
            }
        }
        return rootNodeList;
    }

    /**
     *  递归-----构建子树形结构
     *  @param  pNode 根节点（顶级节点）
     *  @return 整棵树
     */
    private static <T extends ITreeNode<T,V>,V> T buildChildTree(T pNode,List<T> nodeList){
        List<T> childTree = new ArrayList<>();
        // nodeList：所有节点集合（所有数据）
        for (T treeNode : nodeList) {
            V parentId = treeNode.getParentId();
            // 判断当前节点的父节点ID是否等于根节点的ID，即当前节点为其下的子节点
            if (parentId != null && treeNode.getParentId().equals(pNode.getId())) {
                // 再递归进行判断当前节点的情况，调用自身方法
                childTree.add(buildChildTree(treeNode,nodeList));
            }
        }
        // for循环结束，即节点下没有任何节点，树形构建结束，设置树结果
        pNode.setChildren(childTree);
        return pNode;
    }
}
