text: /**
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  import React, { PureComponent } from 'react';
  import { Layout, Menu, Icon } from 'antd';
  import pathToRegexp from 'path-to-regexp';
  import { Link } from 'dva/router';
  import styles from './index.less';
  
  const { Sider } = Layout;
  const { SubMenu } = Menu;
  
  // Allow menu.js config icon as string or ReactNode
  //   icon: 'setting',
  //   icon: 'http://demo.com/icon.png',
  //   icon: <Icon type="setting" />,
  const getIcon = (icon) => {
    if (typeof icon === 'string' && icon.indexOf('http') === 0) {
      return <img src={icon} alt="icon" className={styles.icon} />;
    }
    if (typeof icon === 'string' && icon.indexOf('/img') === 0) {
      return <img src={icon} alt="icon" className={styles.icon} />;
    }
    if (typeof icon === 'string') {
      return <Icon type={icon} />;
    }
    return icon;
  };
  
  export default class SiderMenu extends PureComponent {
    constructor(props) {
      super(props);
      this.menus = props.menuData;
      this.state = {
        openKeys: this.getDefaultCollapsedSubMenus(props),
      };
    }
    componentWillReceiveProps(nextProps) {
      if (nextProps.location.pathname !== this.props.location.pathname) {
        this.setState({
          openKeys: this.getDefaultCollapsedSubMenus(nextProps),
        });
      }
    }
    /**
     * Convert pathname to openKeys
     * /list/search/articles = > ['list','/list/search']
     * @param  props
     */
    getDefaultCollapsedSubMenus(props) {
      const { location: { pathname } } = props || this.props;
      // eg. /list/search/articles = > ['','list','search','articles']
      let snippets = pathname.split('/');
      // Delete the end
      // eg.  delete 'articles'
      snippets.pop();
      // Delete the head
      // eg. delete ''
      snippets.shift();
      // eg. After the operation is completed, the array should be ['list','search']
      // eg. Forward the array as ['list','list/search']
      snippets = snippets.map((item, index) => {
        // If the array length > 1
        if (index > 0) {
          // eg. search => ['list','search'].join('/')
          return snippets.slice(0, index + 1).join('/');
        }
        // index 0 to not do anything
        return item;
      });
      snippets = snippets.map((item) => {
        return this.getSelectedMenuKeys(`/${item}`)[0];
      });
      // eg. ['list','list/search']
      return snippets;
    }
    /**
     * Recursively flatten the data
     * [{path:string},{path:string}] => {path,path2}
     * @param  menus
     */
    getFlatMenuKeys(menus) {
      let keys = [];
      menus.forEach((item) => {
        if (item.children) {
          keys.push(item.path);
          keys = keys.concat(this.getFlatMenuKeys(item.children));
        } else {
          keys.push(item.path);
        }
      });
      return keys;
    }
    /**
     * Get selected child nodes
     * /user/chen => /user/:id
     */
    getSelectedMenuKeys = (path) => {
      const flatMenuKeys = this.getFlatMenuKeys(this.menus);
      return flatMenuKeys.filter((item) => {
        return pathToRegexp(`/${item}`).test(path);
      });
    }
    /**
    * Judge whether it is http link.return a or Link
    * @memberof SiderMenu
    */
    getMenuItemPath = (item) => {
      const itemPath = this.conversionPath(item.path);
      const icon = getIcon(item.icon);
      const { target, name } = item;
      // Is it a http link
      if (/^https?:\/\//.test(itemPath)) {
        return (
          <a href={itemPath} target={target}>
            {icon}<span>{name}</span>
          </a>
        );
      }
      return (
        <Link
          to={itemPath}
          target={target}
          replace={itemPath === this.props.location.pathname}
          onClick={() => this.props.onCollapse(true)}
        >
          {icon}<span>{name}</span>
        </Link>
      );
    }
    /**
     * get SubMenu or Item
     */
    getSubMenuOrItem=(item) => {
      if (item.children && item.children.some(child => child.name)) {
        return (
          <SubMenu
            title={
              item.icon ? (
                <span>
                  {getIcon(item.icon)}
                  <span>{item.name}</span>
                </span>
              ) : item.name
              }
            key={item.path}
          >
            {this.getNavMenuItems(item.children)}
          </SubMenu>
        );
      } else {
        return (
          <Menu.Item key={item.path}>
            {this.getMenuItemPath(item)}
          </Menu.Item>
        );
      }
    }
    /**
    * Get subnodes
    * @memberof SiderMenu
    */
    getNavMenuItems = (menusData) => {
      if (!menusData) {
        return [];
      }
      return menusData
        .filter(item => item.name && !item.hideInMenu)
        .map((item) => {
          const ItemDom = this.getSubMenuOrItem(item);
          return this.checkPermissionItem(item.authority, ItemDom);
        })
        .filter(item => !!item);
    }
    // conversion Path
    conversionPath=(path) => {
      if (path && path.indexOf('http') === 0) {
        return path;
      } else {
        return `/${path || ''}`.replace(/\/+/g, '/');
      }
    }
    // permission to check
    checkPermissionItem = (authority, ItemDom) => {
      if (this.props.Authorized && this.props.Authorized.check) {
        const { check } = this.props.Authorized;
        return check(
          authority,
          ItemDom
        );
      }
      return ItemDom;
    }
    handleOpenChange = (openKeys) => {
      const lastOpenKey = openKeys[openKeys.length - 1];
      const isMainMenu = this.menus.some(
        item => lastOpenKey && (item.key === lastOpenKey || item.path === lastOpenKey)
      );
      this.setState({
        openKeys: isMainMenu ? [lastOpenKey] : [...openKeys],
      });
    }
    render() {
      const { logo, collapsed, location: { pathname }, onCollapse } = this.props;
      const { openKeys } = this.state;
      // Don't show popup menu when it is been collapsed
      const menuProps = collapsed ? {} : {
        openKeys,
      };
      // if pathname can't match, use the nearest parent's key
      let selectedKeys = this.getSelectedMenuKeys(pathname);
      if (!selectedKeys.length) {
        selectedKeys = [openKeys[openKeys.length - 1]];
      }
      return (
        <Sider
          trigger={null}
          collapsible
          collapsed={collapsed}
          breakpoint="lg"
          onCollapse={onCollapse}
          width={256}
          className={styles.sider}
        >
          <div className={styles.logo} key="logo">
            <Link to="/">
              <img src={logo} alt="logo" />
              <h1>Sky Walking</h1>
            </Link>
          </div>
          <Menu
            key="Menu"
            theme="dark"
            mode="inline"
            {...menuProps}
            onOpenChange={this.handleOpenChange}
            selectedKeys={selectedKeys}
            style={{ padding: '16px 0', width: '100%' }}
          >
            {this.getNavMenuItems(this.menus)}
          </Menu>
        </Sider>
      );
    }
  }
  