package com.jeeplus.test.reimbursement.reimbursementType.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jeeplus.core.service.TreeService;
import com.jeeplus.core.service.dto.TreeDTO;
import com.jeeplus.test.reimbursement.reimbursementType.domain.ReimbursementTypeInfo;
import com.jeeplus.test.reimbursement.reimbursementType.mapper.ReimbursementTypeMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class ReimbursementTypeForTreeDataService extends TreeService<ReimbursementTypeMapper, ReimbursementTypeInfo> {

    @Resource
    private ReimbursementTypeMapper typeMapper;

    /**
     * 获取JSON树形数据。
     *
     * @param extId 排除的ID
     * @param type 禁选类型
     * @return
     */
    public List<ReimbursementTypeInfo> treeDataForType(String extId, String type) throws Exception{
        List <ReimbursementTypeInfo> allList = super.list (new LambdaQueryWrapper<>( (Class <ReimbursementTypeInfo>) entityClass ).orderByAsc ( ReimbursementTypeInfo::getSort ));
        ReimbursementTypeInfo root = entityClass.getConstructor ( ).newInstance ( );
        root.setId ( TreeDTO.getRootId () );
        List <ReimbursementTypeInfo> rootTree = this.formatListToTreeForType ( root, allList, extId, type );
        return rootTree;
    }

    /**
     * 以root为根节点, 将allList从线性列表转为树形列表
     *
     * @param root    根节点, 为空抛出空指针异常
     * @param allList 所有需要参与构造为树的列表
     * @param extId   需要排除在树之外的节点(子节点一并被排除)
     * @return java.util.List<T>
     * @Author 滕鑫源
     * @Date 2020/10/23 17:04
     **/
    public List <ReimbursementTypeInfo> formatListToTreeForType (ReimbursementTypeInfo root, List <ReimbursementTypeInfo> allList, String extId, String type) {
        String rootId = root.getId ( );
        // 最终的树形态
        List <ReimbursementTypeInfo> trees = Lists.newArrayList ( );

        // 把需要构造树的所有列表, 根据以父id作为key, 整理为列表
        Map<String, List <ReimbursementTypeInfo>> treeMap = Maps.newHashMap ( );
        for (ReimbursementTypeInfo entity : allList) {
            List <ReimbursementTypeInfo> entities = treeMap.get ( entity.getParentId ( ) );
            if ( entities == null ) {
                entities = Lists.newLinkedList ( );
            }

            // 剔除排除项, 构造treeMap, 转递归为线性操作
            if ( StrUtil.isBlank ( extId ) || (!extId.equals ( entity.getId ( ) ) && entity.getParentIds ( ).indexOf ( "," + extId + "," ) == -1) ) {
                entities.add ( entity );
                treeMap.put ( entity.getParentId ( ), entities );
            }

            if (StringUtils.isNotEmpty(type)) {
                //禁选类型设置disable值为true
                if (type.contains(entity.getLevel())) {
                    entity.setDisabled(true);
                }
            }
        }

        // 没有给定的子树, 返回空树
        if ( treeMap.get ( rootId ) == null || treeMap.get ( rootId ).isEmpty ( ) ) {
            return trees;
        }

        // 开始递归格式化
        List <ReimbursementTypeInfo> children = treeMap.get ( rootId );
        for (ReimbursementTypeInfo parent : children) {
            formatFillChildren ( parent, treeMap );
            trees.add ( parent );
        }
        if ( StrUtil.equals ( rootId, TreeDTO.getRootId () ) ) {
            return children;
        } else {
            root.setChildren ( trees );
            return Lists.newArrayList ( root );
        }
    }

    /**
     * 从treeMap中取出子节点填入parent, 并递归此操作
     *
     * @param parent
     * @param treeMap
     * @return void
     * @Author 滕鑫源
     * @Date 2020/9/30 16:33
     **/
    private void formatFillChildren(ReimbursementTypeInfo parent, Map <String, List <ReimbursementTypeInfo>> treeMap) {
        List <ReimbursementTypeInfo> children = treeMap.get ( parent.getId ( ) );
        parent.setChildren ( children );
        if ( children != null && !children.isEmpty ( ) ) {
            for (ReimbursementTypeInfo child : children) {
                formatFillChildren ( child, treeMap );
            }
        }
    }

}
