package com.yeejoin.amos.boot.biz.common.utils;

import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;

/**
 * 生成树工具类
 *
 * @author DELL
 * @return <PRE>
 * author tw
 * date 2021/6/10
 * </PRE>
 */
public class TreeParser {

    public static final Integer CODE_LENGTH = 6;

    /**
     * @param topId                     父id
     * @param entityList                数据集合
     * @param packageURL                集合对象包名+类名
     * @param IDMethodName              集合对象获取树id 方法名
     * @param IDHierarchy               集合对象获取树id 来源于自己 还是父级(  1自己，2 父级 ，3 父级的父级)
     * @param NAMEMethodName            集合对象获取树name 方法名
     * @param PARENTIDMethodName        集合对象获取树父id 方法名
     * @param List<FirefightersTreeDto>
     * @return java.util.List<com.yeejoin.amos.boot.module.jcs.api.vo.Menu>
     * <PRE>
     * author tw
     * date 2021/6/10
     * </PRE>
     */
    @SuppressWarnings("unchecked")
    public static List<Menu> getTree(Long topId, @SuppressWarnings("rawtypes") Collection entityList, String packageURL, String IDMethodName, int IDHierarchy, String NAMEMethodName, String PARENTIDMethodName, List<FirefightersTreeDto> list) throws Exception {
        List<Menu> resultList = new ArrayList<>();
        @SuppressWarnings("rawtypes")
        Class clazz = Class.forName(packageURL);
        Method IDMethodNameme = null;
        switch (IDHierarchy) {
            case 1:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
            case 2:
                IDMethodNameme = clazz.getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            case 3:
                IDMethodNameme = clazz.getSuperclass().getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            default:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
        }

        Method NAMEMethodNameme = clazz.getDeclaredMethod(NAMEMethodName);
        Method PARENTIDMethodNameme = clazz.getDeclaredMethod(PARENTIDMethodName);
        //获取顶层元素集合  
        Long parentId;
        for (Object ob : entityList) {

            Object entity = clazz.cast(ob);

            parentId = PARENTIDMethodNameme.invoke(entity) != null ? Long.valueOf(String.valueOf(PARENTIDMethodNameme.invoke(entity))) : null;

            if (parentId == null || topId == parentId) {
                String codeString = String.valueOf(IDMethodNameme.invoke(entity));
                Integer num = 0;
                if (list != null && list.size() > 0) {
                    for (FirefightersTreeDto map : list) {
                        if (map.getJobTitleCode().equals(codeString)) {
                            num = Integer.valueOf((String) map.getNum());
                            break;
                        }
                    }
                    ;

                }
                Menu menu = new Menu(Long.valueOf(codeString), String.valueOf(NAMEMethodNameme.invoke(entity)), parentId, num);
                resultList.add(menu);
            }
        }
        //获取每个顶层元素的子数据集合  
        for (Menu entity : resultList) {
            entity.setChildren(getSub(entity.getId(), entityList, packageURL, IDMethodName, IDHierarchy, NAMEMethodName, PARENTIDMethodName, list));
        }

        return resultList;
    }

    /**
     * 获取子数据集合
     */
    @SuppressWarnings("unchecked")
    private static List<Menu> getSub(Long topId, @SuppressWarnings("rawtypes") Collection entityList, String packageURL, String IDMethodName, int IDHierarchy, String NAMEMethodName, String PARENTIDMethodName, List<FirefightersTreeDto> list) throws Exception {
        List<Menu> childList = new ArrayList<>();
        @SuppressWarnings("rawtypes")
        Class clazz = Class.forName(packageURL);
        Method IDMethodNameme = null;
        switch (IDHierarchy) {
            case 1:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
            case 2:
                IDMethodNameme = clazz.getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            case 3:
                IDMethodNameme = clazz.getSuperclass().getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            default:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
        }
        Method NAMEMethodNameme = clazz.getDeclaredMethod(NAMEMethodName);
        Method PARENTIDMethodNameme = clazz.getDeclaredMethod(PARENTIDMethodName);
        Long parentId;
        //子集的直接子对象  
        for (Object ob : entityList) {
            Object entity = clazz.cast(ob);

            parentId = PARENTIDMethodNameme.invoke(entity) != null ? Long.valueOf(String.valueOf(PARENTIDMethodNameme.invoke(entity))) : null;

            if (parentId == null) {
                if (topId == parentId) {

                    String codeString = String.valueOf(IDMethodNameme.invoke(entity));
                    Integer num = 0;
                    if (list != null && list.size() > 0) {
                        for (FirefightersTreeDto map : list) {
                            if (map.getJobTitleCode().equals(codeString)) {
                                num = Integer.valueOf((String) map.getNum());
                                break;
                            }
                        }
                        ;

                    }
                    Menu menu = new Menu(Long.valueOf(codeString), String.valueOf(NAMEMethodNameme.invoke(entity)), parentId, num);
                    childList.add(menu);
                }
            } else {
                if (topId.longValue() == parentId.longValue()) {


                    String codeString = String.valueOf(IDMethodNameme.invoke(entity));
                    Integer num = 0;
                    if (list != null && list.size() > 0) {
                        for (FirefightersTreeDto map : list) {
                            if (map.getJobTitleCode().equals(codeString)) {
                                num = Integer.valueOf((String) map.getNum());
                                break;
                            }
                        }
                        ;

                    }
                    Menu menu = new Menu(Long.valueOf(codeString), String.valueOf(NAMEMethodNameme.invoke(entity)), parentId, num);
                    childList.add(menu);
                }
            }

        }

        //子集的间接子对象  
        for (Menu entity : childList) {
            entity.setChildren(getSub(entity.getId(), entityList, packageURL, IDMethodName, IDHierarchy, NAMEMethodName, PARENTIDMethodName, list));
        }

        //递归退出条件  
        if (childList.size() == 0) {
            return null;
        }

        return childList;
    }


    /**
     * @param topId              父id
     * @param entityList         数据集合
     * @param packageURL         集合对象包名+类名
     * @param IDMethodName       集合对象获取树id 方法名
     * @param IDHierarchy        集合对象获取树id 来源于自己 还是父级(  1自己，2 父级 ，3 父级的父级)
     * @param NAMEMethodName     集合对象获取树name 方法名
     * @param PARENTIDMethodName 集合对象获取树父id 方法名
     * @return java.util.List<com.yeejoin.amos.boot.module.jcs.api.vo.Menu>
     * <PRE>
     * author tw
     * date 2021/6/10
     * </PRE>
     */
    @SuppressWarnings("unchecked")
    public static List<MenuFrom> getTreexin(String topId, @SuppressWarnings("rawtypes") Collection entityList,
                                            String packageURL, String IDMethodName, int IDHierarchy,
                                            String NAMEMethodName, String PARENTIDMethodName,
                                            String nodeTypeMethodName) throws Exception {
        List<MenuFrom> resultList = new ArrayList<>();
        @SuppressWarnings("rawtypes")
        Class clazz = Class.forName(packageURL);
        Method IDMethodNameme = null;
        switch (IDHierarchy) {
            case 1:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
            case 2:
                IDMethodNameme = clazz.getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            case 3:
                IDMethodNameme = clazz.getSuperclass().getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            default:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
        }

        Method NAMEMethodNameme = clazz.getDeclaredMethod(NAMEMethodName);
        Method PARENTIDMethodNameme = clazz.getDeclaredMethod(PARENTIDMethodName);
        Method nodeTypeMethod = null;
        if (!ValidationUtil.isEmpty(nodeTypeMethodName)) {
            nodeTypeMethod = clazz.getDeclaredMethod(nodeTypeMethodName);
        }
        //获取顶层元素集合
        String parentId;
        for (Object ob : entityList) {

            Object entity = clazz.cast(ob);

            parentId = PARENTIDMethodNameme.invoke(entity) != null ? String.valueOf(PARENTIDMethodNameme.invoke(entity)) : null;

            if (parentId == null || parentId.equals(topId)) {
                MenuFrom menu = new MenuFrom(String.valueOf(IDMethodNameme.invoke(entity)),
                        String.valueOf(IDMethodNameme.invoke(entity)), String.valueOf(IDMethodNameme.invoke(entity)),
                        String.valueOf(NAMEMethodNameme.invoke(entity)),
                        String.valueOf(NAMEMethodNameme.invoke(entity)),
                        String.valueOf(NAMEMethodNameme.invoke(entity)), parentId,
                        String.valueOf(nodeTypeMethod == null ? "0" : nodeTypeMethod.invoke(entity)));
                resultList.add(menu);
            }
        }
        //获取每个顶层元素的子数据集合  
        for (MenuFrom entity : resultList) {
            List<MenuFrom> list = getSubxin(entity.getKey(), entityList, packageURL, IDMethodName, IDHierarchy,
                    NAMEMethodName, PARENTIDMethodName, nodeTypeMethodName);
            if (list != null && list.size() > 0) {
                entity.setIsLeaf(false);
            }
            entity.setChildren(list);
        }

        return resultList;
    }

    /**
     * 获取子数据集合
     */
    @SuppressWarnings("unchecked")
    private static List<MenuFrom> getSubxin(String topId, @SuppressWarnings("rawtypes") Collection entityList,
                                            String packageURL, String IDMethodName, int IDHierarchy,
                                            String NAMEMethodName, String PARENTIDMethodName,
                                            String nodeTypeMethodName) throws Exception {
        List<MenuFrom> childList = new ArrayList<>();
        @SuppressWarnings("rawtypes")
        Class clazz = Class.forName(packageURL);
        Method IDMethodNameme = null;
        switch (IDHierarchy) {
            case 1:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
            case 2:
                IDMethodNameme = clazz.getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            case 3:
                IDMethodNameme = clazz.getSuperclass().getSuperclass().getDeclaredMethod(IDMethodName);
                break;
            default:
                IDMethodNameme = clazz.getDeclaredMethod(IDMethodName);
                break;
        }
        Method NAMEMethodNameme = clazz.getDeclaredMethod(NAMEMethodName);
        Method PARENTIDMethodNameme = clazz.getDeclaredMethod(PARENTIDMethodName);
        Method nodeTypeMethod = null;
        if (!ValidationUtil.isEmpty(nodeTypeMethodName)) {
            nodeTypeMethod = clazz.getDeclaredMethod(nodeTypeMethodName);
        }
        String parentId;
        //子集的直接子对象  
        for (Object ob : entityList) {
            Object entity = clazz.cast(ob);

            parentId = PARENTIDMethodNameme.invoke(entity) != null ? String.valueOf(PARENTIDMethodNameme.invoke(entity)) : null;

            if (parentId == null) {
                if (parentId == topId) {
                    MenuFrom menu = new MenuFrom(String.valueOf(IDMethodNameme.invoke(entity)),
                            String.valueOf(IDMethodNameme.invoke(entity)), String.valueOf(IDMethodNameme.invoke(entity)),
                            String.valueOf(NAMEMethodNameme.invoke(entity)),
                            String.valueOf(NAMEMethodNameme.invoke(entity)),
                            String.valueOf(NAMEMethodNameme.invoke(entity)), parentId,
							String.valueOf(nodeTypeMethod == null ? "0" : nodeTypeMethod.invoke(entity)));
                    childList.add(menu);
                }
            } else {
                if (topId != null && topId.equals(parentId)) {
                    MenuFrom menu = new MenuFrom(String.valueOf(IDMethodNameme.invoke(entity)),
                            String.valueOf(IDMethodNameme.invoke(entity)),
                            String.valueOf(IDMethodNameme.invoke(entity)),
                            String.valueOf(NAMEMethodNameme.invoke(entity)),
                            String.valueOf(NAMEMethodNameme.invoke(entity)),
                            String.valueOf(NAMEMethodNameme.invoke(entity)), parentId,
                            String.valueOf(nodeTypeMethod == null ? "0" : nodeTypeMethod.invoke(entity)));
                    menu.setIsLeaf(false);
                    childList.add(menu);
                }
            }

        }

        //子集的间接子对象  
        for (MenuFrom entity : childList) {
            entity.setChildren(getSubxin(entity.getKey(), entityList, packageURL, IDMethodName, IDHierarchy,
                    NAMEMethodName, PARENTIDMethodName, nodeTypeMethodName));
        }

        //递归退出条件  
        if (childList.size() == 0) {
            return null;
        }

        return childList;
    }

    public static String genTreeCode() {
        int length = CODE_LENGTH;
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }
} 
