/**
 * 图表列表
 */
import React from 'react'
import { Layout, Button, Icon, Menu, Dropdown, Card, Col, Row, Breadcrumb, Tag, Checkbox, Pagination } from 'antd'
import { connect } from 'dva'
import ChooseDataSourceBox from './chooseDataSourceBox'
import GroupManagementBox from '../common/groupManageMentBox/box'
import EmptyContent from '../common/emptyContent/index'
import moment from 'moment'
import Ellipsis from 'ant-design-pro/lib/Ellipsis'
import 'ant-design-pro/dist/ant-design-pro.css'
import GroupSelector from '../common/groupSelector/popover'
import Thumbnail from './thumbnail'
import DistributeBox from './distributeBox'
import TransferBox from '../common/selectUserBox/selectUserBox'
import DeleteBox from '../common/deleteBox/deleteBox'
import { arrayToTree } from '../../utils/baseUtils'
import ListFilter from '../common/listFilter/index'
import Loading from '../common/loading/index'
import './list.less'
const { Content } = Layout
const CardGrid = Card.Grid

class ChartList extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            selectedRecord: null,

            visibleChooseDataSourceBox: false,
            visibleDistributeBox: false,
            visibleTransferBox: false,
            visibleGroupMenu: false, // 显示分组菜单
            visibleDeleteBox: false,
            visibleGroupManageMentBox: false, // 显示分组管理组件
            visibleDataPreviewBox: false,

            noGroup: false, // 显示未分组数据

            page: 1, // 分页器当前页码
            pageSize: 25,// 每页最大展示卡片数(maxRowCards * maxRow)
            maxRowCards: 5, // 每行最大展示卡片数(无需自定义，有自动计算逻辑)
            maxRow: 5, // 每页最大行数(手动设置，也许后期可以通过判断电脑性能自动设置该值？)
        }
        this.bodyRef = React.createRef();
    }

    componentDidMount() {
        const { dispatch, chart } = this.props;
        this.setBodyWidth();
        dispatch({ type: 'chart/fetchList' })
        dispatch({ type: 'chart/remoteGroupList' });
        this.setState({
            page: chart.page || 1
        });
        this.bodyRef.current.parentNode.scrollTo(0, chart.listScrollTop)
        window.addEventListener('resize', this.setBodyWidth);
    }

    componentWillUnmount() {
        const { dispatch } = this.props;
        window.removeEventListener('resize', this.setBodyWidth);
        dispatch({ type: 'chart/setFields', fields: [
            { name: 'listScrollTop', value: this.bodyRef.current.parentNode.scrollTop },
            { name: 'page', value: this.state.page },
        ] });
    }

    /**
     * 设置卡片容器宽度 = 每行最大卡片数量 * 卡片宽度
     */
    setBodyWidth = () => {
        const { maxRowCards, maxRow } = this.state;
        const cardBody = this.bodyRef.current; // 卡片容器
        const parent = cardBody.parentNode; // 父级容器
        const pWidth = parent.offsetWidth; // 父级容器宽度
        const pPadding = 10 + 10; // 父级容器左右padding
        const cWidth = 207; // 每个卡片宽度
        const cMargin = 8 + 8; // 每个卡片左右margin
        const pTrueWidth = pWidth - pPadding; // 父容器实际可用宽度
        const cTrueWidth = cWidth + cMargin; // 卡片实际占用宽度
        const count = Math.ceil(pTrueWidth/cTrueWidth) - 1; // 每行最大卡片数量，考虑到滚动条，减少一个
        const cardBodyWidth = count * cTrueWidth; // 考虑到滚动条，减少一个

        cardBodyWidth > 0 ? cardBody.style.width = cardBodyWidth + 'px' : void(0);

        if(maxRowCards !== count) {
            this.setState({
                maxRowCards: count,
                pageSize: count * maxRow
            });
        }
    }

    onGroup = () => {
        const { chart } = this.props;
        const { noGroup } = this.state;
        const { list, currentGroup } = chart;
        
        if(noGroup) {
            return list.filter(l => l.groupCode === '-1' );
        }else if(currentGroup) {
            return list.filter(l => l.groupCode === currentGroup.code );
        }else {
            return list;
        }
    }

    onFilterAndGroup = (cardList) => {
        const { chart } = this.props;
        const { noGroup } = this.state;
        const { filterItem, currentGroup } = chart;
        const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
        let filterLabel = chart.filterLabel ? (chart.filterLabel + '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') : ''; // 添加转义符号
        let filterReg = new RegExp('(' + filterLabel + '){1}', 'ig');

        let list = cardList.filter(l => {
            if(filterItem.type === 'date') {
                if(filterLabel===""){
                    if(noGroup) {
                        return l.groupCode === '-1'
                    }else {
                        return !!currentGroup ? l.groupCode === currentGroup.code : true;
                    }
                }else if(filterLabel.indexOf('#')>-1){
                    let start = filterLabel.split('#')[0]
                    let end = filterLabel.split('#')[1]
                    let nowTime = new Date(l[filterItem.name]).getTime();
                    if(nowTime>=start && nowTime<=end){
                        if(noGroup) {
                            return l.groupCode === '-1'
                        }else {
                            return !!currentGroup ? l.groupCode === currentGroup.code : true;
                        }
                    }
                    return false;
                }else{
                    return false;
                }
            }else {
                if((l[filterItem.name] + '').search(filterReg) > -1) {
                    if(noGroup) {
                        return l.groupCode === '-1'
                    }else {
                        return !!currentGroup ? l.groupCode === currentGroup.code : true;
                    }
                }else {
                    return false;
                }
            }
        })

        return list;
    }

    onSort = (list) => {
        return list.sort((a, b) => {
            return new Date(b.createTime) - new Date(a.createTime)
        })
    }

    onPage = (list) => {
        const { page, pageSize } = this.state;
        return list.slice(pageSize * (page - 1), pageSize * (page - 1) + pageSize)
    }

    onReduce = () => {
        const { list } = this.props.chart;
        return this.onSort(this.onFilterAndGroup(list));
    }

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

    generateGroupTags = () => {
        const { chart, dispatch } = this.props;
        const { noGroup } = this.state;
        const { currentGroup } = chart;
        const pGroups = currentGroup ? [{ code: '-1', label: '全部分组' }].concat(this.getParens(currentGroup)) : [{ code: '-1', label: '全部分组' }];
        return <Breadcrumb className={`group${noGroup ? ' nogroup' : ''}`} separator=">">
            { pGroups.map(g => (
                <Breadcrumb.Item key={g.code}>
                    <Tag color={'blue'} >
                        <span onClick={() => {
                            let group = chart.groupList.find(group => group.code === g.code);
                            dispatch({ type: 'chart/setCurrentGroup', group: group });
                        }}>{g.label}</span>
                        <GroupSelector
                            visible={this.state['visibleGroupSelector' + g.code]}
                            handleVisibleChange={(visible) => {
                                let obj = {};
                                obj['visibleGroupSelector' + g.code] = visible
                                this.setState(obj);
                            }}
                            pGroup={g}
                            groupList={chart.groupList}
                            selectGroup={(group) => {
                                let obj = {};
                                obj['visibleGroupSelector' + g.code] = false;
                                this.setState(obj);
                                dispatch({ type: 'chart/setCurrentGroup', group });
                            }}
                        >
                            <Icon style={{ marginLeft: '2px', fontSize: '12px' }} type="down" />
                        </GroupSelector>
                    </Tag>
                </Breadcrumb.Item>
            )) }
        </Breadcrumb>
    }

    generateOperationMenu = () => {
        const { main, chart, dispatch } = this.props;
        const { currentUser } = main;
        const { selectedRecord } = this.state;
        const treeData = arrayToTree(chart.groupList, '-1', 'code', 'pcode', 'children');
        
        return (
            <Menu className='menu-operation'>
                <Menu.Item disabled>
                    <Icon type="link" />分享
                </Menu.Item>
                {/* {selectedRecord && (currentUser.code === selectedRecord.creatorCode || currentUser.role === 'superAdmin') && <Menu.Item onClick={() => {
                    const { selectedRecord } = this.state;
                    // const selectedChartDataSourceCode = selectedRecord ? selectedRecord.code : '';
                    const selectedChartCode = selectedRecord ? selectedRecord.code : '';
                    dispatch({ type: 'chartPolicy/fetchList', chartCode: selectedChartCode });
                    dispatch({ type: 'chartPolicy/remoteColumnData', chartCode: selectedChartCode });
                    // dispatch({ type: 'chartDesigner/remoteDataColumn', code:  });
                    this.setState({visibleDistributeBox: true})
                }}> 
                    <Icon type='share-alt'/>分发
                </Menu.Item>} */}
                { selectedRecord && (currentUser.code === selectedRecord.creatorCode || currentUser.role === 'superAdmin') && <Menu.SubMenu className='setgroupmenu' title={<div><Icon style={{ marginRight: '6px' }} type='profile' />移动到</div>}>
                    {[<Menu.Item key='-1' onClick={() => {
                        dispatch({ type: 'chart/remoteSetGroup', chart: selectedRecord, group: { code: '-1'} });
                        this.setState({
                            noGroup: true
                        });
                    }}>未分组</Menu.Item>].concat(this.createGroupMenu(treeData))}
                </Menu.SubMenu>}
                <Menu.Divider />
                { selectedRecord && (currentUser.code === selectedRecord.creatorCode || currentUser.role === 'superAdmin') && <Menu.Item
                    onClick={()=>{
                        this.setState({ visibleTransferBox: true})
                    }}
                >
                    <Icon type="swap" />移交
                </Menu.Item>}
                { selectedRecord && (currentUser.code === selectedRecord.creatorCode || currentUser.role === 'superAdmin') && <Menu.Item
                    onClick={(e) => {
                        this.setState({ visibleDeleteBox: true})
                    }}
                >
                    <Icon type="delete" />删除
                    
                </Menu.Item>}
            </Menu>
        )
    }

    generateCard(list) {
        const { chart, dispatch } = this.props;
        let { filterItem } = chart

        const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
        let filterLabel = chart.filterLabel ? (chart.filterLabel + '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') : ''; // 添加转义符号
        
        
        let cards = list.map( (l, i) => (
            <CardGrid className={`chart-card`} key={i} onClick={() => {
                this.setState({ selectedRecord: l })
            }}>
                <Card
                    title={
                        <Row type='flex' justify='space-between'>
                            <Col className='label' style={{ overflow: 'hidden', textOverflow: 'ellipsis', padding: '0 16px' }} >
                                { (filterItem.name === 'name' && filterLabel) ?
                                    ((l.name || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
                                        return (
                                            fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
                                            <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
                                            fragment
                                        )
                                    }
                                    )) : l.name
                                }
                            </Col>
                        </Row>
                    }
                    cover={
                        <Col className='cover-body'>
                            <Row className='thumb' onClick={l.access && l.database ? () => {
                                dispatch({ type: 'chartDesigner/reset' });
                                dispatch({ type: 'main/redirect', path: '/chart/' + l.code });
                                dispatch({ type: 'recent/addRecentRecord', tarId: l.code, recordType: 0});
                            } : () => {}}>
                                {!l.database ? <div className='deny-body'>
                                    <div className='deny-tip'>数据源丢失</div>
                                </div> : (!l.access ? <div className='deny-body'>
                                    <div className='deny-tip'>无数据权限</div>
                                </div> : null)}
                                <Thumbnail style={{ opacity: (l.access && l.database) ? 1 : 0.3 }} type={l.type} code={l.code} option={l.chartOption}/>
                            </Row>
                            <Row className='desc'>
                                <Ellipsis tooltip={l.description&&l.description.length > 16} lines={2}>{
                                    <span>
                                    { (filterItem.name === 'description' && filterLabel) ?
                                        ((l.description || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
                                            return (
                                                fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
                                                <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
                                                fragment
                                            )
                                        }
                                        )) : l.description
                                    }
                                    </span>
                                }</Ellipsis>
                            </Row>
                            <Row className='footer' type='flex' justify='end' align='bottom'>
                                <Col style={{ textAlign: 'left', lineHeight: '28px' }} span={21}>
                                    <Row>{
                                        (filterItem.name === 'creatorName' && filterLabel) ?
                                        ((l.creatorName || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
                                            return (
                                                fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
                                                <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
                                                fragment
                                            )
                                        }
                                        )) : l.creatorName
                                    } {moment(l.createTime).format('YYYY-MM-DD')}</Row>
                                </Col>
                                <Col span={3} style={{ textAlign: 'right' }}>
                                    <Dropdown getPopupContainer={() => document.querySelector('.layout-chart .ant-card-body')} overlay={this.generateOperationMenu()} trigger={['click']}>
                                        <Icon style={{ fontSize: '24px' }} type="ellipsis" theme="outlined" />
                                    </Dropdown>
                                </Col>
                            </Row>
                        </Col>
                    }
                >
                </Card>
            </CardGrid>
        ));
        if(cards.length === 0) {
            return <EmptyContent />
        }
        return cards;
    }

    createGroupMenu = (treeData) => {
        const { dispatch } = this.props;
        const { selectedRecord } = this.state;
        return treeData.map(t => {
            if(t.children && t.children.length > 0) {
                return <Menu.SubMenu
                    key={t.code}
                    title={selectedRecord.groupCode === t.code ? <span className='current' style={{ fontWeight: 'bold' }}>{t.label}</span> : t.label}
                    onTitleClick={() => {
                        dispatch({ type: 'chart/remoteSetGroup', chart: selectedRecord, group: t });
                        dispatch({ type: 'chart/setCurrentGroup', group: t });
                        this.setState({noGroup: false})
                    }}
                >
                    {this.createGroupMenu(t.children)}
                </Menu.SubMenu>
            }else {
                return <Menu.Item key={t.code} onClick={() => {
                    dispatch({ type: 'chart/remoteSetGroup', chart: selectedRecord, group: t });
                    dispatch({ type: 'chart/setCurrentGroup', group: t });
                    this.setState({noGroup: false})
                }}>{selectedRecord.groupCode === t.code ? <span className='current' style={{ fontWeight: 'bold' }}>{t.label}</span> : t.label}</Menu.Item>
            }
        })
    }

    handleVisibleChange = (flag) => {
        this.setState({ visibleGroupMenu: flag });
    }

    hideGroupMenu = () => {
        this.setState({
            visibleGrouMenu: false
        });
    }

    onDrop = (info) => {
        const { dispatch } = this.props;

        const dropCode = info.node.props.eventKey;
        const dragCode = info.dragNode.props.eventKey;
        const dropPos = info.node.props.pos.split('-');
        const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); // -1/0/1 -> 兄/子/弟
        dispatch({ type: 'chart/remoteMoveGroup', dragCode, dropCode, dropPosition });
    }

    onPageChange = (pageNumber) => {
        this.setState({
            page: pageNumber
        }, () => {
            this.bodyRef.current.parentNode.scrollTo(0, 0)
        })
    }

    render() {
        const { dispatch, chart } = this.props;
        const { listLoading } = chart;
        const { visibleChooseDataSourceBox, visibleDistributeBox, visibleGroupManageMentBox, visibleTransferBox, visibleDeleteBox, selectedRecord, noGroup, pageSize, page } = this.state;
        let reduceList =  this.onReduce();
        let viewList = this.onPage(reduceList);
        return (
            <Layout className='layout-chart'>
                <Loading visible={listLoading} />
                <Content>
                    <Card bordered={false} title={
                        <Row className='tools' type='flex' justify='space-between'>
                            <Col style={{ display: 'flex', width: 'calc(100% - 324px)', overflow: 'hidden' }}>
                                <Checkbox style={{ marginTop: '4px' }} checked={noGroup} onChange={(e) => {
                                    this.setState({noGroup: e.target.checked})
                                }}>未分组</Checkbox>
                                <Icon type="bars" onClick={() => {
                                    this.setState({
                                        visibleGroupManageMentBox: true
                                    });
                                }}/>
                                { this.generateGroupTags() }
                            </Col>
                            <Col className='search'>
                                <Col>
                                    <Button className='btn-refresh' onClick={() => {
                                        dispatch({ type: 'chart/setFilterLabel', label: '' });
                                        dispatch({ type: 'chart/fetchList', mandatory: true });
                                    }}>
                                        {/* <CusIcon type='bi-refresh'/> */}
                                        <Icon type='sync'/>
                                    </Button>
                                </Col>
                                <Col>
                                    <ListFilter modelName='chart' model={chart} />
                                </Col>
                                <Col >
                                    <Button onClick={() => {
                                        dispatch({ type: 'dataSource/fetchList' });
                                        this.setState({
                                            visibleChooseDataSourceBox: true
                                        });
                                    }}>
                                        <Icon type="area-chart" />创建图表
                                    </Button>
                                    {visibleChooseDataSourceBox && <ChooseDataSourceBox visibleChooseDataSourceBox={visibleChooseDataSourceBox} hideBox={() => {
                                        this.setState({
                                            visibleChooseDataSourceBox: false
                                        });
                                    }}/>}
                                </Col>
                            </Col>
                        </Row>
                    }>
                        <div ref={this.bodyRef} className='chart-body'>
                            { this.generateCard(viewList) }
                        </div>
                    </Card>
                    <Pagination showQuickJumper pageSize={pageSize} current={page} total={reduceList.length} onChange={this.onPageChange}
                        showTotal={total => `共${total}个图表`}
                    />
                </Content>
                {visibleGroupManageMentBox && <GroupManagementBox
                    typeText='图表'
                    visibleBox={visibleGroupManageMentBox}
                    groupData={chart.groupList}
                    hideBox={() => {
                        this.setState({
                            visibleGroupManageMentBox: false
                        })
                    }}
                    okHandler={(aGroups, mGroups, dGroups) => {
                        return dispatch({ type: 'chart/remoteSetGroups', aGroups, mGroups, dGroups }).then(() => {
                            dispatch({ type: 'chart/fetchList', mandatory: true });
                            dispatch({ type: 'chart/setCurrentGroup', group: null });
                        });
                    }}
                />}
                {visibleDistributeBox && <DistributeBox visibleDistributeBox={visibleDistributeBox} selectedRecord={this.state.selectedRecord} hideBox={() => {
                    this.setState({
                        visibleDistributeBox: false
                    });
                }} />}
                {visibleTransferBox && <TransferBox
                    visibleBox={visibleTransferBox}
                    title='选择移交对象'
                    okHandler={(user) => {
                        dispatch({ type: 'chart/transfer', chartCode: this.state.selectedRecord.code, userCode: user.code });
                    }}
                    hideBox={() => {
                        this.setState({
                            visibleTransferBox: false
                        })
                    }}
                />}
                {visibleDeleteBox && <DeleteBox
                    visibleBox={visibleDeleteBox}
                    text={<div><span>确定要删除图表【{selectedRecord.name}】吗？</span></div>}
                    hideBox={() => {
                        this.setState({
                            visibleDeleteBox: false
                        })
                    }}
                    okHandler={() => {
                        dispatch({ type: 'chart/remoteDelete', code: this.state.selectedRecord.code }).then(() => {
                            dispatch({ type: 'chart/fetchList', mandatory: true });
                        })
                }} />}
            </Layout>
        )
    }
}

export default connect(({ present: { main, chart } }) => ({ main, chart }))(ChartList)