var __awaiter = this && this.__awaiter || function(thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))((function(resolve, reject) {
        function fulfilled(value) {
            try {
                step(generator.next(value));
            } catch (e) {
                reject(e);
            }
        }
        function rejected(value) {
            try {
                step(generator.throw(value));
            } catch (e) {
                reject(e);
            }
        }
        function step(result) {
            var value;
            result.done ? resolve(result.value) : (value = result.value, value instanceof P ? value : new P((function(resolve) {
                resolve(value);
            }))).then(fulfilled, rejected);
        }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    }));
}, __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;
};

import { FormulaManager } from "../managers/formula-manager";

import SheetManager from "../managers/sheet-manager";

import { WorkSheet } from "../core/WorkSheet";

import * as VTable from "@visactor/vtable";

import { getTablePlugins } from "../core/table-plugins";

import { EventManager } from "../event/event-manager";

import { showSnackbar } from "../tools/ui/snackbar";

import { WorkSheetEventType } from "../ts-types";

import SheetTabDragManager from "../managers/tab-drag-manager";

import { FormulaAutocomplete } from "../formula/formula-autocomplete";

import { formulaEditor } from "../formula/formula-editor";

import { MenuManager } from "../managers/menu-manager";

import { FormulaUIManager } from "../formula/formula-ui-manager";

import { SheetTabEventHandler } from "./sheet-tab-event-handler";

VTable.register.editor("formula", formulaEditor);

export default class VTableSheet {
    constructor(container, options) {
        this.activeWorkSheet = null, this.workSheetInstances = new Map, this.formulaAutocomplete = null, 
        this.formulaBarElement = null, this.sheetTabElement = null, this.mainMenuElement = null, 
        this.container = container, this.options = this.mergeDefaultOptions(options), this.sheetManager = new SheetManager, 
        this.formulaManager = new FormulaManager(this), this.eventManager = new EventManager(this), 
        this.dragManager = new SheetTabDragManager(this), this.menuManager = new MenuManager(this), 
        this.formulaUIManager = new FormulaUIManager(this), this.sheetTabEventHandler = new SheetTabEventHandler(this), 
        this.initUI(), this.initSheets(), this.resize();
    }
    mergeDefaultOptions(options) {
        return Object.assign({
            showFormulaBar: !0,
            showSheetTab: !0,
            defaultRowHeight: 25,
            defaultColWidth: 100
        }, options);
    }
    initFormulaAutocomplete() {
        if (!this.formulaBarElement) return;
        const formulaInput = this.formulaUIManager.formulaInput;
        formulaInput && (this.formulaAutocomplete = new FormulaAutocomplete(this.rootElement, this), 
        this.formulaAutocomplete.attachTo(formulaInput));
    }
    initUI() {
        var _a;
        this.rootElement = document.createElement("div"), this.rootElement.className = "vtable-sheet-container", 
        this.container.appendChild(this.rootElement);
        const topContainer = document.createElement("div");
        topContainer.className = "vtable-sheet-top-container", this.rootElement.appendChild(topContainer), 
        (null === (_a = this.options.mainMenu) || void 0 === _a ? void 0 : _a.show) && (this.mainMenuElement = this.menuManager.createMainMenu(), 
        topContainer.appendChild(this.mainMenuElement)), this.options.showFormulaBar && (this.formulaBarElement = this.formulaUIManager.createFormulaBar(), 
        topContainer.appendChild(this.formulaBarElement), this.initFormulaAutocomplete()), 
        this.contentElement = document.createElement("div"), this.contentElement.className = "vtable-sheet-content", 
        this.rootElement.appendChild(this.contentElement), this.options.showSheetTab && (this.sheetTabElement = this.createSheetTab(), 
        this.rootElement.appendChild(this.sheetTabElement));
    }
    createSheetTab() {
        const sheetTab = document.createElement("div");
        sheetTab.className = "vtable-sheet-tab-bar";
        const fadeLeft = document.createElement("div");
        fadeLeft.className = "vtable-sheet-fade-left", fadeLeft.style.display = "none", 
        sheetTab.appendChild(fadeLeft);
        const tabsContainer = document.createElement("div");
        tabsContainer.className = "vtable-sheet-tabs-container", tabsContainer.addEventListener("scroll", (() => this.sheetTabEventHandler.updateFadeEffects(tabsContainer, fadeLeft, fadeRight))), 
        sheetTab.appendChild(tabsContainer);
        const insertIndicator = document.createElement("div");
        insertIndicator.className = "vtable-sheet-insert-indicator", insertIndicator.style.display = "none", 
        tabsContainer.appendChild(insertIndicator);
        const fadeRight = document.createElement("div");
        fadeRight.className = "vtable-sheet-fade-right", sheetTab.appendChild(fadeRight);
        const addButton = document.createElement("button");
        addButton.className = "vtable-sheet-add-button", addButton.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6z"/></svg>', 
        addButton.title = "添加工作表", addButton.addEventListener("click", (() => this._addNewSheet())), 
        sheetTab.appendChild(addButton);
        const navButtons = document.createElement("div");
        navButtons.className = "vtable-sheet-nav-buttons";
        const leftScrollBtn = document.createElement("button");
        leftScrollBtn.className = "vtable-sheet-scroll-button", leftScrollBtn.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>', 
        leftScrollBtn.title = "向左滚动", leftScrollBtn.addEventListener("click", (() => this.sheetTabEventHandler.scrollSheetTabs("left", tabsContainer))), 
        navButtons.appendChild(leftScrollBtn);
        const rightScrollBtn = document.createElement("button");
        rightScrollBtn.className = "vtable-sheet-scroll-button", rightScrollBtn.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>', 
        rightScrollBtn.title = "向右滚动", rightScrollBtn.addEventListener("click", (() => this.sheetTabEventHandler.scrollSheetTabs("right", tabsContainer))), 
        navButtons.appendChild(rightScrollBtn);
        const menuButton = document.createElement("button");
        menuButton.className = "vtable-sheet-menu-button", menuButton.innerHTML = '<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>', 
        menuButton.title = "工作表选项", menuButton.addEventListener("click", (e => this.sheetTabEventHandler.toggleSheetMenu(e))), 
        navButtons.appendChild(menuButton);
        const menuContainer = document.createElement("ul");
        return menuContainer.className = "vtable-sheet-menu-list", sheetTab.appendChild(menuContainer), 
        sheetTab.appendChild(navButtons), setTimeout((() => {
            this.sheetTabEventHandler.updateFadeEffects(tabsContainer, fadeLeft, fadeRight);
        }), 100), sheetTab;
    }
    _activeSheetTab() {
        this.sheetTabEventHandler.activeSheetTab();
    }
    updateSheetTabs(tabsContainer) {
        var _a;
        if (void 0 === tabsContainer && (tabsContainer = null === (_a = this.sheetTabElement) || void 0 === _a ? void 0 : _a.querySelector(".vtable-sheet-tabs-container")), 
        !tabsContainer) return;
        tabsContainer.querySelectorAll(".vtable-sheet-tab").forEach((tab => {
            tab.remove();
        }));
        this.sheetManager.getAllSheets().forEach(((sheet, index) => {
            tabsContainer.appendChild(this.createSheetTabItem(sheet, index));
        })), this._activeSheetTab();
    }
    createSheetTabItem(sheet, index) {
        const tab = document.createElement("div");
        return tab.className = "vtable-sheet-tab", tab.dataset.key = sheet.sheetKey, tab.textContent = sheet.sheetTitle, 
        tab.title = sheet.sheetTitle, tab.addEventListener("click", (() => this.activateSheet(sheet.sheetKey))), 
        tab.addEventListener("dblclick", (() => this.sheetTabEventHandler.handleSheetTabDblClick(sheet.sheetKey, sheet.sheetTitle))), 
        tab.addEventListener("mousedown", (e => this.dragManager.handleTabMouseDown(e, sheet.sheetKey))), 
        tab;
    }
    updateSheetMenu() {
        this.sheetTabEventHandler.updateSheetMenu();
    }
    initSheets() {
        if (this.options.sheets && this.options.sheets.length > 0) {
            this.options.sheets.forEach((sheetDefine => {
                this.sheetManager.addSheet(sheetDefine);
            }));
            let activeSheetKey = "";
            const activeSheet = this.options.sheets.find((sheet => sheet.active));
            activeSheetKey = activeSheet ? activeSheet.sheetKey : this.options.sheets[0].sheetKey, 
            this.activateSheet(activeSheetKey);
        } else this._addNewSheet();
    }
    activateSheet(sheetKey) {
        this.sheetManager.setActiveSheet(sheetKey);
        const sheetDefine = this.sheetManager.getSheet(sheetKey);
        if (sheetDefine) {
            if (this.workSheetInstances.forEach((instance => {
                instance.getElement().style.display = "none";
            })), this.workSheetInstances.has(sheetKey)) {
                const instance = this.workSheetInstances.get(sheetKey);
                instance.getElement().style.display = "block", this.activeWorkSheet = instance, 
                this.formulaManager.setActiveSheet(sheetKey), this._activeSheetTab(), this.sheetTabEventHandler.activeSheetMenuItem(), 
                this.restoreFilterState(instance, sheetDefine);
            } else {
                const instance = this.createWorkSheetInstance(sheetDefine);
                this.workSheetInstances.set(sheetKey, instance), this.activeWorkSheet = instance, 
                this.formulaManager.setActiveSheet(sheetKey), this.updateSheetTabs(), this.updateSheetMenu(), 
                this.restoreFilterState(instance, sheetDefine);
            }
            this.updateFormulaBar();
        }
    }
    addSheet(sheet) {
        this.sheetManager.addSheet(sheet), this.updateSheetTabs(), this.updateSheetMenu();
    }
    removeSheet(sheetKey) {
        if (this.sheetManager.getSheetCount() <= 1) return void showSnackbar("至少保留一个工作表", 1300);
        const instance = this.workSheetInstances.get(sheetKey);
        instance && (instance.getElement().remove(), this.workSheetInstances.delete(sheetKey));
        const newActiveSheetKey = this.sheetManager.removeSheet(sheetKey);
        newActiveSheetKey && this.activateSheet(newActiveSheetKey), this.updateSheetTabs(), 
        this.updateSheetMenu();
    }
    getSheetCount() {
        return this.sheetManager.getSheetCount();
    }
    getSheet(sheetKey) {
        return this.sheetManager.getSheet(sheetKey);
    }
    getAllSheets() {
        return this.sheetManager.getAllSheets();
    }
    createWorkSheetInstance(sheetDefine) {
        var _a, _b, _c;
        formulaEditor.setSheet(this);
        const contentWidth = this.contentElement.clientWidth, contentHeight = this.contentElement.clientHeight;
        sheetDefine.dragOrder = null !== (_a = sheetDefine.dragOrder) && void 0 !== _a ? _a : this.options.dragOrder;
        const sheet = new WorkSheet(this, Object.assign(Object.assign({}, sheetDefine), {
            container: this.contentElement,
            width: contentWidth,
            height: contentHeight,
            defaultRowHeight: this.options.defaultRowHeight,
            defaultColWidth: this.options.defaultColWidth,
            dragOrder: sheetDefine.dragOrder,
            plugins: getTablePlugins(sheetDefine, this.options, this),
            headerEditor: "formula",
            editor: "formula",
            select: {
                makeSelectCellVisible: !1
            },
            style: {
                borderColor: [ "#E1E4E8", "#E1E4E8", "#E1E4E8", "#E1E4E8" ],
                borderLineWidth: [ 1, 1, 1, 1 ],
                borderLineDash: [ null, null, null, null ],
                padding: [ 8, 8, 8, 8 ]
            },
            editCellTrigger: [ "api", "keydown", "doubleclick" ],
            customMergeCell: sheetDefine.cellMerge,
            theme: (null === (_b = sheetDefine.theme) || void 0 === _b ? void 0 : _b.tableTheme) || (null === (_c = this.options.theme) || void 0 === _c ? void 0 : _c.tableTheme)
        }));
        sheet.on(WorkSheetEventType.CELL_CLICK, this.eventManager.handleCellClickBind), 
        sheet.on(WorkSheetEventType.CELL_VALUE_CHANGED, this.eventManager.handleCellValueChangedBind), 
        sheet.on(WorkSheetEventType.SELECTION_CHANGED, this.eventManager.handleSelectionChangedForRangeModeBind), 
        sheet.on(WorkSheetEventType.SELECTION_END, this.eventManager.handleSelectionChangedForRangeModeBind);
        try {
            const normalizedData = this.formulaManager.normalizeSheetData(sheetDefine.data, sheet.tableInstance);
            this.formulaManager.addSheet(sheetDefine.sheetKey, normalizedData), sheetDefine.formulas && Object.keys(sheetDefine.formulas).length > 0 && this.loadFormulas(sheetDefine.sheetKey, sheetDefine.formulas);
        } catch (error) {}
        return sheet;
    }
    loadFormulas(sheetKey, formulas) {
        if (formulas && 0 !== Object.keys(formulas).length) try {
            const sortedFormulas = this.formulaManager.sortFormulasByDependency(sheetKey, formulas);
            for (const [cellRef, formula] of sortedFormulas) {
                const {row: row, col: col} = this.parseCellKey(cellRef);
                this.formulaManager.setCellContent({
                    sheet: sheetKey,
                    row: row,
                    col: col
                }, formula);
            }
            this.formulaManager.rebuildAndRecalculate();
        } catch (error) {}
    }
    parseCellKey(cellKey) {
        const match = cellKey.match(/^([A-Za-z]+)(\d+)$/);
        if (!match) throw new Error(`Invalid cell reference: ${cellKey}`);
        const [, colStr, rowStr] = match, row = parseInt(rowStr, 10) - 1;
        let col = 0;
        for (let i = 0; i < colStr.length; i++) {
            col = 26 * col + (colStr.toUpperCase().charCodeAt(i) - 65);
        }
        return {
            row: row,
            col: col
        };
    }
    restoreFilterState(sheet, sheetDefine) {
        sheetDefine.filterState && setTimeout((() => {
            if (sheet.tableInstance && sheet.tableInstance.pluginManager) {
                const filterPlugin = sheet.tableInstance.pluginManager.getPluginByName("Filter");
                filterPlugin && filterPlugin.setFilterState(sheetDefine.filterState);
            }
        }), 0);
    }
    _addNewSheet() {
        const sheetCount = this.sheetManager.getSheetCount();
        let key = `sheet${sheetCount + 1}`, title = `Sheet ${sheetCount + 1}`, index = sheetCount + 1;
        const existingKeys = new Set(this.sheetManager.getAllSheets().map((s => s.sheetKey))), existingTitles = new Set(this.sheetManager.getAllSheets().map((s => s.sheetTitle)));
        for (;existingKeys.has(key) || existingTitles.has(title); ) index += 1, key = `sheet${index}`, 
        title = `Sheet ${index}`;
        const newSheet = {
            sheetKey: key,
            sheetTitle: title,
            columnCount: 20,
            rowCount: 100,
            data: []
        };
        this.sheetManager.addSheet(newSheet), this.activateSheet(key);
    }
    updateFormulaBar() {
        this.formulaUIManager.updateFormulaBar();
    }
    getFormulaManager() {
        return this.formulaManager;
    }
    getSheetManager() {
        return this.sheetManager;
    }
    getActiveSheet() {
        return this.activeWorkSheet;
    }
    saveToConfig() {
        const sheets = [];
        return this.sheetManager.getAllSheets().forEach((sheetDefine => {
            const instance = this.workSheetInstances.get(sheetDefine.sheetKey);
            if (instance) {
                const data = instance.getCopiedData(), columns = instance.getColumns().map((column => {
                    const rest = __rest(column, []);
                    return delete rest.field, rest;
                })), lastTitleIndex = columns.reduce(((lastIndex, column, index) => column.title ? index : lastIndex), -1);
                -1 === lastTitleIndex ? columns.length = 0 : columns.splice(lastTitleIndex + 1);
                const lastDataIndex = data.reduce(((lastIndex, rowData, index) => rowData ? index : lastIndex), -1);
                -1 === lastDataIndex ? data.length = 0 : data.splice(lastDataIndex + 1);
                let filterState = null;
                const filterPlugin = instance.tableInstance.pluginManager.getPluginByName("Filter");
                filterPlugin && (filterState = filterPlugin.getFilterState());
                let currentSortState, sortState = instance.tableInstance.internalProps.sortState;
                sortState && (sortState = Array.isArray(sortState) ? sortState : [ sortState ], 
                currentSortState = sortState.map((item => Object.assign({
                    field: item.field,
                    order: item.order
                }, null != item.orderFn && {
                    orderFn: item.orderFn
                }))));
                const formulas = this.formulaManager.exportFormulas(sheetDefine.sheetKey), columnWidthConfig = Array.from(instance.tableInstance.internalProps._widthResizedColMap).map((key => ({
                    key: key,
                    width: instance.tableInstance.getColWidth(key)
                }))), rowHeightConfig = Array.from(instance.tableInstance.internalProps._heightResizedRowMap).map((key => ({
                    key: key,
                    height: instance.tableInstance.getRowHeight(key)
                })));
                sheets.push(Object.assign(Object.assign({}, sheetDefine), {
                    data: data,
                    columns: columns,
                    cellMerge: instance.tableInstance.options.customMergeCell,
                    showHeader: instance.tableInstance.options.showHeader,
                    frozenRowCount: instance.tableInstance.frozenRowCount,
                    frozenColCount: instance.tableInstance.frozenColCount,
                    active: sheetDefine.sheetKey === this.sheetManager.getActiveSheet().sheetKey,
                    filterState: filterState,
                    sortState: currentSortState,
                    formulas: Object.keys(formulas).length > 0 ? formulas : void 0,
                    columnWidthConfig: columnWidthConfig,
                    rowHeightConfig: rowHeightConfig
                }));
            } else sheets.push(sheetDefine);
        })), Object.assign(Object.assign({}, this.options), {
            sheets: sheets
        });
    }
    exportSheetToFile(fileType) {
        var _a, _b;
        const sheet = this.getActiveSheet();
        sheet && ("csv" === fileType ? (null === (_a = sheet.tableInstance) || void 0 === _a ? void 0 : _a.exportToCsv) && sheet.tableInstance.exportToCsv() : (null === (_b = sheet.tableInstance) || void 0 === _b ? void 0 : _b.exportToExcel) && sheet.tableInstance.exportToExcel());
    }
    importFileToSheet() {
        var _a;
        return __awaiter(this, void 0, void 0, (function*() {
            const sheet = this.getActiveSheet();
            if (sheet) return (null === (_a = sheet.tableInstance) || void 0 === _a ? void 0 : _a.importFile) ? yield sheet.tableInstance.importFile() : void 0;
        }));
    }
    getContainer() {
        return this.container;
    }
    getRootElement() {
        return this.rootElement;
    }
    getOptions() {
        return this.options;
    }
    getFormulaBarElement() {
        return this.formulaBarElement;
    }
    getSheetTabElement() {
        return this.sheetTabElement;
    }
    getContentElement() {
        return this.contentElement;
    }
    release() {
        this.eventManager.release(), this.formulaManager.release(), this.formulaUIManager.release(), 
        this.sheetTabEventHandler.removeClickOutsideListener(), this.workSheetInstances.forEach((instance => {
            instance.release();
        })), this.rootElement && this.rootElement.parentNode && this.rootElement.parentNode.removeChild(this.rootElement), 
        this.formulaAutocomplete && this.formulaAutocomplete.release(), this.formulaManager.cellHighlightManager && this.formulaManager.cellHighlightManager.release();
    }
    exportData(sheetKey) {
        const sheet = this.workSheetInstances.get(sheetKey);
        return sheet ? sheet.getData() : [];
    }
    exportAllData() {
        return Array.from(this.workSheetInstances.values()).map((sheet => sheet.getData()));
    }
    resize() {
        var _a;
        null === (_a = this.getActiveSheet()) || void 0 === _a || _a.resize();
    }
    excludeEditCellFromSelection(range, editRow, editCol) {
        const r = Object.assign({}, range), withinRow = r.startRow <= editRow && editRow <= r.endRow, withinCol = r.startCol <= editCol && editCol <= r.endCol;
        if (!withinRow || !withinCol) return r;
        const rowSpan = r.endRow - r.startRow, colSpan = r.endCol - r.startCol;
        return 0 === rowSpan && 0 === colSpan && r.startRow === editRow && r.startCol === editCol ? {
            startRow: -1,
            startCol: -1,
            endRow: -1,
            endCol: -1
        } : (rowSpan >= colSpan ? editRow === r.startRow && r.startRow < r.endRow ? r.startRow += 1 : editRow === r.endRow && r.startRow < r.endRow ? r.endRow -= 1 : r.startRow < r.endRow && (r.startRow += 1) : editCol === r.startCol && r.startCol < r.endCol ? r.startCol += 1 : editCol === r.endCol && r.startCol < r.endCol ? r.endCol -= 1 : r.startCol < r.endCol && (r.startCol += 1), 
        r);
    }
}
//# sourceMappingURL=vtable-sheet.js.map