const { AccessControl } = require('accesscontrol');
const { buildAc } = require('./can');

class Menu {
  ac;
  menuList;

  /**
   * 
   * @param {AccessControl} ac 
   * @param {*} menuList 
   */
  constructor(menuList, ac) {
    this.ac = ac;
    this.menu = {
      name: 'ROOT',
      children: menuList,
    }
  }

  /*
   * 深度优先
   */
  travelDFS(menu, callback, depth) {
    depth = depth || 0;
    if (menu.children) {
      menu.children.forEach(c => this.travelDFS(c, callback, depth + 1))
    }
    callback(menu, depth);
  }

  /*
   * 广度优先
   */
  travelBFS(menu, callback, depth) {
    depth = depth || 0;
    callback(menu, depth);
    if (menu.children) {
      menu.children.forEach(c => this.travelBFS(c, callback, depth + 1))
    }
  }

  checkPermission(role, permission) {
    permission.role = role;
    return this.ac.permission(permission).granted;
  }

  /*
   * 根据角色获取菜单
   */
  getByRole(role) {
    let menu = this.dcopy(this.menu);
    this.travelDFS(menu, (item) => {
      let keep = item.permission ? this.checkPermission(role, item.permission) : true;
      item.keep = item.children ? item.children.some(c => c.keep) : keep;
    });
    this.travelBFS(menu, (item) => {
      if (item.children) item.children = item.children.filter(c => c.keep);
    });

    //移除无用信息
    this.travelBFS(menu, (item) => {
      delete item.permission;
      delete item.keep;
    });

    //this.print(menu);
    //console.log(JSON.stringify(menu, null, 2));
    return menu.children;
  }


  print(menu) {
    menu = menu || this.menu;
    this.travelBFS(menu, (item, depth) => {
      console.log(
        '\t\t\t\t\t\t\t\t\t'.substr(0, depth), depth, item.name, item.url);
    })
  }

  dcopy(obj) {
    return JSON.parse(JSON.stringify(obj));
  }

}





if (require.main === module) {

  (async () => {
    let username = 'chengen.test';
    let user = await require('../../models').User.findOne({ username });
    if (!user) throw new Error(`user ${username}`);
    let ac = await buildAc(user._id);
    const menu = new Menu(require('./menu-config'), ac);
    menu.print();
    let roleMenu = menu.getByRole('user');
    //let roleMenu = menu.getByRole('调解员');
    console.log(JSON.stringify(roleMenu, null, 2));

  })().catch(console.error)

}

module.exports = Menu;
