package com.qiaoba.module.system.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 树工具类 遍历子节点
 *
 * @author ailanyin
 * @version 1.0
 * @since 2021-08-31
 */
public class TreeUtil {

    public static <T> List<T> buildTree(List<T> trees, Class<T> clazz, String idFieldName, String parentIdFieldName, String childIdFieldName) {
        List<T> returnList = new ArrayList<>();
        List<Object> tempList = new ArrayList<>();
        for (T tree : trees) {
            tempList.add(ReflectUtil.getFieldValue(tree, ReflectUtil.getField(clazz, idFieldName)));
        }

        for (T tree : trees) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(ReflectUtil.getFieldValue(tree, ReflectUtil.getField(clazz, parentIdFieldName)))) {
                recursionFn(trees, clazz, tree, idFieldName, parentIdFieldName, childIdFieldName);
                returnList.add(tree);
            }
        }

        if (returnList.isEmpty()) {
            returnList = trees;
        }

        return returnList;
    }

    /**
     * 递归列表
     */
    private static <T> void recursionFn(List<T> list, Class<T> clazz, T t, String idFieldName, String parentIdFieldName, String childIdFieldName) {
        // 得到子节点列表
        List<T> childList = getChildList(list, t, clazz, idFieldName, parentIdFieldName);
        ReflectUtil.invoke(t, ReflectUtil.getMethodByName(clazz, getSetMethodName(childIdFieldName)), childList);

        for (T tChild : childList) {
            if (hasChild(list, tChild, clazz, idFieldName, parentIdFieldName)) {
                recursionFn(list, clazz, tChild, idFieldName, parentIdFieldName, childIdFieldName);
            }
        }
    }

    private static String getSetMethodName(String field) {
        return "set" + StrUtil.upperFirst(field);
    }

    /**
     * 得到子节点列表
     */
    private static <T> List<T> getChildList(List<T> list, T t, Class<T> clazz, String idFieldName, String parentIdFieldName) {
        List<T> childList = new ArrayList<>();
        for (T n : list) {
            Object parentId = ReflectUtil.getFieldValue(n, ReflectUtil.getField(clazz, parentIdFieldName));
            Object id = ReflectUtil.getFieldValue(t, ReflectUtil.getField(clazz, idFieldName));
            if (ObjectUtil.isNotEmpty(parentId) && ObjectUtil.isNotEmpty(id) && parentId.toString().equals(id.toString())) {
                childList.add(n);
            }

        }
        return childList;
    }

    /**
     * 判断是否有子节点
     */
    private static <T> boolean hasChild(List<T> list, T t, Class<T> clazz, String idFieldName, String parentIdFieldName) {
        return getChildList(list, t, clazz, idFieldName, parentIdFieldName).size() > 0;
    }

}
