import React from 'react'
import { connect } from 'dva'
import { Tree, Input, Button, Icon } from 'antd'
import DeleteBox from '../common/deleteBox/deleteBox'
import CusIcon from '../common/cusIcon/index'
import './menu.less'
const { TreeNode } = Tree
const { Search } = Input

class DashboardMenu extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            editingKey: null,
            selectedMenu: null,
            visibleDeleteBox: false,
        };
    }

    static defaultProps = { 
        onlyMenu: true, // 仅展示目录
        hideEmptyMenu: false, // 隐藏空目录
        editable: true,
        searchMenu: true,
        hideHeader: false,
    }

    componentDidMount() {
        const { dispatch, onMount } = this.props;
        dispatch({ type: 'dashboard/remoteMenuTree' }).then((res) => {
            if(res) {
                typeof onMount === 'function' && onMount(res.menuList, res.menuTree);
            }
        });
    }

    cloneTree = (tree) => {
        let arr = [];
        tree.forEach(t => {
            let obj = { ...t, children: []};
            if(t.children && t.children.length > 0) {
                obj.children = this.cloneTree(t.children);
            }
            arr.push(obj);
        });
        return arr;
    }

    reduceTree = (tree, regLabel) => {
        const { onlyMenu, searchMenu, hideEmptyMenu } = this.props;
        let arr = tree ? [ ...tree ] : [];
        for(let i = arr.length - 1; i >= 0; i--) {
            let t = arr[i];
            if(t.children && t.children.length > 0) {
                t.children = this.reduceTree(t.children, regLabel);
            }

            // 纯目录过滤
            if(onlyMenu) {
                if(t.type === 'dashboard') {
                    arr.splice(i, 1);
                    continue;
                }
            }
            // 空目录过滤
            if(hideEmptyMenu) {
                // 当搜索包括目录时还是保留目录
                // if(searchMenu && t.type === 'menu' && t.name.search(new RegExp('(' + regLabel + '){1}', 'ig')) >= -1) {

                // }else if((!t.children || t.children.length === 0) && t.type === 'menu') {
                //     arr.splice(i, 1);
                //     continue;
                // }

                if(t.type === 'menu' && (!t.children || t.children.length === 0) && !(searchMenu && t.name.search(new RegExp('(' + regLabel + '){1}', 'ig')) >= -1)) {
                    arr.splice(i, 1);
                    continue;
                }
            }
            // 关键字过滤
            if(!!regLabel && t.name.search(new RegExp('(' + regLabel + '){1}', 'ig')) === -1 && (t.type === 'dashboard' || (t.children.length === 0))) {
                arr.splice(i, 1);
                continue;
            }
        }
        return arr;
    }

    generateMenu(tree, regLabel) {
        const { dispatch, onlyMenu, searchMenu, editable, extraTools, onMenuModify } = this.props;
        const { editingKey } = this.state;
        let ftree = this.cloneTree(tree);
        ftree = this.reduceTree(ftree, regLabel)
        return ftree.filter(t => (onlyMenu ? t.type === 'menu' : true)).sort((a, b) => a.index - b.index).map(t => {
            let title = <div className={`node-title node-${t.type}`}>
                <span>{ (t.code !== editingKey) ?
                   ( !!regLabel && (searchMenu || t.type === 'dashboard') ? (<div className='label'> <span title={t.name} style={{ fontWeight: t.type === 'dashboard' ? 'bold' : 'normal' }}>
                        { t.type === 'dashboard' && <CusIcon style={{ marginRight: '8px' }} type="bi-nav-dashboard" /> }
                        { (t.name || '').split(new RegExp(`(${regLabel})`, 'i')).map((fragment, i) => {
                            return (
                                fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'), '\\$1') === regLabel.toLowerCase() ?
                                <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
                                fragment
                            )
                        }) }                       
                   </span> </div>  ) : <div className='label' onDoubleClick={() => {
                        const { dashboard, model, onExpand: propsOnExpand } = this.props;
                        const { menuExpandedKeys } = model;
                        const { menuList } = dashboard;
                        let expandedMenus = [];
                        let menu = [{ code: '-1', name: '报表目录' }].concat(menuList).find(l => l.code === t.code);
                        let menus = this.getParens(menu);
                        // 去掉非目录节点（只有第一个会出现非目录节点）
                        if(menus[0].type !== 'menu') {
                            menus.shift();
                        }
                        // 已展开时关闭该目录
                        if(!!menuExpandedKeys.find(s => s === t.code)) {
                            menus.shift();
                        }
                        expandedMenus = expandedMenus.concat(menus);
                        if(typeof propsOnExpand === 'function') {
                            propsOnExpand(expandedMenus);
                        }
                    }}>
                        <span title={t.name} style={{ fontWeight: t.type === 'dashboard' ? 'bold' : 'normal' }}>
                            { t.type === 'dashboard' && <CusIcon style={{ marginRight: '8px' }} type="bi-nav-dashboard" /> }
                            { t.name }
                        </span>
                    </div> ) : ( <div className='input'>
                    <Input
                        ref={(input) => { this['inputRef-' + t.code] = input }}
                        size="small"
                        defaultValue={t.name}
                        addonAfter={<Icon style={{ cursor: 'pointer', color: '#52C41A' }} type="check-circle" onClick={() => {
                            this.setState({ editingKey: false });
                        }}/>}
                        onBlur={(e) => {
                            let val = e.target.value;
                            if(!!(val+'').trim() && val !== t.name) {
                                dispatch({ type: 'dashboard/remoteModifyMenu', menu: { ...t, name: val } }).then((menu) => {
                                    if(typeof onMenuModify === 'function') {
                                        onMenuModify(menu);
                                    }
                                });
                            }
                            this.setState({ editingKey: false });
                        }}
                        onPressEnter={(e) => {
                            let val = e.target.value;
                            if(!!(val+'').trim() && val !== t.name) {
                                dispatch({ type: 'dashboard/remoteModifyMenu', menu: { ...t, name: val } }).then((menu) => {
                                    if(typeof onMenuModify === 'function') {
                                        onMenuModify(menu);
                                    }
                                });
                            }
                            this.setState({ editingKey: false });
                        }}
                    />
                </div> )
                }</span>
                {editable && <div className='tools'>
                    {t.code !== editingKey && t.type === 'menu' && <Icon type='plus' onClick={() => {
                        this.onAddClick(t)
                    }}/>}
                    {t.code !== editingKey && <Icon type='edit' onClick={() => {
                        this.setState({
                            editingKey: t.code
                        }, () => {
                            this['inputRef-' + t.code].focus();
                        });
                    }}/>}
                    {t.code !== editingKey && !(t.children && t.children.length > 0) && <Icon type='delete' onClick={() => {
                        this.setState({
                            selectedMenu: t,
                            visibleDeleteBox: true,
                        });
                    }}/>}
                </div>}
                {extraTools && extraTools.render && extraTools.render(t)}
            </div>

            return <TreeNode title={title} key={t.code} >
                { t.children && t.children.length > 0 && this.generateMenu(t.children, regLabel) }
            </TreeNode>
        });
    }

    onExpand = (keys) => {
        const { dashboard, onExpand: propsOnExpand } = this.props;
        const { menuList } = dashboard;
        let expandedMenus = [];
        for(let i = 0; i < keys.length; i++) {
            let menu = [{ code: '-1', name: '报表目录' }].concat(menuList).find(l => l.code === keys[i]);
            expandedMenus.push(menu);
        }
        if(typeof propsOnExpand === 'function') {
            propsOnExpand(expandedMenus);
        }
    }

    onSelect = (selectedKeys, info) => {
        const { dashboard, onSelect: propsOnSelect, onUnSelect: propsOnUnSelect } = this.props;
        const { menuList, currentMenu } = dashboard;
        if(selectedKeys.length > 0) {
            let selectedMenu = [{ code: '-1', name: '报表目录' }].concat(menuList).find(l => l.code === selectedKeys[0]);
            let parents = this.getParens(selectedMenu);
    
            if(typeof propsOnSelect === 'function') {
                propsOnSelect(selectedMenu, parents);
            }
        }else {
            typeof propsOnUnSelect === 'function' && propsOnUnSelect(currentMenu);
        }
    }

    onSearch = (value) => {
        const { dashboard, onSearch: propsOnSearch } = this.props;
        // 获得需要展开的目录（存在包含关键字的报表或目录）
        const expandedMenus = this.findExpandedKeys(dashboard.menuTree, {code: '-1'}, value);

        if(typeof propsOnSearch === 'function') {
            propsOnSearch(value, expandedMenus);
        }
    }

    findExpandedKeys = (tree, parent, filterLabel) => {
        let result = [];
        if(tree && tree.length > 0) {
            tree.forEach(t => {
                if(t.name.toLowerCase().indexOf(filterLabel.toLowerCase()) > -1 && result.indexOf(parent.code) === -1) {
                    result.push(parent);
                }
                result = result.concat(this.findExpandedKeys(t.children, t, filterLabel));
            });
        }
        return result;
    }

    onAddClick = (pmenu) => {
        const { dashboard, dispatch } = this.props;
        const { menuExpandedKeys } = dashboard;
        const menu = {
            index: pmenu.childrenCount,
            name: '新目录',
            pcode: pmenu.code
        }
        dispatch({ type: 'dashboard/remoteAddMenu', menu }).then(menuCode => {
            if(menuCode) {
                dispatch({ type: 'dashboard/remoteMenuTree', mandatory: true }).then(menuData => {
                    this.onExpand(menuExpandedKeys.concat([menuCode]));
                    this.onSelect([menuCode]);
                    this.setState({
                        editingKey: menuCode
                    }, () => {
                        this['inputRef-' + menuCode].focus();
                    })
                })
            }
        });
    }

    getParens = (menu) => {
        const { menuList } = this.props.dashboard;
        let pmenus = [menu];
        let fmenu = [{ code: '-1', name: '报表目录' }].concat(menuList).find(l => l.code === menu.pcode);
        if(fmenu) {
            pmenus = pmenus.concat(this.getParens(fmenu));
        }
        return pmenus;
    }

    render() {
        const { dashboard, dispatch, hideHeader, editable, model, onSearch: propsOnSearch, onMenuDelete, silentFetch } = this.props;
        const { visibleDeleteBox, selectedMenu } = this.state;
        const { menuTree } = dashboard;
        const { menuFilterLabel, menuExpandedKeys, menuSelectedKeys, menuAutoExpandParent } = model;
        const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
        const regLabel = menuFilterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号

        return <div className='menu-container' style={ hideHeader ? { paddingTop: 0 } : { paddingTop: '48px' } }>
            {!hideHeader && <div className='menu-search'>
                <Search
                    value={menuFilterLabel}
                    placeholder='搜索'
                    //onSearch={this.onSearch}
                    onChange={(e) => {
                        // 获得需要展开的目录（存在包含关键字的报表或目录）
                        const expandedMenus = this.findExpandedKeys(dashboard.menuTree, {code: '-1'}, e.target.value);
                        if(typeof propsOnSearch === 'function') {
                            propsOnSearch(e.target.value, expandedMenus);
                        }
                        dispatch({ type: 'dashboard/setFields', fields: [
                            { name: 'menuFilterLabel', value: e.target.value },
                            { name: 'menuAutoExpandParent', value: true },
                        ] });
                    }}
                />
                <Button onClick={() => {
                    dispatch({ type: 'dashboard/remoteMenuTree', mandatory: true, silent: silentFetch });
                    dispatch({ type: 'dashboard/setFields', fields: [
                        { name: 'menuFilterLabel', value: '' },
                        { name: 'menuAutoExpandParent', value: false },
                    ] });
                }}><Icon type='sync' /></Button>
            </div>}
            <div className='menu-content'>
                <Tree
                    inlineIndent={8}
                    expandedKeys={menuExpandedKeys}
                    onExpand={this.onExpand}
                    selectedKeys={menuSelectedKeys}
                    onSelect={this.onSelect}
                    autoExpandParent={menuAutoExpandParent}
                >
                    <TreeNode title={
                        <div className='node-title node-menu'>
                            <span><div className='label' style={{ fontSize: '16px' }} onDoubleClick={() => {
                                const { model, onExpand: propsOnExpand } = this.props;
                                const { menuExpandedKeys } = model;
                                let expandedMenus = [];
                                let menus = [{ code: '-1', name: '报表目录' }]
                                // 已展开时关闭该目录
                                if(!!menuExpandedKeys.find(s => s === '-1')) {
                                    menus.shift();
                                }
                                expandedMenus = expandedMenus.concat(menus);
                                if(typeof propsOnExpand === 'function') {
                                    propsOnExpand(expandedMenus);
                                }
                            }}><CusIcon style={{ marginRight: '8px' }} type="bi-compass" /><span>报表目录</span></div></span>
                            {editable && <div className='tools'>
                                <Icon type='plus' onClick={() => {
                                    this.onAddClick({ code: '-1', name: '报表目录', pcode: '-1', childrenCount: menuTree.length })
                                }}/>
                            </div>}
                        </div>
                    } key='-1'>
                        { this.generateMenu(menuTree, regLabel) }
                    </TreeNode>
                </Tree>
                {visibleDeleteBox && <DeleteBox
                    visibleBox={visibleDeleteBox}
                    text={`确定要删除目录【${selectedMenu.name}】吗？`}
                    hideBox={() => {
                        this.setState({
                            visibleDeleteBox: false
                        })
                    }}
                    okHandler={() => {
                        dispatch({ type: 'dashboard/remoteDeleteMenu', menu: selectedMenu }).then(() => {
                            if(typeof onMenuDelete === 'function') {
                                onMenuDelete(selectedMenu);
                            }
                        });
                    }} 
                />}
            </div>
        </div>
    }
}

function mapStateToProps({ dashboard }) {
    return { dashboard }
}
export default connect(mapStateToProps)(DashboardMenu)