import React from 'react'
import { Modal, Tree, Form, Input, Icon, Row, Col, Button } from 'antd'
import DeleteBox from '../deleteBox/deleteBox'
import { arrayToTree, hashcode } from '../../../utils/baseUtils'
import './box.less'
const { TreeNode } = Tree;
const Search = Input.Search

class GroupBox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            groupData: props.groupData.map(g => g),
            filterLabel: '',
            selectedGroup: null,
            expandedKeys: ['-1'],
            editingKey: null,
            autoExpandParent: true,
            aGroups: [], // 新增的分组
            mGroups: [], // 修改的分组
            dGroups: [], // 删除的分组
            willDeleteGroup: null,
            visibleDeleteGroupBox: false,
            validInfo: {},
            saving: false,
        }
    }

    onFilter = (tree, regLabel) => {
        let arr = tree ? [ ...tree ] : [];
        for(let i = arr.length - 1; i >= 0; i--) {
            let t = arr[i];
            t.children = t.children || [];
            if(t.children.length > 0) {
                t.children = this.onFilter(t.children, regLabel);
            }

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

    generateTreeNode(treeData) {
        const { filterLabel, editingKey, validInfo } = this.state;
        const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
        const regLabel = filterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
        let arr = this.onFilter(treeData, regLabel);
        let list = arr.map(t => {
            const title = <span>{ (regLabel) ?
                ((t.label || '').split(new RegExp(`(${regLabel})`, 'i')).map((fragment, i) => {
                    return (
                        fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === regLabel.toLowerCase() ?
                        <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
                        fragment
                    )
                }
                )) : t.label
            }</span>
            return <TreeNode
                title={<div className='node-title'>
                    {t.code === editingKey ? <div className='input'>
                        <Form.Item
                            status={(validInfo['inputRef-' + t.code] || { status: 'success' }).status}
                            help={(validInfo['inputRef-' + t.code] || { help: '' }).help}
                        >
                            <Input
                                ref={(input) => {this['inputRef-' + t.code] = input}}
                                size="small"
                                defaultValue={t.label}
                                addonAfter={<Icon style={{ cursor: 'pointer', color: '#52C41A' }} type="check-circle" onClick={() => {
                                    this.setState({ editingKey: false });
                                }}/>}
                                onChange={e => {
                                    let val = e.target.value + '';
                                    let status, help;
                                    if(val.trim().length === 0) {
                                        status = 'error';
                                        help = '*分组名称不能为空';
                                    }else if(val.trim().length > 20) {
                                        status = 'error';
                                        help = '*分组名称不能超过20个字符';
                                    }else {
                                        status = 'success';
                                        help = '';
                                    }
                                    window.clearTimeout(this['inputRef-' + t.code + '-key']);
                                    this['inputRef-' + t.code + '-key'] = window.setTimeout(() => {
                                        let obj = {};
                                        obj['inputRef-' + t.code] = { status, help }
                                        this.setState({
                                            validInfo: { ...validInfo, ...obj }
                                        });
                                    }, 100);
                                }}
                                onBlur={(e) => {
                                    this.setState({ editingKey: false });
                                    if(!e.target.value.trim()) {
                                        return;
                                    }
                                    this.modifyGroup({ ...t, label:e.target.value });
                                }} onPressEnter={(e) => {
                                    this.setState({ editingKey: false });
                                    if(!e.target.value.trim()) {
                                        return;
                                    }
                                    this.modifyGroup({ ...t, label:e.target.value });
                                }}
                            />
                        </Form.Item>
                    </div> :
                    <div className='label' onDoubleClick={() => {
                        this.setState({
                            editingKey: t.code
                        }, () => {
                            this['inputRef-' + t.code].focus();
                        });
                    }}>{title}</div>}
                    { t.code !== editingKey && t.label.trim().length === 0 && <span style={{ position: 'absolute', color: 'red', marginTop: '14px', fontSize: '12px' }}>*分组名称不能为空</span> }
                    { t.code !== editingKey && t.label.length > 20 && <span style={{ position: 'absolute', color: 'red', marginTop: '14px', fontSize: '12px' }}>*分组名称不能超过20个字符</span> }
                    <div className='tools'>
                        {t.code !== editingKey && <Icon type='edit' onClick={() => {
                            this.setState({
                                editingKey: t.code
                            }, () => {
                                this['inputRef-' + t.code].focus();
                            });
                        }}/>}
                        {(!t.children || t.children.length === 0) && <Icon type='delete' onClick={() => {
                            if(t.code.startsWith('new-')) {
                                this.deleteGroup(t);
                            }else {
                                this.setState({
                                    willDeleteGroup: t,
                                    visibleDeleteGroupBox: true
                                });
                            }
                        }}/>}
                    </div>
                </div>}
                key={t.code}
            >
                {(t.children && t.children.length > 0) && this.generateTreeNode(t.children)}
            </TreeNode>
        });

        return list;
    }

    onSelect = (selectedKeys, info) => {
        const { groupData } = this.state;
        let group = groupData.filter(g => g.code === selectedKeys[0])[0];
        this.setState({
            selectedGroup: group
        });
    }

    onExpand = (expandedKeys) => {
        this.setState({
            expandedKeys,
            autoExpandParent: false,
        });
    }

    onSearch = (e) => {
        const value = e.target.value;
        const expandedKeys = this.findExpandedKeys(value);
        this.setState({
            expandedKeys,
            filterLabel: value,
            autoExpandParent: true,
        });
    }
    
    findExpandedKeys = (filterLabel) => {
        const { groupData } = this.state;
        let result = [];

        groupData.forEach(g => {
            if(g.label.toLowerCase().indexOf(filterLabel.toLowerCase()) > -1 && result.indexOf(g.pcode) === -1) {
                result.push(g.pcode);
            }
        });
        return result;
    }

    findGroup = (treeData, group) => {
        let fg;
        if(group && treeData && treeData.length > 0) {
            for(let i = 0; i < treeData.length && !fg; i++) {
                if(treeData[i].code === group.code) {
                    fg = treeData[i];
                }else {
                    fg = this.findGroup(treeData[i].children, group);
                }
            }
        }
        return fg;
    }

    getParens = (group) => {
        const { groupData } = this.state;
        let pgroups = [group];
        let fgroup = groupData.find(g => g.code === group.pcode);
        if(fgroup) {
            pgroups = pgroups.concat(this.getParens(fgroup));
        }
        return pgroups;
    }

    addGroup = (pgroup) => {
        let { aGroups, groupData } = this.state;
        // let treeData = arrayToTree(groupData, '-1', 'code', 'pcode', 'children');
        // let fGroup = this.findGroup(treeData, pgroup);
        let pGroups = pgroup ? this.getParens(pgroup) : [];
        let g = {
            label: '新分组',
            operate: 'add',
            code: 'new-' + Math.random() * 10,
        };
        if(pgroup) {
            g.pcode = pgroup.code
        }else {
            g.pcode = '-1'
        }
        groupData.unshift(g);
        this.setState({
            groupData,
            expandedKeys: pGroups.concat([{ code: '-1' }]).map(g => g.code),
            aGroups: aGroups.concat([g]),
            editingKey: g.code,
        }, () => {
            this['inputRef-' + g.code].focus();
        });
    }

    modifyGroup = (group) => {
        let { aGroups, mGroups, groupData } = this.state;
        let idx = groupData.findIndex(g => g.code === group.code);
        groupData.splice(idx, 1, group);

        if(group.code.startsWith('new-')) {
            for(let i = 0; i < aGroups.length; i++) {
                if(aGroups[i].code === group.code) {
                    aGroups[i] = Object.assign({}, aGroups[i], group);
                    break;
                }
            }
            this.setState({
                groupData,
                aGroups: aGroups
            });
        }else {
            let fidx = mGroups.findIndex(g => g.code === group.code);
            if(fidx === -1) {
                this.setState({
                    groupData,
                    mGroups: mGroups.concat([{ ...group, operate: 'update' }])
                });
            }else {
                mGroups[fidx] = Object.assign({}, mGroups[fidx], group);
                this.setState({
                    groupData,
                    mGroups: mGroups
                });
            }
        }
    }

    deleteGroup = (group) => {
        let { aGroups, mGroups, dGroups, groupData } = this.state;
        let idx = groupData.findIndex(g => g.code === group.code);
        groupData.splice(idx, 1);

        if(group.code.startsWith('new-')) {
            let fidx = aGroups.findIndex(g => g.code === group.code);
            aGroups.splice(fidx, 1);
            this.setState({
                groupData,
                aGroups: aGroups
            });
        }else {
            let fidx = mGroups.findIndex(g => g.code === group.code);
            if(fidx !== -1) {
                mGroups.splice(fidx, 1);
            }
            this.setState({
                groupData,
                mGroups: mGroups,
                dGroups: dGroups.concat([{ ...group, operate: 'delete' }]),
                selectedGroup: null
            });
        }
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        if(hashcode(prevProps.groupData) !== hashcode(this.props.groupData)) {
            this.setState({
                groupData: this.props.groupData.map(g => g),
                aGroups: [],
                mGroups: [],
                dGroups: [],
            });
        }
    }

    checkValid = () => {
        const { validInfo } = this.state;
        let flag = true;
        for(let k in validInfo) {
            if(validInfo[k].status === 'error') {
                flag = false;
                break;
            }
        }
        return flag;
    }

    render() {
        let { visibleBox, hideBox, okHandler, typeText } = this.props;
        let { groupData, expandedKeys, selectedGroup, autoExpandParent, aGroups, mGroups, dGroups, visibleDeleteGroupBox, willDeleteGroup, saving } = this.state;
        let treeData = arrayToTree(groupData, '-1', 'code', 'pcode', 'children');
        return <Modal
            className='groupmanagement-box'
            title={'分组维护'}
            visible={visibleBox}
            footer={
                <div>
                    <Button onClick={hideBox}>取 消</Button>
                    <Button disabled={!this.checkValid() || saving} type='primary' onClick={() => {
                        if(aGroups.length === 0 && mGroups.length === 0 && dGroups.length === 0) {
                            hideBox()
                        }else {
                            this.setState({
                                saving: true
                            });
                            okHandler(aGroups, mGroups, dGroups).then(() => {
                                this.setState({
                                    saving: false,
                                    aGroups: [],
                                    mGroups: [],
                                    dGroups: [],
                                });
                            });
                        }
                    }}>确 定</Button>
                </div>
            }
            onCancel={hideBox}
            maskClosable={false}
            destroyOnClose={true}
        >
            <Row>
                <Col span={20}>
                    <Search placeholder='搜索' onChange={this.onSearch}></Search>
                </Col>
                <Col span={4}>
                    <Button disabled={selectedGroup && selectedGroup.code && (selectedGroup.code.startsWith('new-') || (groupData.findIndex(g => g.code === selectedGroup.code) === -1))} style={{ marginLeft: '11px' }} onClick={() => {
                        this.addGroup(selectedGroup);
                    }}>添加</Button>
                </Col>
            </Row>
            <Row className='tree-container'>
                <Tree
                    onSelect={this.onSelect}
                    onExpand={this.onExpand}
                    expandedKeys={expandedKeys}
                    autoExpandParent={autoExpandParent}
                >
                    {
                        <TreeNode title='全部' key='-1'>{this.generateTreeNode(treeData)}</TreeNode>
                    }
                </Tree>
            </Row>
            {visibleDeleteGroupBox && <DeleteBox
                visibleBox={visibleDeleteGroupBox}
                text={<div><span>确定要删除分组【{willDeleteGroup.label}】吗？</span><br/><span style={{ color: 'red' }}>{`*删除会将该组所有${typeText}移动到未分组`}</span></div>}
                hideBox={() => {
                    this.setState({
                        visibleDeleteGroupBox: false
                    })
                }}
                okHandler={() => {
                    this.deleteGroup(willDeleteGroup);
            }} />}
        </Modal>
    }
}

export default GroupBox