package com.mossle.auth.support;

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

import javax.annotation.Resource;

import com.mossle.api.menu.MenuConnector;
import com.mossle.api.menu.MenuDTO;
import com.mossle.api.tenant.TenantHolder;
import com.mossle.api.userauth.UserAuthConnector;

import com.mossle.auth.persistence.domain.Menu;
import com.mossle.auth.persistence.manager.MenuManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 用来通过用户权限来动态生成菜单.
 */
public class MenuConnectorImpl implements MenuConnector {
    private static Logger logger = LoggerFactory
            .getLogger(MenuConnectorImpl.class);
    private MenuManager menuManager;
    private UserAuthConnector userAuthConnector;
    private TenantHolder tenantHolder;
    private MenuCache menuCache;

    /**
     * systemCode算子系统的标识，比如个人事务子系统，账号子系统.
     */
    public List<MenuDTO> findMenus(String systemCode, String userId) {
        String tenantId = tenantHolder.getTenantId();
        List<MenuDTO> menuDtos = this.menuCache.findByCode(systemCode);

        if (menuDtos == null) {
            String hql = "from Menu where menu.display='true' and menu.type='system' and menu.code=? order by priority";
            List<Menu> menus = menuManager.find(hql, systemCode);
            menuDtos = this.convertMenuDtos(menus, false);
            this.menuCache.updateByCode(systemCode, menuDtos);
        }

        List<String> permissions = userAuthConnector.findById(userId, tenantId)
                .getPermissions();

        return this.filterMenuDtos(menuDtos, permissions, false);
    }

    /**
     * 获得所有子系统的入口，比如账号子系统.
     */
    public List<MenuDTO> findSystemMenus(String userId) {
        String tenantId = tenantHolder.getTenantId();
        List<MenuDTO> menuDtos = this.menuCache.findEntries();

        if (menuDtos == null) {
            List<Menu> menus = menuManager
                    .find("from Menu where type='entry' and display='true'");
            menuDtos = this.convertMenuDtos(menus, true);
            this.menuCache.updateEntries(menuDtos);
        }

        List<String> permissions = userAuthConnector.findById(userId, tenantId)
                .getPermissions();

        return this.filterMenuDtos(menuDtos, permissions, true);
    }

    /**
     * 将menu转换为menuDto.
     */
    public List<MenuDTO> convertMenuDtos(List<Menu> menus, boolean excludeModule) {
        List<MenuDTO> menuDtos = new ArrayList<MenuDTO>();

        for (Menu menu : menus) {
            if (!("true".equals(menu.getDisplay()))) {
                continue;
            }

            if (excludeModule && "module".equals(menu.getType())) {
                continue;
            }

            MenuDTO menuDto = this.convertMenuDto(menu, excludeModule);
            menuDtos.add(menuDto);
        }

        return menuDtos;
    }

    /**
     * 把menu数据复制给dto.
     */
    public MenuDTO convertMenuDto(Menu menu, boolean excludeModule) {
        MenuDTO menuDto = new MenuDTO();
        menuDto.setCode(menu.getCode());
        menuDto.setTitle(menu.getTitle());
        // 为了jsp里使用方便，要去掉url前面的/
        menuDto.setUrl(this.processUrl(menu.getUrl()));

        if (menu.getPerm() != null) {
            menuDto.setPermission(menu.getPerm().getCode());
        }

        menuDto.setType(menu.getType());

        List<Menu> menus = menuManager.find(
                "from Menu where display='true' and menu=? order by priority",
                menu);
        List<MenuDTO> menuDtos = this.convertMenuDtos(menus, excludeModule);
        menuDto.setChildren(menuDtos);

        return menuDto;
    }

    /**
     * 按个人权限过滤菜单.
     */
    public List<MenuDTO> filterMenuDtos(List<MenuDTO> menuDtos,
            List<String> permissions, boolean excludeModule) {
        List<MenuDTO> result = new ArrayList<MenuDTO>();

        for (MenuDTO menuDto : menuDtos) {
            if (excludeModule && "module".equals(menuDto.getType())) {
                continue;
            }

            if ((!permissions.contains("*"))
                    && (!permissions.contains(menuDto.getPermission()))) {
                logger.debug("permissions : {}", permissions);
                logger.debug("skip : {}", menuDto.getPermission());

                continue;
            }

            MenuDTO item = this.filterMenuDto(menuDto, permissions,
                    excludeModule);
            result.add(item);
        }

        return result;
    }

    /**
     * 把menu数据复制给dto.
     */
    public MenuDTO filterMenuDto(MenuDTO menuDto, List<String> permissions,
            boolean excludeModule) {
        MenuDTO item = new MenuDTO();
        item.setCode(menuDto.getCode());
        item.setTitle(menuDto.getTitle());
        // 为了jsp里使用方便，要去掉url前面的/
        item.setUrl(this.processUrl(menuDto.getUrl()));

        List<MenuDTO> children = this.filterMenuDtos(menuDto.getChildren(),
                permissions, excludeModule);
        item.setChildren(children);

        return item;
    }

    /**
     * 如果url以/开头，要去掉/，这样前端jsp渲染的时候就方便多了.
     */
    public String processUrl(String url) {
        if (url == null) {
            return "";
        }

        if (url.length() == 0) {
            return "";
        }

        if (url.charAt(0) != '/') {
            return url;
        }

        for (int i = 0; i < url.length(); i++) {
            if (url.charAt(i) != '/') {
                return url.substring(i);
            }
        }

        return "";
    }

    @Resource
    public void setMenuManager(MenuManager menuManager) {
        this.menuManager = menuManager;
    }

    @Resource
    public void setUserAuthConnector(UserAuthConnector userAuthConnector) {
        this.userAuthConnector = userAuthConnector;
    }

    @Resource
    public void setTenantHolder(TenantHolder tenantHolder) {
        this.tenantHolder = tenantHolder;
    }

    @Resource
    public void setMenuCache(MenuCache menuCache) {
        this.menuCache = menuCache;
    }
}
