package com.pj.project4sp.menu;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.pj.utils.sg.AjaxError;

/**
 * 工具类：sp_menu -- 菜单表
 * @author click33 
 *
 */
@Component
public class SpMenuUtil {

	
	/** 底层 Mapper 对象 */
	public static SpMenuMapper spMenuMapper;
	@Autowired
	private void setSpMenuMapper(SpMenuMapper spMenuMapper) {
		SpMenuUtil.spMenuMapper = spMenuMapper;
	}
	
	/** 
	 * 将一个 SpMenu 对象进行进行数据完整性校验 (方便add/update等接口数据校验) 
	 */
	static void checkAndSet(SpMenu s) {
		// 验证: 父菜单id 
		checkParentId(s);
		
		// 验证: 菜单id 
		AjaxError.notIsNull(s.getId(), "[ 菜单ID ] 不能为空");		
		SpMenu s2 = spMenuMapper.getById(s.getId());
		AjaxError.notTrue(s2 != null && s2.getAid().equals(s.getAid()) == false, "菜单ID 已存在，更换一个试试吧");	
		
		AjaxError.notIsNull(s.getTitle(), "[ 菜单名称 ] 不能为空");		// 验证: 菜单名称 
		AjaxError.notIsNull(s.getType(), "[ 菜单类型 ] 不能为空");		// 验证: 菜单类型 
		if(Arrays.asList("dir", "com", "link", "btn").contains(s.getType()) == false) {
			AjaxError.throwMsg("[ 菜单类型 ] 值必须为以下其一：dir, com, link, btn");
		}
		
		// 不同 type 值 校验不同的属性，并清除其它属性 (dir=目录, com=组件, btn=按钮, link=链接) 
		String type = s.getType();
		if(type.equals("com")) {
			AjaxError.notIsNull(s.getComponentPath(), "[ 指向组件 ] 不能为空");		// 验证: 组件路径 
			AjaxError.notIsNull(s.getAuth(), "[ 是否鉴权 ] 不能为空");		// 验证: 是否鉴权 
			s.setUrl(null);
		} 
		else if(type.equals("link")) {
			AjaxError.notIsNull(s.getUrl(), "[ 跳转链接 ] 不能为空");		// 验证: 菜单url (如果指定了此值，则通过 iframe 打开页面视图) 
			AjaxError.notIsNull(s.getAuth(), "[ 是否鉴权 ] 不能为空");		// 验证: 是否鉴权 
			s.setComponentPath(null);
		} 
		else if(type.equals("btn")) {
			s.setShow("no");
		}
		
		// 验证: 是否显示 (yes=永远显示,no=永远不显示,auth=根据权限决定是否显示) 
		AjaxError.notIsNull(s.getShow(), "请选择 [ 何时显示 ]");		
		if(Arrays.asList("yes", "no", "auth").contains(s.getShow()) == false) {
			AjaxError.throwMsg("[ 是否显示 ] 值必须为以下其一：yes, no, auth");
		}
		
		// 验证: 排序索引 
		AjaxError.notIsNull(s.getSort(), "[ 排序索引 ] 不能为空");		
	}

	// 校验一个菜单填写的父级菜单是否合法 
	static void checkParentId(SpMenu s) {
		// 父级就不能为空 
		AjaxError.notIsNull(s.getParentId(), "[ 所属父级 ] 不能为空");
		
		// 如果是顶级菜单，到此结束 
		if(s.getParentId().equals("-1")) {
			return;
		}
		// 父级不能不存在
		SpMenu parentMenu = spMenuMapper.getById(s.getParentId());
		AjaxError.notTrue(parentMenu == null, "[ 所属父级 ] 不存在");
		
		// 父级不能是自己
		AjaxError.notTrue(s.getParentId().equals(s.getId()), "[ 所属父级 ] 不能是自己");
		
		// 父级不能是自己的子级或者孙级 
		checkNotLoop(parentMenu, s.getId());
	}

	// 校验是否循环依赖：一个菜单的父级不能是指定 menuId
	static void checkNotLoop(SpMenu menu, String menuId) {
		// 是0，说明到顶级了，到此结束 
		if(menu.getParentId().equals("-1")) {
			return;
		}
		// 查不出的话，到此结束 
		SpMenu parentMenu = spMenuMapper.getById(menu.getParentId());
		if(parentMenu == null) {
			return;
		}
		// 判断
		AjaxError.notTrue(parentMenu.getId().equals(menuId), "[ 所属父级 ] 不能是自己的子级");
		
		// 递归模式，继续往上挖
		checkNotLoop(parentMenu, menuId);
	}
	
	/** 
	 * 获取一个SpMenu (方便复制代码用) [G] 
	 */ 
	static SpMenu getSpMenu() {
		SpMenu s = new SpMenu();	// 声明对象 
		s.setId("");		// 菜单id 
		s.setTitle("");		// 菜单名称 
		s.setIcon("");		// 菜单图标 
		s.setInfo("");		// 菜单介绍 
		s.setPath("");		// 菜单路由 
		s.setComponentPath("");		// 组件路径 
		s.setUrl("");		// 菜单url (如果指定了此值，则通过 iframe 打开页面视图) 
		s.setIsBlank(false);		// 是否属于外部链接 (如果为true, 则点击菜单时从新窗口打开url) 
		s.setShow("");		// 是否显示 (yes=永远显示,no=永远不显示,auth=根据权限决定是否显示) 
		s.setAuth(false);		// 是否鉴权 
		s.setParentId("");		// 父菜单id 
		s.setSort(0L);		// 排序索引 
		s.setCreateTime("");		// 创建时间 
		s.setUpdateTime("");		// 更新时间 
		return s;
	}
	

	/**
	 * 查集合 - 根据条件（参数为空时代表忽略指定条件）
	 * @param so 参数集合 
	 * @return 数据列表 
	 */
	public static List<SpMenu> getList(long roleId) {
		return spMenuMapper.getListByRoleId(roleId);
	}

	
	
	
}
