import XEUtils from 'xe-utils';
import { VxeUI } from '../../../ui';
import { isEnableConf } from '../../../ui/src/utils';
import { getCellValue, setCellValue, getRowid } from '../../src/util';
import { removeClass, addClass } from '../../../ui/src/dom';
import { createComponentLog } from '../../../ui/src/log';
const { warnLog, errLog } = createComponentLog('table');
const { getConfig, renderer, getI18n } = VxeUI;
function getEditColumnModel(row, column) {
    const { model, editRender } = column;
    if (editRender) {
        model.value = getCellValue(row, column);
        model.update = false;
    }
}
function setEditColumnModel(row, column) {
    const { model, editRender } = column;
    if (editRender && model.update) {
        setCellValue(row, column, model.value);
        model.update = false;
        model.value = null;
    }
}
function removeCellSelectedClass($xeTable) {
    const el = $xeTable.$refs.refElem;
    if (el) {
        const cell = el.querySelector('.col--selected');
        if (cell) {
            removeClass(cell, 'col--selected');
        }
    }
}
function syncActivedCell($xeTable) {
    const reactData = $xeTable;
    const { editStore, tableColumn } = reactData;
    const editOpts = $xeTable.computeEditOpts;
    const { actived } = editStore;
    const { row, column } = actived;
    if (row && column) {
        if (editOpts.mode === 'row') {
            tableColumn.forEach((column) => setEditColumnModel(row, column));
        }
        else {
            setEditColumnModel(row, column);
        }
    }
}
function insertTreeRow($xeTable, newRecords, isAppend) {
    const internalData = $xeTable;
    const { tableFullTreeData, afterFullData, fullDataRowIdData, fullAllDataRowIdData } = internalData;
    const treeOpts = $xeTable.computeTreeOpts;
    const { rowField, parentField, mapChildrenField } = treeOpts;
    const childrenField = treeOpts.children || treeOpts.childrenField;
    const funcName = isAppend ? 'push' : 'unshift';
    newRecords.forEach((item) => {
        const parentRowId = item[parentField];
        const rowid = getRowid($xeTable, item);
        const matchObj = parentRowId ? XEUtils.findTree(tableFullTreeData, (item) => parentRowId === item[rowField], { children: mapChildrenField }) : null;
        if (matchObj) {
            const { item: parentRow } = matchObj;
            const parentRest = fullAllDataRowIdData[getRowid($xeTable, parentRow)];
            const parentLevel = parentRest ? parentRest.level : 0;
            let pChilds = parentRow[childrenField];
            let pMapChilds = parentRow[mapChildrenField];
            if (!XEUtils.isArray(pChilds)) {
                pChilds = parentRow[childrenField] = [];
            }
            if (!XEUtils.isArray(pMapChilds)) {
                pMapChilds = parentRow[mapChildrenField] = [];
            }
            pChilds[funcName](item);
            pMapChilds[funcName](item);
            const rest = { row: item, rowid, _seq: -1, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: pChilds, parent: parentRow, level: parentLevel + 1, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 };
            fullDataRowIdData[rowid] = rest;
            fullAllDataRowIdData[rowid] = rest;
        }
        else {
            if (parentRowId) {
                warnLog('vxe.error.unableInsert');
            }
            afterFullData[funcName](item);
            tableFullTreeData[funcName](item);
            const rest = { row: item, rowid, _seq: -1, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: tableFullTreeData, parent: null, level: 0, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 };
            fullDataRowIdData[rowid] = rest;
            fullAllDataRowIdData[rowid] = rest;
        }
    });
}
// function insertGroupRow ($xeTable: VxeTableConstructor & VxeTablePrivateMethods, newRecords: any[], isAppend: boolean) {
// }
function handleInsertRowAt($xeTable, records, targetRowOrRowid, isInsertNextRow) {
    const props = $xeTable;
    const reactData = $xeTable;
    const internalData = $xeTable;
    const { treeConfig } = props;
    const { isRowGroupStatus } = reactData;
    const { tableFullTreeData, afterFullData, mergeBodyList, tableFullData, fullDataRowIdData, fullAllDataRowIdData, insertRowMaps, removeRowMaps } = internalData;
    const treeOpts = $xeTable.computeTreeOpts;
    const { transform, parentField, rowField, mapChildrenField } = treeOpts;
    const childrenField = treeOpts.children || treeOpts.childrenField;
    if (!XEUtils.isArray(records)) {
        records = [records];
    }
    let targetRow = targetRowOrRowid;
    if (XEUtils.isString(targetRowOrRowid) || XEUtils.isNumber(targetRowOrRowid)) {
        const rowRest = fullAllDataRowIdData[targetRowOrRowid];
        if (rowRest) {
            targetRow = rowRest.row;
        }
    }
    if (!records.length) {
        return Promise.resolve({ row: null, rows: [] });
    }
    $xeTable.handlePushStack();
    const newRecords = $xeTable.defineField(records.map(record => Object.assign(treeConfig && transform ? { [mapChildrenField]: [], [childrenField]: [] } : {}, record)));
    let treeRecords = [];
    if (treeConfig && transform) {
        treeRecords = XEUtils.toArrayTree(newRecords, { key: rowField, parentKey: parentField, children: childrenField });
    }
    if (XEUtils.eqNull(targetRow)) {
        // 如果为虚拟树
        if (treeConfig && transform) {
            insertTreeRow($xeTable, newRecords, false);
        }
        else if (isRowGroupStatus) {
            // 如果分组
            if (treeConfig) {
                throw new Error(getI18n('vxe.error.noTree', ['insert']));
            }
            errLog(getI18n('vxe.error.noGroup', ['insert']));
            // insertGroupRow($xeTable, newRecords, false)
        }
        else {
            newRecords.forEach(item => {
                const rowid = getRowid($xeTable, item);
                const rest = { row: item, rowid, _seq: -1, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: afterFullData, parent: null, level: 0, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 };
                fullDataRowIdData[rowid] = rest;
                fullAllDataRowIdData[rowid] = rest;
                afterFullData.unshift(item);
                tableFullData.unshift(item);
            });
            // 刷新单元格合并
            mergeBodyList.forEach((mergeItem) => {
                const { row: mergeRowIndex } = mergeItem;
                if (mergeRowIndex >= 0) {
                    mergeItem.row = mergeRowIndex + newRecords.length;
                }
            });
        }
    }
    else {
        if (targetRow === -1) {
            // 如果为虚拟树
            if (treeConfig && transform) {
                insertTreeRow($xeTable, newRecords, true);
            }
            else if (isRowGroupStatus) {
                // 如果分组
                if (treeConfig) {
                    throw new Error(getI18n('vxe.error.noTree', ['insert']));
                }
                errLog(getI18n('vxe.error.noGroup', ['insert']));
                // insertGroupRow($xeTable, newRecords, true)
            }
            else {
                newRecords.forEach(item => {
                    const rowid = getRowid($xeTable, item);
                    const rest = { row: item, rowid, _seq: -1, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: afterFullData, parent: null, level: 0, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 };
                    fullDataRowIdData[rowid] = rest;
                    fullAllDataRowIdData[rowid] = rest;
                    afterFullData.push(item);
                    tableFullData.push(item);
                });
            }
        }
        else {
            // 如果为虚拟树
            if (treeConfig && transform) {
                const matchMapObj = XEUtils.findTree(tableFullTreeData, item => targetRow[rowField] === item[rowField], { children: mapChildrenField });
                if (matchMapObj) {
                    const { parent: parentRow } = matchMapObj;
                    const parentMapChilds = parentRow ? parentRow[mapChildrenField] : tableFullTreeData;
                    const parentRest = fullAllDataRowIdData[getRowid($xeTable, parentRow)];
                    const parentLevel = parentRest ? parentRest.level : 0;
                    treeRecords.forEach((row, i) => {
                        if (parentRow) {
                            if (row[parentField] !== parentRow[rowField]) {
                                errLog('vxe.error.errProp', [`${parentField}=${row[parentField]}`, `${parentField}=${parentRow[rowField]}`]);
                                row[parentField] = parentRow[rowField];
                            }
                        }
                        else {
                            if (row[parentField] !== null) {
                                if (!XEUtils.eqNull(row[parentField])) {
                                    errLog('vxe.error.errProp', [`${parentField}=${row[parentField]}`, 'null']);
                                }
                                row[parentField] = null;
                            }
                        }
                        let targetIndex = matchMapObj.index + i;
                        if (isInsertNextRow) {
                            targetIndex = targetIndex + 1;
                        }
                        parentMapChilds.splice(targetIndex, 0, row);
                    });
                    XEUtils.eachTree(treeRecords, (item) => {
                        const rowid = getRowid($xeTable, item);
                        const rest = { row: item, rowid, _seq: -1, seq: -1, index: -1, _index: -1, $index: -1, treeIndex: -1, _tIndex: -1, items: parentMapChilds, parent: parentRow, level: parentLevel + 1, height: 0, resizeHeight: 0, oTop: 0, expandHeight: 0 };
                        if (item[childrenField]) {
                            item[mapChildrenField] = item[childrenField];
                        }
                        fullDataRowIdData[rowid] = rest;
                        fullAllDataRowIdData[rowid] = rest;
                    }, { children: childrenField });
                    // 源
                    if (parentRow) {
                        const matchObj = XEUtils.findTree(tableFullTreeData, item => targetRow[rowField] === item[rowField], { children: childrenField });
                        if (matchObj) {
                            const parentChilds = matchObj.items;
                            let targetIndex = matchObj.index;
                            if (isInsertNextRow) {
                                targetIndex = targetIndex + 1;
                            }
                            parentChilds.splice(targetIndex, 0, ...treeRecords);
                        }
                    }
                }
                else {
                    warnLog('vxe.error.unableInsert');
                    insertTreeRow($xeTable, newRecords, true);
                }
            }
            else if (isRowGroupStatus) {
                // 如果分组
                if (treeConfig) {
                    throw new Error(getI18n('vxe.error.noTree', ['insert']));
                }
                errLog(getI18n('vxe.error.noGroup', ['insert']));
            }
            else {
                if (treeConfig) {
                    throw new Error(getI18n('vxe.error.noTree', ['insert']));
                }
                let afIndex = -1;
                // 如果是可视索引
                if (XEUtils.isNumber(targetRow)) {
                    if (targetRow < afterFullData.length) {
                        afIndex = targetRow;
                    }
                }
                else {
                    afIndex = $xeTable.findRowIndexOf(afterFullData, targetRow);
                }
                // 如果是插入指定行的下一行
                if (isInsertNextRow) {
                    afIndex = Math.min(afterFullData.length, afIndex + 1);
                }
                if (afIndex === -1) {
                    throw new Error(getI18n('vxe.error.unableInsert'));
                }
                afterFullData.splice(afIndex, 0, ...newRecords);
                const tfIndex = $xeTable.findRowIndexOf(tableFullData, targetRow);
                if (tfIndex > -1) {
                    tableFullData.splice(tfIndex + (isInsertNextRow ? 1 : 0), 0, ...newRecords);
                }
                else {
                    tableFullData.push(...newRecords);
                }
                // 刷新单元格合并
                mergeBodyList.forEach((mergeItem) => {
                    const { row: mergeRowIndex, rowspan: mergeRowspan } = mergeItem;
                    if (mergeRowIndex >= afIndex) {
                        mergeItem.row = mergeRowIndex + newRecords.length;
                    }
                    else if (isInsertNextRow ? (mergeRowIndex + mergeRowspan >= afIndex) : (mergeRowIndex + mergeRowspan > afIndex)) {
                        mergeItem.rowspan = mergeRowspan + newRecords.length;
                    }
                });
            }
        }
    }
    const handleStatus = (newRow) => {
        const rowid = getRowid($xeTable, newRow);
        // 如果是被删除的数据，则还原状态
        if (removeRowMaps[rowid]) {
            delete removeRowMaps[rowid];
            if (insertRowMaps[rowid]) {
                delete insertRowMaps[rowid];
            }
        }
        else {
            insertRowMaps[rowid] = newRow;
        }
    };
    // 如果为虚拟树
    if (treeConfig && transform) {
        XEUtils.eachTree(treeRecords, handleStatus, { children: mapChildrenField });
    }
    else {
        newRecords.forEach(handleStatus);
    }
    reactData.removeRowFlag++;
    reactData.insertRowFlag++;
    $xeTable.cacheRowMap(false);
    $xeTable.updateScrollYStatus();
    $xeTable.handleTableData(treeConfig && transform);
    if (!(treeConfig && transform)) {
        $xeTable.updateAfterDataIndex();
    }
    $xeTable.updateFooter();
    $xeTable.handleUpdateBodyMerge();
    $xeTable.checkSelectionStatus();
    if (reactData.scrollYLoad) {
        $xeTable.updateScrollYSpace();
    }
    return $xeTable.$nextTick().then(() => {
        $xeTable.updateCellAreas();
        return $xeTable.recalculate(true);
    }).then(() => {
        return {
            row: newRecords.length ? newRecords[newRecords.length - 1] : null,
            rows: newRecords
        };
    });
}
function handleInsertChildRowAt($xeTable, records, parentRowOrParentId, targetRowOrRowid, isInsertNextRow) {
    const props = $xeTable;
    const internalData = $xeTable;
    const { treeConfig } = props;
    const { fullAllDataRowIdData } = internalData;
    const treeOpts = $xeTable.computeTreeOpts;
    const { transform, rowField, parentField } = treeOpts;
    if (treeConfig && transform) {
        if (!XEUtils.isArray(records)) {
            records = [records];
        }
        let parentRow = parentRowOrParentId;
        if (XEUtils.isString(parentRowOrParentId) || XEUtils.isNumber(parentRowOrParentId)) {
            const rowRest = fullAllDataRowIdData[parentRowOrParentId];
            if (rowRest) {
                parentRow = rowRest.row;
            }
        }
        return handleInsertRowAt($xeTable, records.map((item) => Object.assign({}, item, { [parentField]: parentRow[rowField] })), targetRowOrRowid, isInsertNextRow);
    }
    else {
        errLog('vxe.error.errProp', ['tree-config.transform=false', 'tree-config.transform=true']);
    }
    return Promise.resolve({ row: null, rows: [] });
}
function handleClearEdit($xeTable, evnt, targetRow) {
    const reactData = $xeTable;
    const { editStore } = reactData;
    const { actived, focused } = editStore;
    const { row, column } = actived;
    const validOpts = $xeTable.computeValidOpts;
    if (row || column) {
        if (targetRow && getRowid($xeTable, targetRow) !== getRowid($xeTable, row)) {
            return $xeTable.$nextTick();
        }
        syncActivedCell($xeTable);
        $xeTable.updateFooter();
        actived.args = null;
        actived.row = null;
        actived.column = null;
        $xeTable.dispatchEvent('edit-closed', {
            row,
            rowIndex: $xeTable.getRowIndex(row),
            $rowIndex: $xeTable.getVMRowIndex(row),
            column,
            columnIndex: $xeTable.getColumnIndex(column),
            $columnIndex: $xeTable.getVMColumnIndex(column)
        }, evnt || null);
    }
    focused.row = null;
    focused.column = null;
    if (validOpts.autoClear) {
        if (validOpts.msgMode !== 'full' || getConfig().cellVaildMode === 'obsolete') {
            if ($xeTable.clearValidate) {
                return $xeTable.clearValidate();
            }
        }
    }
    return $xeTable.$nextTick().then(() => $xeTable.updateCellAreas());
}
function handleEditActive($xeTable, params, evnt, options) {
    const props = $xeTable;
    const reactData = $xeTable;
    const $xeGrid = $xeTable.$xeGrid;
    const { editConfig, mouseConfig } = props;
    const { editStore, tableColumn } = reactData;
    const editOpts = $xeTable.computeEditOpts;
    const { mode } = editOpts;
    const { actived, focused } = editStore;
    const { row, column } = params;
    const { editRender } = column;
    const { isFocus, isPos, isClear } = options;
    const cell = (params.cell || $xeTable.getCellElement(row, column));
    const beforeEditMethod = editOpts.beforeEditMethod || editOpts.activeMethod;
    params.cell = cell;
    if (cell && isEnableConf(editConfig) && isEnableConf(editRender)) {
        // 激活编辑
        if (!$xeTable.isPendingByRow(row) && !$xeTable.isAggregateRecord(row)) {
            if (actived.row !== row || (mode === 'cell' ? actived.column !== column : false)) {
                // 判断是否禁用编辑
                let type = 'edit-disabled';
                if (!beforeEditMethod || beforeEditMethod(Object.assign(Object.assign({}, params), { $table: $xeTable, $grid: $xeGrid }))) {
                    if (mouseConfig) {
                        $xeTable.clearSelected();
                        if ($xeTable.clearCellAreas) {
                            $xeTable.clearCellAreas();
                            $xeTable.clearCopyCellArea();
                        }
                    }
                    $xeTable.closeTooltip();
                    if (actived.column) {
                        handleClearEdit($xeTable, evnt);
                    }
                    type = 'edit-activated';
                    column.renderHeight = cell.offsetHeight;
                    actived.args = params;
                    actived.row = row;
                    actived.column = column;
                    $xeTable.handlePushStack();
                    if (isClear) {
                        setCellValue(row, column, null);
                    }
                    if (mode === 'row') {
                        tableColumn.forEach((column) => getEditColumnModel(row, column));
                    }
                    else {
                        getEditColumnModel(row, column);
                    }
                    const afterEditMethod = editOpts.afterEditMethod;
                    $xeTable.$nextTick(() => {
                        if (isFocus) {
                            $xeTable.handleFocus(params, evnt);
                        }
                        if (afterEditMethod) {
                            afterEditMethod(Object.assign(Object.assign({}, params), { $table: $xeTable, $grid: $xeGrid }));
                        }
                    });
                }
                $xeTable.dispatchEvent(type, {
                    row,
                    rowIndex: $xeTable.getRowIndex(row),
                    $rowIndex: $xeTable.getVMRowIndex(row),
                    column,
                    columnIndex: $xeTable.getColumnIndex(column),
                    $columnIndex: $xeTable.getVMColumnIndex(column)
                }, evnt);
                // v4已废弃
                if (type === 'edit-activated') {
                    $xeTable.dispatchEvent('edit-actived', {
                        row,
                        rowIndex: $xeTable.getRowIndex(row),
                        $rowIndex: $xeTable.getVMRowIndex(row),
                        column,
                        columnIndex: $xeTable.getColumnIndex(column),
                        $columnIndex: $xeTable.getVMColumnIndex(column)
                    }, evnt);
                }
            }
            else {
                const { column: oldColumn } = actived;
                if (mouseConfig) {
                    $xeTable.clearSelected();
                    if ($xeTable.clearCellAreas) {
                        $xeTable.clearCellAreas();
                        $xeTable.clearCopyCellArea();
                    }
                }
                if (oldColumn && oldColumn !== column) {
                    const { model: oldModel } = oldColumn;
                    if (oldModel.update) {
                        setCellValue(row, oldColumn, oldModel.value);
                    }
                    if ($xeTable.clearValidate) {
                        $xeTable.clearValidate(row, column);
                    }
                }
                column.renderHeight = cell.offsetHeight;
                actived.args = params;
                actived.column = column;
                if (isPos) {
                    setTimeout(() => {
                        $xeTable.handleFocus(params, evnt);
                    });
                }
            }
            focused.column = null;
            focused.row = null;
            $xeTable.focus();
        }
    }
    return $xeTable.$nextTick();
}
function handleEditCell($xeTable, row, fieldOrColumn, options) {
    const props = $xeTable;
    const internalData = $xeTable;
    const { editConfig } = props;
    const { isPos } = options;
    const column = XEUtils.isString(fieldOrColumn) ? $xeTable.getColumnByField(fieldOrColumn) : fieldOrColumn;
    if (row && column && isEnableConf(editConfig) && isEnableConf(column.editRender) && !$xeTable.isAggregateRecord(row)) {
        return Promise.resolve(isPos ? $xeTable.scrollToRow(row, column) : null).then(() => {
            const cell = $xeTable.getCellElement(row, column);
            if (cell) {
                handleEditActive($xeTable, {
                    row,
                    rowIndex: $xeTable.getRowIndex(row),
                    column,
                    columnIndex: $xeTable.getColumnIndex(column),
                    cell,
                    $table: $xeTable
                }, null, options);
                internalData._lastCallTime = Date.now();
            }
            return $xeTable.$nextTick();
        });
    }
    return $xeTable.$nextTick();
}
export default {
    methods: {
        /**
         * 往表格中插入临时数据
         *
         * @param {*} records
         */
        _insert(records) {
            const $xeTable = this;
            return handleInsertRowAt($xeTable, records, null);
        },
        /**
         * 往表格指定行中插入临时数据
         * 如果 row 为空则从插入到顶部
         * 如果 row 为 -1 则从插入到底部
         * 如果 row 为有效行则插入到该行的位置
         * @returns
         */
        _insertAt(records, targetRowOrRowid) {
            const $xeTable = this;
            return handleInsertRowAt($xeTable, records, targetRowOrRowid);
        },
        _insertNextAt(records, targetRowOrRowid) {
            const $xeTable = this;
            return handleInsertRowAt($xeTable, records, targetRowOrRowid, true);
        },
        _insertChild(records, parentRowOrParentId) {
            const $xeTable = this;
            return handleInsertChildRowAt($xeTable, records, parentRowOrParentId, null);
        },
        _insertChildAt(records, parentRowOrParentId, targetRowOrRowid) {
            const $xeTable = this;
            return handleInsertChildRowAt($xeTable, records, parentRowOrParentId, targetRowOrRowid);
        },
        _insertChildNextAt(records, parentRowOrParentId, targetRowOrRowid) {
            const $xeTable = this;
            return handleInsertChildRowAt($xeTable, records, parentRowOrParentId, targetRowOrRowid, true);
        },
        /**
         * 删除指定行数据
         * 如果传 row 则删除一行
         * 如果传 rows 则删除多行
         * 如果为空则删除所有
         */
        _remove(rows) {
            const $xeTable = this;
            const props = $xeTable;
            const reactData = $xeTable;
            const internalData = $xeTable;
            const { treeConfig } = props;
            const { editStore, isRowGroupStatus } = reactData;
            const { tableFullTreeData, selectCheckboxMaps, afterFullData, mergeBodyList, tableFullData, pendingRowMaps, insertRowMaps, removeRowMaps } = internalData;
            const checkboxOpts = $xeTable.computeCheckboxOpts;
            const treeOpts = $xeTable.computeTreeOpts;
            const { transform, mapChildrenField } = treeOpts;
            const childrenField = treeOpts.children || treeOpts.childrenField;
            const { actived } = editStore;
            const { checkField } = checkboxOpts;
            let delList = [];
            if (!rows) {
                rows = tableFullData;
            }
            else if (!XEUtils.isArray(rows)) {
                rows = [rows];
            }
            if (!rows.length) {
                return Promise.resolve({ row: null, rows: [] });
            }
            $xeTable.handlePushStack();
            // 如果是新增，则保存记录
            rows.forEach(row => {
                if (!$xeTable.isInsertByRow(row)) {
                    const rowid = getRowid($xeTable, row);
                    removeRowMaps[rowid] = row;
                }
            });
            // 如果绑定了多选属性，则更新状态
            if (!checkField) {
                rows.forEach((row) => {
                    const rowid = getRowid(this, row);
                    if (selectCheckboxMaps[rowid]) {
                        delete selectCheckboxMaps[rowid];
                    }
                });
                reactData.updateCheckboxFlag++;
            }
            // 从数据源中移除
            if (tableFullData === rows) {
                rows = delList = tableFullData.slice(0);
                internalData.tableFullData = [];
                internalData.afterFullData = [];
                $xeTable.clearMergeCells();
            }
            else {
                // 如果为虚拟树
                if (treeConfig && transform) {
                    rows.forEach((row) => {
                        const rowid = getRowid($xeTable, row);
                        const matchMapObj = XEUtils.findTree(tableFullTreeData, item => rowid === getRowid($xeTable, item), { children: mapChildrenField });
                        if (matchMapObj) {
                            const rItems = matchMapObj.items.splice(matchMapObj.index, 1);
                            delList.push(rItems[0]);
                        }
                        const matchObj = XEUtils.findTree(tableFullTreeData, item => rowid === getRowid($xeTable, item), { children: childrenField });
                        if (matchObj) {
                            matchObj.items.splice(matchObj.index, 1);
                        }
                        const afIndex = $xeTable.findRowIndexOf(afterFullData, row);
                        if (afIndex > -1) {
                            afterFullData.splice(afIndex, 1);
                        }
                    });
                }
                else if (isRowGroupStatus) {
                    // 如果分组
                    warnLog(getI18n('vxe.error.noGroup', ['remove']));
                }
                else {
                    rows.forEach((row) => {
                        const tfIndex = $xeTable.findRowIndexOf(tableFullData, row);
                        if (tfIndex > -1) {
                            const rItems = tableFullData.splice(tfIndex, 1);
                            delList.push(rItems[0]);
                        }
                        const afIndex = $xeTable.findRowIndexOf(afterFullData, row);
                        if (afIndex > -1) {
                            // 刷新单元格合并
                            mergeBodyList.forEach((mergeItem) => {
                                const { row: mergeRowIndex, rowspan: mergeRowspan } = mergeItem;
                                if (mergeRowIndex > afIndex) {
                                    mergeItem.row = mergeRowIndex - 1;
                                }
                                else if (mergeRowIndex + mergeRowspan > afIndex) {
                                    mergeItem.rowspan = mergeRowspan - 1;
                                }
                            });
                            afterFullData.splice(afIndex, 1);
                        }
                    });
                }
            }
            // 如果当前行被激活编辑，则清除激活状态
            if (actived.row && $xeTable.findRowIndexOf(rows, actived.row) > -1) {
                $xeTable.clearEdit();
            }
            // 从新增中移除已删除的数据
            rows.forEach((row) => {
                const rowid = getRowid($xeTable, row);
                if (insertRowMaps[rowid]) {
                    delete insertRowMaps[rowid];
                }
                if (pendingRowMaps[rowid]) {
                    delete pendingRowMaps[rowid];
                }
            });
            reactData.removeRowFlag++;
            reactData.insertRowFlag++;
            reactData.pendingRowFlag++;
            $xeTable.cacheRowMap(false);
            $xeTable.handleTableData(treeConfig && transform);
            $xeTable.updateFooter();
            $xeTable.handleUpdateBodyMerge();
            if (!(treeConfig && transform)) {
                $xeTable.updateAfterDataIndex();
            }
            $xeTable.checkSelectionStatus();
            if (reactData.scrollYLoad) {
                $xeTable.updateScrollYSpace();
            }
            return $xeTable.$nextTick().then(() => {
                $xeTable.updateCellAreas();
                return $xeTable.recalculate(true);
            }).then(() => {
                return { row: delList.length ? delList[delList.length - 1] : null, rows: delList };
            });
        },
        /**
         * 删除复选框选中的数据
         */
        _removeCheckboxRow() {
            const $xeTable = this;
            return $xeTable.remove($xeTable.getCheckboxRecords()).then((params) => {
                $xeTable.clearCheckboxRow();
                return params;
            });
        },
        /**
         * 删除单选框选中的数据
         */
        _removeRadioRow() {
            const $xeTable = this;
            const radioRecord = $xeTable.getRadioRecord();
            return $xeTable.remove(radioRecord || []).then((params) => {
                $xeTable.clearRadioRow();
                return params;
            });
        },
        /**
         * 删除当前行选中的数据
         */
        _removeCurrentRow() {
            const $xeTable = this;
            const currentRecord = $xeTable.getCurrentRecord();
            return $xeTable.remove(currentRecord || []).then((params) => {
                $xeTable.clearCurrentRow();
                return params;
            });
        },
        /**
         * 获取表格数据集，包含新增、删除、修改
         */
        _getRecordset() {
            const $xeTable = this;
            const removeRecords = $xeTable.getRemoveRecords();
            const pendingRecords = $xeTable.getPendingRecords();
            const delRecords = removeRecords.concat(pendingRecords);
            // 如果已经被删除，则无需放到更新数组
            const updateRecords = $xeTable.getUpdateRecords().filter((row) => {
                return !delRecords.some((item) => $xeTable.eqRow(item, row));
            });
            return {
                insertRecords: $xeTable.getInsertRecords(),
                removeRecords,
                updateRecords,
                pendingRecords
            };
        },
        /**
         * 获取新增的临时数据
         */
        _getInsertRecords() {
            const $xeTable = this;
            const internalData = $xeTable;
            const { fullAllDataRowIdData, insertRowMaps } = internalData;
            const insertRecords = [];
            XEUtils.each(insertRowMaps, (row, rowid) => {
                if (fullAllDataRowIdData[rowid]) {
                    insertRecords.push(row);
                }
            });
            return insertRecords;
        },
        /**
         * 获取已删除的数据
         */
        _getRemoveRecords() {
            const $xeTable = this;
            const internalData = $xeTable;
            const { removeRowMaps } = internalData;
            const removeRecords = [];
            XEUtils.each(removeRowMaps, (row) => {
                removeRecords.push(row);
            });
            return removeRecords;
        },
        /**
         * 获取更新数据
         * 只精准匹配 row 的更改
         * 如果是树表格，子节点更改状态不会影响父节点的更新状态
         */
        _getUpdateRecords() {
            const $xeTable = this;
            const props = $xeTable;
            const internalData = $xeTable;
            const { keepSource, treeConfig } = props;
            const { tableFullData, tableFullTreeData } = internalData;
            const treeOpts = $xeTable.computeTreeOpts;
            const updateRecords = [];
            if (keepSource) {
                syncActivedCell($xeTable);
                if (treeConfig) {
                    const childrenField = treeOpts.children || treeOpts.childrenField;
                    XEUtils.eachTree(tableFullTreeData, row => {
                        if ($xeTable.isUpdateByRow(row)) {
                            updateRecords.push(row);
                        }
                    }, { children: childrenField });
                }
                else {
                    tableFullData.forEach((row) => {
                        if ($xeTable.isUpdateByRow(row)) {
                            updateRecords.push(row);
                        }
                    });
                }
            }
            return updateRecords;
        },
        /**
         * 处理激活编辑
         */
        handleEdit(params, evnt, options) {
            const $xeTable = this;
            return handleEditActive($xeTable, params, evnt, Object.assign({
                isFocus: true,
                isPos: true
            }, options));
        },
        /**
         * @deprecated
         */
        handleActived(params, evnt) {
            const $xeTable = this;
            return $xeTable.handleEdit(params, evnt);
        },
        _getColumnModel(row, column) {
            getEditColumnModel(row, column);
        },
        _setColumnModel(row, column) {
            setEditColumnModel(row, column);
        },
        _syncActivedCell() {
            const $xeTable = this;
            syncActivedCell($xeTable);
        },
        _clearActived(row) {
            const $xeTable = this;
            warnLog('vxe.error.delFunc', ['clearActived', 'clearEdit']);
            // 即将废弃
            return $xeTable.clearEdit(row);
        },
        /**
         * 清除激活的编辑
         */
        _clearEdit(row) {
            const $xeTable = this;
            return handleClearEdit($xeTable, null, row);
        },
        /**
         * 取消编辑
         */
        handleClearEdit(evnt, targetRow) {
            const $xeTable = this;
            return handleClearEdit($xeTable, evnt, targetRow);
        },
        _getActiveRecord() {
            const $xeTable = this;
            const reactData = $xeTable;
            const internalData = $xeTable;
            warnLog('vxe.error.delFunc', ['getActiveRecord', 'getEditCell']);
            const { editStore } = reactData;
            const { fullAllDataRowIdData } = internalData;
            const { args, row } = editStore.actived;
            if (args && row && fullAllDataRowIdData[getRowid($xeTable, row)]) {
                return Object.assign({}, args, { row });
            }
            return null;
        },
        _getEditRecord() {
            const $xeTable = this;
            const reactData = $xeTable;
            const internalData = $xeTable;
            warnLog('vxe.error.delFunc', ['getEditRecord', 'getEditCell']);
            const { editStore } = reactData;
            const { fullAllDataRowIdData } = internalData;
            const { args, row } = editStore.actived;
            if (args && row && fullAllDataRowIdData[getRowid($xeTable, row)]) {
                return Object.assign({}, args, { row });
            }
            return null;
        },
        _getEditCell() {
            const $xeTable = this;
            const reactData = $xeTable;
            const { editStore } = reactData;
            const { row, column } = editStore.actived;
            if (column && row) {
                return {
                    row,
                    rowIndex: $xeTable.getRowIndex(row),
                    column,
                    columnIndex: $xeTable.getColumnIndex(column)
                };
            }
            return null;
        },
        _isActiveByRow(row) {
            const $xeTable = this;
            warnLog('vxe.error.delFunc', ['isActiveByRow', 'isEditByRow']);
            // 即将废弃
            return $xeTable.isEditByRow(row);
        },
        /**
         * 判断行是否为激活编辑状态
         * @param {Row} row 行对象
         */
        _isEditByRow(row) {
            const $xeTable = this;
            const reactData = $xeTable;
            const { editStore } = reactData;
            return editStore.actived.row === row;
        },
        /**
         * 处理聚焦
         */
        handleFocus(params) {
            const $xeTable = this;
            const { row, column, cell } = params;
            const { editRender } = column;
            const editOpts = $xeTable.computeEditOpts;
            if (isEnableConf(editRender)) {
                const browseObj = XEUtils.browse();
                const compRender = renderer.get(editRender.name);
                let autoFocus = editRender.autofocus || editRender.autoFocus;
                let autoSelect = editRender.autoSelect || editRender.autoselect;
                let inputElem;
                // 是否启用聚焦
                if (editOpts.autoFocus) {
                    if (!autoFocus && compRender) {
                        autoFocus = compRender.tableAutoFocus || compRender.tableAutofocus || compRender.autoFocus || compRender.autofocus;
                    }
                    if (!autoSelect && compRender) {
                        autoSelect = compRender.tableAutoSelect || compRender.autoSelect || compRender.autoselect;
                    }
                    // 如果指定了聚焦 class
                    if (XEUtils.isFunction(autoFocus)) {
                        inputElem = autoFocus.call($xeTable, params);
                    }
                    else if (autoFocus) {
                        if (autoFocus === true) {
                            // 自动匹配模式，会自动匹配第一个可输入元素
                            inputElem = cell.querySelector('input,textarea');
                        }
                        else {
                            inputElem = cell.querySelector(autoFocus);
                        }
                        if (inputElem) {
                            inputElem.focus();
                        }
                    }
                }
                if (inputElem) {
                    if (autoSelect) {
                        inputElem.select();
                    }
                    else {
                        // 保持一致行为，光标移到末端
                        if (browseObj.msie) {
                            const textRange = inputElem.createTextRange();
                            textRange.collapse(false);
                            textRange.select();
                        }
                    }
                }
                else {
                    // 是否自动定位
                    if (editOpts.autoPos) {
                        if (!column.fixed) {
                            // 显示到可视区中
                            $xeTable.scrollToRow(row, column);
                        }
                    }
                }
            }
        },
        _setActiveRow(row) {
            const $xeTable = this;
            warnLog('vxe.error.delFunc', ['setActiveRow', 'setEditRow']);
            // 即将废弃
            return $xeTable.setEditRow(row);
        },
        /**
         * 激活行编辑
         */
        _setEditRow(row, fieldOrColumn, options) {
            const $xeTable = this;
            const internalData = $xeTable;
            const { visibleColumn } = internalData;
            let column = XEUtils.find(visibleColumn, column => isEnableConf(column.editRender));
            let isPos = false;
            if (fieldOrColumn) {
                isPos = true;
                if (fieldOrColumn !== true) {
                    column = XEUtils.isString(fieldOrColumn) ? $xeTable.getColumnByField(fieldOrColumn) : fieldOrColumn;
                }
            }
            return handleEditCell($xeTable, row, column, Object.assign({
                isPos,
                isFocus: isPos
            }, options));
        },
        _setActiveCell(row, fieldOrColumn) {
            const $xeTable = this;
            warnLog('vxe.error.delFunc', ['setActiveCell', 'setEditCell']);
            // 即将废弃
            return $xeTable.setEditCell(row, fieldOrColumn);
        },
        /**
         * 激活单元格编辑
         */
        _setEditCell(row, fieldOrColumn, options) {
            const $xeTable = this;
            return handleEditCell($xeTable, row, fieldOrColumn, Object.assign({
                isFocus: true,
                isPos: true
            }, options));
        },
        /**
         * 只对 trigger=dblclick 有效，选中单元格
         */
        _setSelectCell(row, fieldOrColumn) {
            const $xeTable = this;
            const reactData = $xeTable;
            const { tableData } = reactData;
            const editOpts = $xeTable.computeEditOpts;
            const column = XEUtils.isString(fieldOrColumn) ? $xeTable.getColumnByField(fieldOrColumn) : fieldOrColumn;
            if (row && column && editOpts.trigger !== 'manual') {
                const rowIndex = $xeTable.findRowIndexOf(tableData, row);
                if (rowIndex > -1) {
                    const cell = $xeTable.getCellElement(row, column);
                    const params = {
                        row,
                        rowIndex,
                        column,
                        columnIndex: $xeTable.getColumnIndex(column),
                        cell
                    };
                    $xeTable.handleSelected(params, {});
                }
            }
            return $xeTable.$nextTick();
        },
        /**
         * 处理选中源
         */
        handleSelected(params, evnt) {
            const $xeTable = this;
            const props = $xeTable;
            const reactData = $xeTable;
            const { mouseConfig } = props;
            const { editStore } = reactData;
            const mouseOpts = $xeTable.computeMouseOpts;
            const editOpts = $xeTable.computeEditOpts;
            const { actived, selected } = editStore;
            const { row, column } = params;
            const isMouseSelected = mouseConfig && mouseOpts.selected;
            const selectMethod = () => {
                if (isMouseSelected && (selected.row !== row || selected.column !== column)) {
                    if (actived.row !== row || (editOpts.mode === 'cell' ? actived.column !== column : false)) {
                        handleClearEdit($xeTable, evnt);
                        $xeTable.clearSelected();
                        if ($xeTable.clearCellAreas) {
                            $xeTable.clearCellAreas();
                            $xeTable.clearCopyCellArea();
                        }
                        selected.args = params;
                        selected.row = row;
                        selected.column = column;
                        if (isMouseSelected) {
                            $xeTable.addCellSelectedClass();
                        }
                        $xeTable.focus();
                        if (evnt) {
                            $xeTable.dispatchEvent('cell-selected', params, evnt);
                        }
                    }
                }
                return $xeTable.$nextTick();
            };
            return selectMethod();
        },
        /**
         * 获取选中的单元格
         */
        _getSelectedCell() {
            const $xeTable = this;
            const reactData = $xeTable;
            const { editStore } = reactData;
            const { row, column } = editStore.selected;
            if (row && column) {
                return {
                    row,
                    column
                };
            }
            return null;
        },
        /**
         * 清除所选中源状态
         */
        _clearSelected() {
            const $xeTable = this;
            const reactData = $xeTable;
            const { editStore } = reactData;
            const { selected } = editStore;
            selected.row = null;
            selected.column = null;
            removeCellSelectedClass($xeTable);
            return $xeTable.$nextTick();
        },
        reColTitleSdCls() {
            const $xeTable = this;
            const internalData = $xeTable;
            const { elemStore } = internalData;
            const headerElem = elemStore['main-header-list'];
            if (headerElem) {
                XEUtils.arrayEach(headerElem.querySelectorAll('.col--title-selected'), elem => removeClass(elem, 'col--title-selected'));
            }
        },
        addCellSelectedClass() {
            const $xeTable = this;
            const reactData = $xeTable;
            const { editStore } = reactData;
            const { selected } = editStore;
            const { row, column } = selected;
            removeCellSelectedClass($xeTable);
            if (row && column) {
                const cell = $xeTable.getCellElement(row, column);
                if (cell) {
                    addClass(cell, 'col--selected');
                }
            }
        }
    }
};
