package com.izouma.awesomeadmin.service.impl;


import com.izouma.awesomeadmin.constant.AppConstant;
import com.izouma.awesomeadmin.dao.SysMenuMapper;
import com.izouma.awesomeadmin.dto.Page;
import com.izouma.awesomeadmin.dto.TreeNode;
import com.izouma.awesomeadmin.model.SysMenu;
import com.izouma.awesomeadmin.model.SysRole;
import com.izouma.awesomeadmin.model.UserInfo;
import com.izouma.awesomeadmin.service.SysMenuService;
import com.izouma.awesomeadmin.service.SysRoleService;
import com.izouma.awesomeadmin.service.UserInfoService;
import com.izouma.awesomeadmin.util.TreeUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * sys_menu service接口实现类
 * Tue Apr 10 18:09:44 CST 2018  Suo Chen Cheng
 */
@Service
public class SysMenuServiceImpl implements SysMenuService {

    private static Logger logger = Logger.getLogger(SysMenuServiceImpl.class);

    @Autowired
    private SysMenuMapper   sysMenuMapper;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private SysRoleService  sysRoleService;

    @Override
    public List<SysMenu> getSysMenuList(SysMenu record) {

        logger.info("getSysMenuList");
        try {

            return sysMenuMapper.queryAllSysMenu(record);
        } catch (Exception e) {
            logger.error("getSysMenuList", e);
        }

        return null;
    }

    @Override
    public List<SysMenu> getSysMenuByPage(Page page, SysMenu record) {

        logger.info("getSysMenuByPage");
        try {

            Map<String, Object> parameter = new HashMap<String, Object>();
            parameter.put("record", record);
            parameter.put(AppConstant.PAGE, page);

            return sysMenuMapper.querySysMenusByPage(parameter);
        } catch (Exception e) {
            logger.error("getSysMenuByPage", e);
        }

        return null;
    }

    @Override
    public SysMenu getSysMenuById(String id) {

        logger.info("getSysMenuById");
        try {

            return sysMenuMapper.selectByPrimaryKey(Integer.valueOf(id));
        } catch (Exception e) {
            logger.error("getSysMenuById", e);
        }

        return null;
    }

    @Override
    public SysMenu getSysMenu(SysMenu record) {

        logger.info("getSysMenu");
        try {

            return sysMenuMapper.querySysMenu(record);
        } catch (Exception e) {
            logger.error("getSysMenu", e);
        }

        return null;
    }

    @Override
    public boolean createSysMenu(SysMenu record) {

        logger.info("createSysMenu");
        try {

            int updates = sysMenuMapper.insertSelective(record);

            if (updates > 0) {
                return true;
            }
        } catch (Exception e) {
            logger.error("createSysMenu", e);
        }

        return false;
    }

    @Override
    public boolean deleteSysMenu(String id) {

        logger.info("deleteSysMenu");
        try {

            int updates = sysMenuMapper.delete(id);

            if (updates > 0) {
                return true;
            }
        } catch (Exception e) {
            logger.error("deleteSysMenu", e);
        }

        return false;
    }

    @Override
    public boolean updateSysMenu(SysMenu record) {

        logger.info("updateSysMenu");
        try {

            int updates = sysMenuMapper.updateByPrimaryKeySelective(record);

            if (updates > 0) {
                return true;
            }
        } catch (Exception e) {
            logger.error("updateSysMenu", e);
        }

        return false;
    }

    @Override
    public List<SysMenu> getMenuTree() {
        logger.info("getMenuTree");
        try {
            List<SysMenu> allMenus = getSysMenuList(new SysMenu());
            List<SysMenu> tree = new ArrayList<>();
            makeTree(allMenus, tree);
            return tree;
        } catch (Exception e) {
            logger.error("getMenuTree", e);
        }
        return null;
    }

    @Override
    public List<SysMenu> getMenuTree(Integer userId) {
        logger.info("getMenuTree");
        try {
            List<SysMenu> nodes = new ArrayList<>();
            List<SysMenu> entireTree = getMenuTree();
            List<String> menuIds = new ArrayList<>();
            for (SysRole role : sysRoleService.getUserRoles(userId)) {
                if (StringUtils.isNotEmpty(role.getMenuIds())) {
                    menuIds.addAll(Arrays.asList(role.getMenuIds().split(",")));
                }
            }
            removeDuplicate(menuIds);
            for (String id : menuIds) {
                List<SysMenu> list;
                list = getParents(new ArrayList<>(), entireTree, Integer.valueOf(id));
                list = list == null ? new ArrayList<>() : list;
                nodes.addAll(list);
            }
            nodes = nodes.stream().distinct().collect(Collectors.toList());
            List<SysMenu> tree = new ArrayList<>();
            makeTree(nodes, tree);
            return tree;
        } catch (Exception e) {
            logger.error("getMenuTree", e);
        }
        return null;
    }

    private void makeTree(List<SysMenu> nodes, List<SysMenu> tree) {
        for (SysMenu menu : nodes) {
            if (menu.getParentId() == 0) {
                tree.add(menu);
            }
            for (SysMenu node : nodes) {
                if (node.getParentId().equals(menu.getId())) {
                    if (menu.getChildren() == null) {
                        menu.setChildren(new ArrayList<>());
                    }
                    menu.getChildren().add(node);
                }
            }
            if (menu.getChildren() != null) {
                menu.getChildren().sort(Comparator.comparingInt(o -> o.getSort().intValue()));
            }
        }
        tree.sort(Comparator.comparingInt(o -> o.getSort().intValue()));
    }

    @Override
    public List<TreeNode> getMenuTree(boolean all, Integer userId) {

        logger.info("getMenuTree");
        try {
            List<SysMenu> pp = new ArrayList<>();
            if (all) {
                pp = getSysMenuList(new SysMenu());
            } else {
                List<String> menuIds = new ArrayList<>();
                for (SysRole role : sysRoleService.getUserRoles(userId)) {
                    if (StringUtils.isNotEmpty(role.getMenuIds())) {
                        menuIds.addAll(Arrays.asList(role.getMenuIds().split(",")));
                    }
                }
                removeDuplicate(menuIds);
                for (SysMenu menu : sysMenuMapper.selectByPrimaryKeys(StringUtils.join(menuIds, ","))) {
                    pp.addAll(getParents(menu));
                }
                List<SysMenu> list = new ArrayList<>();
                for (SysMenu menu : pp) {
                    if (!list.contains(menu)) {
                        list.add(menu);
                    }
                }
                pp = list;
            }

            List<TreeNode> trees = new ArrayList<>();
            List<TreeNode> tree = new ArrayList<>();
            for (SysMenu m : pp) {
                TreeNode treeNode = new TreeNode(String.valueOf(m.getId()), m.getName(), String.valueOf(m.getParentId()));
                treeNode.setExtra(m);
                tree.add(treeNode);
            }
            TreeUtils.buildTree(trees, tree);
            return trees;
        } catch (Exception e) {
            logger.error("updateSysMenu", e);
        }

        return null;
    }

    private List<SysMenu> getParents(SysMenu menu) {
        List<SysMenu> menuList = new ArrayList<>();
        menuList.add(menu);
        if (menu.getParentId() != null) {
            SysMenu parent = getSysMenuById(String.valueOf(menu.getParentId()));
            if (parent != null) {
                menuList.addAll(getParents(parent));
            }
        }
        return menuList;
    }

    private List removeDuplicate(List list) {
        HashSet h = new HashSet(list);
        list.clear();
        list.addAll(h);
        return list;
    }

    private List<SysMenu> getParents(List<SysMenu> parents, List<SysMenu> children, Integer id) {
        for (SysMenu child : children) {
            List<SysMenu> list = new ArrayList<>(parents);
            if (child.getId().equals(id)) {
                SysMenu copy = child.clone();
                copy.setChildren(null);
                list.add(copy);
                return list;
            } else if (child.getChildren() != null) {
                SysMenu copy = child.clone();
                copy.setChildren(null);
                list.add(copy);
                List<SysMenu> next = getParents(list, child.getChildren(), id);
                if (next != null) {
                    return next;
                }
            }
        }
        return null;
    }
}

