"use strict";

var __rest = this && this.__rest || function(s, e) {
    var t = {};
    for (var p in s) Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0 && (t[p] = s[p]);
    if (null != s && "function" == typeof Object.getOwnPropertySymbols) {
        var i = 0;
        for (p = Object.getOwnPropertySymbols(s); i < p.length; i++) e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]) && (t[p[i]] = s[p[i]]);
    }
    return t;
};

Object.defineProperty(exports, "__esModule", {
    value: !0
}), exports.WorkSheet = void 0;

const vtable_1 = require("@visactor/vtable"), vutils_1 = require("@visactor/vutils"), tools_1 = require("../tools"), ts_types_1 = require("../ts-types"), formula_paste_processor_1 = require("../formula/formula-paste-processor"), worksheet_event_manager_1 = require("../event/worksheet-event-manager");

class WorkSheet {
    get sheetKey() {
        return this._sheetKey;
    }
    getEventBus() {
        return this.eventBus ? this.eventBus : this.vtableSheet.getEventBus();
    }
    get sheetTitle() {
        return this._sheetTitle;
    }
    set sheetTitle(title) {
        this._sheetTitle = title;
    }
    constructor(sheet, options) {
        this.selection = null, this.editingCell = null, this.resizeTimer = null, this.isResizing = !1, 
        this.options = options, this.container = options.container, this._sheetKey = options.sheetKey, 
        this._sheetTitle = options.sheetTitle, this.vtableSheet = sheet, this.element = this._createRootElement(), 
        this.container.appendChild(this.element), this._initializeTable(), this._setupEventListeners();
    }
    get rowCount() {
        return this.getRowCount();
    }
    get colCount() {
        return this.getColumnCount();
    }
    getRowCount() {
        return this.tableInstance.rowCount;
    }
    getColumnCount() {
        return this.tableInstance.colCount;
    }
    get records() {
        return this.getData();
    }
    get columns() {
        return this.options.columns || [];
    }
    _createRootElement() {
        const element = document.createElement("div");
        element.setAttribute("sheet-key", `${this.sheetKey}`), element.classList.add("vtable-sheet"), 
        element.style.outline = "none", element.style.position = "relative";
        const width = this.container.clientWidth || 800, height = this.container.clientHeight || 600;
        return element.style.width = `${width}px`, element.style.height = `${height}px`, 
        element;
    }
    _initializeTable() {
        const tableOptions = this._generateTableOptions();
        this.tableInstance = new vtable_1.ListTable(tableOptions), this.element.classList.add("vtable-excel-cursor"), 
        this.eventBus = this.vtableSheet.getEventBus(), this.eventManager = new worksheet_event_manager_1.WorkSheetEventManager(this), 
        this.tableInstance.__vtableSheet = this.vtableSheet, this.vtableSheet.tableEventRelay.bindSheetEvents(this.sheetKey, this.tableInstance), 
        this.eventManager && this.eventManager.emitDataLoaded(this.rowCount, this.colCount);
    }
    _generateTableOptions() {
        let isShowTableHeader = this.options.showHeader;
        if (this.options.columns) for (let i = 0; i < this.options.columns.length; i++) this.options.columns[i].field = i, 
        this.options.columns[i].key = i; else isShowTableHeader = !!(0, vutils_1.isValid)(isShowTableHeader) && isShowTableHeader, 
        this.options.columns = [];
        if (this.options.data) {
            if (0 === this.options.columns.length && this.options.firstRowAsHeader) {
                const data = this.options.data;
                if (data && data.length > 0) for (let i = 0; i < data[0].length; i++) this.options.columns[i] = {
                    field: i,
                    key: i,
                    title: data[0][i],
                    filter: !!this.options.filter
                };
                data.shift(), isShowTableHeader = !0;
            }
        } else this.options.data = [];
        const keyboardOptions = Object.assign(Object.assign({}, this.options.keyboardOptions), {
            copySelected: !0,
            getCopyCellValue: {
                html: this.getCellValueConsiderFormula.bind(this)
            },
            processFormulaBeforePaste: this.processFormulaPaste.bind(this),
            pasteValueToCell: !0,
            showCopyCellBorder: !0,
            cutSelected: !0
        });
        return Object.assign(Object.assign({}, this.options), {
            dragOrder: {
                maintainArrayDataOrder: !0
            },
            addRecordRule: "Array",
            defaultCursor: "cell",
            records: this.options.data,
            sortState: this.options.sortState,
            container: this.element,
            showHeader: isShowTableHeader,
            keyboardOptions: keyboardOptions,
            theme: this._adjustTheme(this.options.theme),
            excelOptions: {
                fillHandle: !0
            },
            customConfig: {
                selectCellWhenCellEditorNotExists: !0
            }
        });
    }
    _adjustTheme(theme) {
        let changedTheme;
        if (this.options.theme = theme || ts_types_1.VTableThemes.DEFAULT, this.options.theme.bodyStyle && !(0, 
        tools_1.isPropertyWritable)(this.options.theme, "bodyStyle")) {
            changedTheme = this.options.theme.extends(this.options.theme.getExtendTheme());
            const extendThemeOption = changedTheme.getExtendTheme();
            extendThemeOption.frameStyle = Object.assign({}, extendThemeOption.frameStyle, {
                shadowBlur: 0,
                cornerRadius: 0,
                borderLineWidth: 0
            });
        } else "string" == typeof this.options.theme || (changedTheme = this.options.theme, 
        changedTheme.frameStyle = Object.assign({}, this.options.theme.frameStyle, {
            shadowBlur: 0,
            cornerRadius: 0,
            borderLineWidth: 0
        }));
        return changedTheme;
    }
    _setupEventListeners() {
        this.tableInstance && (this.tableInstance.on("mousedown_cell", (event => {
            this.vtableSheet.formulaManager.formulaWorkingOnCell && event.event.preventDefault();
        })), this.tableInstance.on("selected_changed", (event => {
            this.tableInstance.eventManager.isDraging || (this.vtableSheet.formulaManager.formulaWorkingOnCell || (this.editingCell = {
                sheet: this.getKey(),
                row: event.row,
                col: event.col
            }), this.handleCellSelected(event)), this.handleSelectionChanged(event);
        })), this.tableInstance.on("drag_select_end", (event => {
            this.handleDragSelectEnd(event);
        })), this.tableInstance.on("change_cell_value", (event => {
            this.handleCellValueChanged(event);
        })), this.tableInstance.on("add_record", (event => {
            this.handleDataRecordsChanged("add", event);
        })), this.tableInstance.on("delete_record", (event => {
            this.handleDataRecordsChanged("delete", event);
        })), this.tableInstance.on("add_column", (event => {
            this.handleColumnsChanged("add", event);
        })), this.tableInstance.on("delete_column", (event => {
            this.handleColumnsChanged("delete", event);
        })), this.tableInstance.on("click_cell", (() => {
            this.element.classList.add("vtable-excel-cursor");
        })), this.tableInstance.on("change_header_position", (event => {
            this.handleChangeHeaderPosition(event);
        })));
    }
    handleCellSelected(event) {
        if (this.selection = {
            startRow: event.row,
            startCol: event.col,
            endRow: event.row,
            endCol: event.col
        }, this.vtableSheet.formulaManager.formulaWorkingOnCell) return;
        const formulaUIManager = this.vtableSheet.formulaUIManager;
        formulaUIManager.isFormulaBarShowingResult = !1, formulaUIManager.clearFormula(), 
        formulaUIManager.updateFormulaBar();
    }
    handleSelectionChanged(event) {
        var _a;
        if (null === (_a = null == event ? void 0 : event.ranges) || void 0 === _a ? void 0 : _a.length) {
            const r = event.ranges[event.ranges.length - 1];
            this.selection = {
                startRow: r.start.row,
                startCol: r.start.col,
                endRow: r.end.row,
                endCol: r.end.col
            };
        }
        this.vtableSheet.formulaManager.formulaRangeSelector.handleSelectionChangedForRangeMode();
    }
    handleDragSelectEnd(event) {
        var _a;
        if (null === (_a = null == event ? void 0 : event.cells) || void 0 === _a ? void 0 : _a.length) {
            const first = event.cells[0][0], lastRow = event.cells[event.cells.length - 1], last = lastRow[lastRow.length - 1];
            this.selection = {
                startRow: first.row,
                startCol: first.col,
                endRow: last.row,
                endCol: last.col
            };
        }
        this.vtableSheet.formulaManager.formulaRangeSelector.handleSelectionChangedForRangeMode();
    }
    handleCellValueChanged(event) {
        this.vtableSheet.formulaManager.formulaRangeSelector.handleCellValueChanged(event);
    }
    handleDataRecordsChanged(type, event) {
        try {
            const sheetKey = this.getKey(), normalizedData = this.vtableSheet.formulaManager.normalizeSheetData(this.tableInstance.records, this.tableInstance);
            if (this.vtableSheet.formulaManager.formulaEngine.updateSheetData(sheetKey, normalizedData), 
            "add" === type) {
                const {recordIndex: recordIndex, recordCount: recordCount} = event;
                if (void 0 !== recordIndex && recordCount > 0) this.vtableSheet.formulaManager.addRows(sheetKey, recordIndex + this.tableInstance.columnHeaderLevelCount, recordCount); else {
                    const currentRowCount = this.getRowCount();
                    this.vtableSheet.formulaManager.addRows(sheetKey, currentRowCount, recordCount);
                }
            } else if ("delete" === type) {
                const {rowIndexs: rowIndexs, deletedCount: deletedCount} = event;
                if (rowIndexs && rowIndexs.length > 0) {
                    const minIndex = Math.min(...rowIndexs.flat());
                    if (this.vtableSheet.formulaManager.removeRows(sheetKey, minIndex, deletedCount), 
                    Array.isArray(this.tableInstance.options.customMergeCell)) {
                        const mergeCellsToRemove = [], deleteEndIndex = minIndex + deletedCount - 1, customMergeCellArray = this.tableInstance.options.customMergeCell, cloneMergeCellArray = customMergeCellArray.map((mergeCell => Object.assign(Object.assign({}, mergeCell), {
                            range: {
                                start: Object.assign({}, mergeCell.range.start),
                                end: Object.assign({}, mergeCell.range.end)
                            }
                        })));
                        customMergeCellArray.forEach(((mergeCell, index) => {
                            const startRow = mergeCell.range.start.row, endRow = mergeCell.range.end.row;
                            startRow >= minIndex && endRow <= deleteEndIndex ? mergeCellsToRemove.push(index) : startRow <= deleteEndIndex && endRow >= minIndex ? (startRow >= minIndex && (mergeCell.range.start.row = minIndex), 
                            endRow <= deleteEndIndex ? mergeCell.range.end.row = minIndex - 1 : mergeCell.range.end.row -= deletedCount, 
                            mergeCell.range.start.row > mergeCell.range.end.row && mergeCellsToRemove.push(index)) : startRow > deleteEndIndex && (mergeCell.range.start.row -= deletedCount, 
                            mergeCell.range.end.row -= deletedCount);
                        })), mergeCellsToRemove.sort(((a, b) => b - a)).forEach((index => {
                            customMergeCellArray.splice(index, 1);
                        }));
                        const updateRanges = cloneMergeCellArray.map((mergeCell => ({
                            start: Object.assign({}, mergeCell.range.start),
                            end: Object.assign({}, mergeCell.range.end)
                        })));
                        this.tableInstance.updateCellContentRange(updateRanges);
                    }
                }
            }
        } catch (error) {}
    }
    handleColumnsChanged(type, event) {
        try {
            const sheetKey = this.getKey(), normalizedData = this.vtableSheet.formulaManager.normalizeSheetData(this.tableInstance.records, this.tableInstance);
            if (this.vtableSheet.formulaManager.formulaEngine.updateSheetData(sheetKey, normalizedData), 
            "add" === type) {
                const {columnIndex: columnIndex, columnCount: columnCount} = event;
                if (void 0 !== columnIndex && columnCount > 0) this.vtableSheet.formulaManager.addColumns(sheetKey, columnIndex, columnCount); else {
                    const currentColumnCount = this.getColumnCount();
                    this.vtableSheet.formulaManager.addColumns(sheetKey, currentColumnCount, columnCount);
                }
            } else if ("delete" === type) {
                const {deleteColIndexs: deleteColIndexs} = event;
                if (deleteColIndexs && deleteColIndexs.length > 0) {
                    const minIndex = Math.min(...deleteColIndexs.flat()), deletedCount = deleteColIndexs.length;
                    if (this.vtableSheet.formulaManager.removeColumns(sheetKey, minIndex, deletedCount), 
                    Array.isArray(this.tableInstance.options.customMergeCell)) {
                        const mergeCellsToRemove = [], deleteEndIndex = minIndex + deletedCount - 1, customMergeCellArray = this.tableInstance.options.customMergeCell, cloneMergeCellArray = customMergeCellArray.map((mergeCell => Object.assign(Object.assign({}, mergeCell), {
                            range: {
                                start: Object.assign({}, mergeCell.range.start),
                                end: Object.assign({}, mergeCell.range.end)
                            }
                        })));
                        customMergeCellArray.forEach(((mergeCell, index) => {
                            const startCol = mergeCell.range.start.col, endCol = mergeCell.range.end.col;
                            startCol >= minIndex && endCol <= deleteEndIndex ? mergeCellsToRemove.push(index) : startCol <= deleteEndIndex && endCol >= minIndex ? (startCol >= minIndex && (mergeCell.range.start.col = minIndex), 
                            endCol <= deleteEndIndex ? mergeCell.range.end.col = minIndex - 1 : mergeCell.range.end.col -= deletedCount, 
                            mergeCell.range.start.col > mergeCell.range.end.col && mergeCellsToRemove.push(index)) : startCol > deleteEndIndex && (mergeCell.range.start.col -= deletedCount, 
                            mergeCell.range.end.col -= deletedCount);
                        })), mergeCellsToRemove.sort(((a, b) => b - a)).forEach((index => {
                            customMergeCellArray.splice(index, 1);
                        }));
                        const updateRanges = cloneMergeCellArray.map((mergeCell => ({
                            start: Object.assign({}, mergeCell.range.start),
                            end: Object.assign({}, mergeCell.range.end)
                        })));
                        this.tableInstance.updateCellContentRange(updateRanges);
                    }
                }
            }
        } catch (error) {}
    }
    handleChangeHeaderPosition(event) {
        "column" === event.movingColumnOrRow ? this.handleChangeColumnHeaderPosition(event) : this.handleChangeRowHeaderPosition(event);
    }
    handleChangeColumnHeaderPosition(event) {
        const {source: source, target: target} = event, {col: sourceCol} = source, {col: targetCol} = target, sheetKey = this.getKey(), normalizedData = this.vtableSheet.formulaManager.normalizeSheetData(this.tableInstance.records, this.tableInstance);
        this.vtableSheet.formulaManager.formulaEngine.updateSheetData(sheetKey, normalizedData), 
        this.vtableSheet.formulaManager.changeColumnHeaderPosition(sheetKey, sourceCol, targetCol);
    }
    handleChangeRowHeaderPosition(event) {
        const {source: source, target: target} = event, {row: sourceRow} = source, {row: targetRow} = target, sheetKey = this.getKey(), normalizedData = this.vtableSheet.formulaManager.normalizeSheetData(this.tableInstance.records, this.tableInstance);
        this.vtableSheet.formulaManager.formulaEngine.updateSheetData(sheetKey, normalizedData), 
        this.vtableSheet.formulaManager.changeRowHeaderPosition(sheetKey, sourceRow, targetRow);
    }
    resize() {
        this.element && (null !== this.resizeTimer && (window.clearTimeout(this.resizeTimer), 
        this.resizeTimer = null), this.isResizing ? this.resizeTimer = window.setTimeout((() => {
            this.doResize(), this.resizeTimer = null;
        }), 50) : this.doResize());
    }
    doResize() {
        try {
            this.isResizing = !0;
            const width = this.container.clientWidth || 800, height = this.container.clientHeight || 600;
            parseInt(this.element.style.width, 10) === width && parseInt(this.element.style.height, 10) === height || (this.element.style.width = `${width}px`, 
            this.element.style.height = `${height}px`, this.tableInstance && this.tableInstance.resize());
        } catch (error) {} finally {
            this.isResizing = !1;
        }
    }
    getElement() {
        return this.element;
    }
    getContainer() {
        return this.container;
    }
    getKey() {
        return this.sheetKey;
    }
    getTitle() {
        return this.sheetTitle;
    }
    setTitle(title) {
        this.sheetTitle = title, this.options.sheetTitle = title;
    }
    getColumns() {
        return this.tableInstance.columns || [];
    }
    getData() {
        return this.options.data || [];
    }
    getCopiedData() {
        return this.getData().map((row => Array.isArray(row) ? row.slice() : []));
    }
    getCellValue(col, row) {
        if (this.tableInstance) try {
            return this.tableInstance.getCellValue(col, row);
        } catch (error) {}
        const data = this.getData();
        return data && data[row] && void 0 !== data[row][col] ? data[row][col] : null;
    }
    getCellValueConsiderFormula(col, row) {
        if (this.tableInstance) {
            try {
                return this.vtableSheet.formulaManager.isCellFormula({
                    sheet: this.getKey(),
                    row: row,
                    col: col
                }) ? this.vtableSheet.formulaManager.getCellFormula({
                    sheet: this.getKey(),
                    row: row,
                    col: col
                }) : this.getCellValue(col, row);
            } catch (error) {}
            return null;
        }
    }
    setCellValue(col, row, value) {
        const data = this.getData();
        data && data[row] && (data[row][col] = value, this.tableInstance && this.tableInstance.changeCellValue(col, row, value));
    }
    getCellByAddress(address) {
        const coord = this.coordFromAddress(address);
        return {
            coord: coord,
            value: this.getCellValue(coord.col, coord.row)
        };
    }
    addressFromCoord(coordOrCol, row) {
        let col, rowNum;
        if ("object" == typeof coordOrCol) col = coordOrCol.col, rowNum = coordOrCol.row; else {
            if (col = coordOrCol, void 0 === row) throw new Error("row is required when coordOrCol is a number");
            rowNum = row;
        }
        let colStr = "", tempCol = col + 1;
        do {
            tempCol -= 1, colStr = String.fromCharCode(65 + tempCol % 26) + colStr, tempCol = Math.floor(tempCol / 26);
        } while (tempCol > 0);
        return `${colStr}${rowNum + 1}`;
    }
    coordFromAddress(address) {
        const match = address.match(/^([A-Z]+)([0-9]+)$/);
        if (!match) throw new Error(`Invalid cell address: ${address}`);
        const colStr = match[1], rowStr = match[2];
        let col = 0;
        for (let i = 0; i < colStr.length; i++) col = 26 * col + (colStr.charCodeAt(i) - 64);
        return {
            row: parseInt(rowStr, 10) - 1,
            col: col - 1
        };
    }
    getSelection() {
        return this.selection;
    }
    getMultipleSelections() {
        if (!this.tableInstance) return this.selection ? [ this.selection ] : [];
        const vtableRanges = this.tableInstance.getSelectedCellRanges();
        return 0 === vtableRanges.length ? this.selection ? [ this.selection ] : [] : vtableRanges.map((range => ({
            startRow: range.start.row,
            startCol: range.start.col,
            endRow: range.end.row,
            endCol: range.end.col
        })));
    }
    setFirstRowAsHeader() {
        const data = this.getData();
        if (data && data.length > 0) for (let i = 0; i < data[0].length; i++) this.options.columns[i] ? (this.options.columns[i].title = data[0][i], 
        this.options.columns[i].field = i) : this.options.columns[i] = {
            field: i,
            title: data[0][i]
        };
        data.shift();
        const _a = this.options, {dragOrder: _omitSheetDragOrder} = _a, optionsRest = __rest(_a, [ "dragOrder" ]);
        this.tableInstance.updateOption(Object.assign(Object.assign({}, optionsRest), {
            dragOrder: {
                maintainArrayDataOrder: !0
            },
            columns: this.options.columns,
            showHeader: !0,
            records: data
        }));
    }
    updateSheetOption(sheetOption) {
        this.options = Object.assign(Object.assign({}, this.options), sheetOption);
        const tableOptions = this._generateTableOptions();
        this.tableInstance.updateOption(tableOptions);
    }
    processFormulaPaste(formulas, sourceStartCol, _sourceStartRow, targetStartCol, _targetStartRow) {
        if (!formulas || 0 === formulas.length) return formulas;
        const colOffset = targetStartCol - sourceStartCol, rowOffset = _targetStartRow - _sourceStartRow;
        return formula_paste_processor_1.FormulaPasteProcessor.adjustFormulasForPasteWithOffset(formulas, colOffset, rowOffset);
    }
    getCopyData() {
        const selections = this.getMultipleSelections();
        if (0 === selections.length) return [];
        const data = this.getData(), result = [], selection = selections[0], rows = selection.endRow - selection.startRow + 1, cols = selection.endCol - selection.startCol + 1;
        for (let row = 0; row < rows; row++) {
            const rowData = [];
            for (let col = 0; col < cols; col++) {
                const actualRow = selection.startRow + row, actualCol = selection.startCol + col;
                if (data[actualRow] && void 0 !== data[actualRow][actualCol]) if (this.vtableSheet.formulaManager.isCellFormula({
                    sheet: this.getKey(),
                    row: actualRow,
                    col: actualCol
                })) {
                    const formula = this.vtableSheet.formulaManager.getCellFormula({
                        sheet: this.getKey(),
                        row: actualRow,
                        col: actualCol
                    });
                    rowData.push(formula);
                } else rowData.push(data[actualRow][actualCol]); else rowData.push("");
            }
            result.push(rowData);
        }
        return result;
    }
    pasteData(data, targetStartCol, targetStartRow) {
        if (!data || 0 === data.length) return;
        const selections = this.getMultipleSelections();
        if (0 === selections.length) return;
        const sourceSelection = selections[0], sourceStartCol = sourceSelection.startCol, sourceStartRow = sourceSelection.startRow, processedData = this.processFormulaPaste(data, sourceStartCol, sourceStartRow, targetStartCol, targetStartRow), dataArray = this.getData();
        for (let row = 0; row < processedData.length; row++) for (let col = 0; col < processedData[row].length; col++) {
            const targetRow = targetStartRow + row, targetCol = targetStartCol + col;
            if (targetRow < dataArray.length && targetCol < dataArray[targetRow].length) {
                const value = processedData[row][col];
                formula_paste_processor_1.FormulaPasteProcessor.needsFormulaAdjustment(value) ? this.setCellFormula(targetRow, targetCol, value) : this.setCellValue(targetRow, targetCol, value);
            }
        }
    }
    setCellFormula(row, col, formula) {
        this.vtableSheet.formulaManager && this.vtableSheet.formulaManager.setCellContent({
            sheet: this.getKey(),
            row: row,
            col: col
        }, formula);
    }
    release() {
        var _a;
        this.tableInstance && this.vtableSheet.tableEventRelay.unbindSheetEvents(this.sheetKey, this.tableInstance), 
        this.tableInstance && this.tableInstance.release(), this.element && this.element.parentNode && this.element.parentNode.removeChild(this.element), 
        null === (_a = this.tableInstance) || void 0 === _a || _a.release();
    }
}

exports.WorkSheet = WorkSheet;
//# sourceMappingURL=WorkSheet.js.map