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());
    }));
};

import ExcelJS from "exceljs";

import { encodeCellAddress } from "../util/encode";

import { getCellAlignment, getCellBorder, getCellFill, getCellFont } from "./style";

import { updateCell, renderChart, graphicUtil } from "@visactor/vtable";

import { isArray, isFunction } from "@visactor/vutils";

import { getHierarchyOffset } from "../util/indent";

import { isPromise } from "../util/promise";

import { handlePaginationExport } from "../util/pagination";

function requestIdleCallbackPromise(options) {
    return new Promise((resolve => {
        requestIdleCallback((deadline => {
            resolve(deadline);
        }), options);
    }));
}

export function exportVTableToExcel(tableInstance, options, optimization = !1) {
    return __awaiter(this, void 0, void 0, (function*() {
        const workbook = new ExcelJS.Workbook, worksheet = workbook.addWorksheet("sheet1"), exportAllData = !!(null == options ? void 0 : options.exportAllData), {handleRowCount: handleRowCount, reset: reset} = handlePaginationExport(tableInstance, exportAllData), maxRow = handleRowCount(), maxCol = tableInstance.colCount - 1;
        worksheet.properties.defaultRowHeight = 40;
        const columns = [], mergeCells = [], mergeCellSet = new Set;
        let currentRow = 0;
        function processSlice(deadline) {
            return new Promise((resolve => __awaiter(this, void 0, void 0, (function*() {
                for (;currentRow <= maxRow && (!optimization || (null == deadline ? void 0 : deadline.timeRemaining()) > 0); ) {
                    const endRow = Math.min(currentRow + 100 - 1, maxRow);
                    for (let col = 0; col <= maxCol; col++) {
                        const colWidth = tableInstance.getColWidth(col);
                        void 0 === columns[col] && (columns[col] = {
                            width: colWidth / 6
                        });
                        for (let row = currentRow; row <= endRow; row++) {
                            if (0 === col) {
                                const rowHeight = tableInstance.getRowHeight(row);
                                worksheet.getRow(row + 1).height = rowHeight;
                            }
                            yield addCell(col, row, tableInstance, worksheet, workbook, options);
                            const cellRange = tableInstance.getCellRange(col, row);
                            if (cellRange.start.col !== cellRange.end.col || cellRange.start.row !== cellRange.end.row) {
                                const key = `${cellRange.start.col},${cellRange.start.row}:${cellRange.end.col},${cellRange.end.row}`;
                                mergeCellSet.has(key) || (mergeCellSet.add(key), mergeCells.push(cellRange));
                            }
                        }
                    }
                    currentRow = endRow + 1;
                }
                if (currentRow > maxRow) resolve(); else {
                    let nextDeadline;
                    optimization && (nextDeadline = yield requestIdleCallbackPromise()), yield processSlice(nextDeadline), 
                    resolve();
                }
            }))));
        }
        yield new Promise((resolve => __awaiter(this, void 0, void 0, (function*() {
            let deadline;
            optimization && (deadline = yield requestIdleCallbackPromise()), yield processSlice(deadline), 
            resolve();
        })))), worksheet.columns = columns, mergeCells.forEach((mergeCell => {
            worksheet.mergeCells(mergeCell.start.row + 1, mergeCell.start.col + 1, mergeCell.end.row + 1, mergeCell.end.col + 1);
        }));
        const frozenView = [];
        tableInstance.frozenRowCount > 0 && frozenView.push({
            state: "frozen",
            ySplit: tableInstance.frozenRowCount,
            topLeftCell: encodeCellAddress(0, tableInstance.frozenRowCount)
        }), tableInstance.frozenColCount > 0 && frozenView.push({
            state: "frozen",
            xSplit: tableInstance.frozenColCount,
            topLeftCell: encodeCellAddress(tableInstance.frozenColCount, 0)
        }), worksheet.views = frozenView, (null == options ? void 0 : options.excelJSWorksheetCallback) && options.excelJSWorksheetCallback(worksheet);
        const buffer = yield workbook.xlsx.writeBuffer();
        return reset(), buffer;
    }));
}

function addCell(col, row, tableInstance, worksheet, workbook, options) {
    var _a;
    return __awaiter(this, void 0, void 0, (function*() {
        const {layoutMap: layoutMap} = tableInstance.internalProps, cellType = tableInstance.getCellType(col, row), rawRecord = tableInstance.getCellRawRecord(col, row);
        let cellValue = null !== (_a = rawRecord && rawRecord.vtableMergeName) && void 0 !== _a ? _a : tableInstance.getCellValue(col, row, !1);
        isPromise(cellValue) && (cellValue = yield cellValue);
        const cellStyle = tableInstance.getCellStyle(col, row), cellLocation = tableInstance.getCellLocation(col, row), define = "body" !== cellLocation ? tableInstance.getHeaderDefine(col, row) : tableInstance.getBodyColumnDefine(col, row);
        let icons, customRender, customLayout, cell;
        if (("body" !== cellLocation || ((null == define ? void 0 : define.dragOrder) || !!(null == define ? void 0 : define.icon) || !!(null == define ? void 0 : define.tree))) && (icons = tableInstance.getCellIcons(col, row)), 
        "body" !== cellLocation ? (customRender = null == define ? void 0 : define.headerCustomRender, 
        customLayout = null == define ? void 0 : define.headerCustomLayout) : (customRender = (null == define ? void 0 : define.customRender) || tableInstance.customRender, 
        customLayout = null == define ? void 0 : define.customLayout), null == options ? void 0 : options.formatExportOutput) {
            const cellInfo = {
                cellType: cellType,
                cellValue: cellValue,
                table: tableInstance,
                col: col,
                row: row
            }, formattedValue = options.formatExportOutput(cellInfo);
            if (void 0 !== formattedValue) {
                let cell = worksheet.getCell(encodeCellAddress(col, row));
                cell.value = formattedValue, cell.font = getCellFont(cellStyle, cellType), cell.fill = getCellFill(cellStyle), 
                cell.border = getCellBorder(cellStyle);
                const offset = getHierarchyOffset(col, row, tableInstance);
                if (cell.alignment = getCellAlignment(cellStyle, Math.ceil(offset / cell.font.size)), 
                cell && (null == options ? void 0 : options.formatExcelJSCell)) {
                    const formatedCell = options.formatExcelJSCell({
                        cellType: cellType,
                        cellValue: cellValue,
                        table: tableInstance,
                        col: col,
                        row: row
                    }, cell);
                    formatedCell && (cell = formatedCell);
                }
                return cell;
            }
        }
        if ("image" === cellType || "video" === cellType || "progressbar" === cellType || "sparkline" === cellType || layoutMap.isAxisCell(col, row) || !(null == options ? void 0 : options.ignoreIcon) && isArray(icons) && icons.length || customRender || customLayout) if (needCellImageExport(cellType, layoutMap.isAxisCell(col, row), !!customRender || !!customLayout, !((null == options ? void 0 : options.ignoreIcon) || !isArray(icons) || !icons.length), options)) {
            const cellImageBase64 = exportCellImg(col, row, tableInstance), imageId = workbook.addImage({
                base64: cellImageBase64,
                extension: "png"
            });
            worksheet.addImage(imageId, {
                tl: {
                    col: col + 1 / 80,
                    row: row + 1 / 120
                },
                br: {
                    col: col + 1,
                    row: row + 1
                },
                editAs: "oneCell"
            });
        } else cell = worksheet.getCell(encodeCellAddress(col, row)); else if ("text" === cellType || "link" === cellType) {
            let linkUrl;
            if (cell = worksheet.getCell(encodeCellAddress(col, row)), "link" === cellType) {
                const templateLink = define.templateLink;
                if (templateLink) {
                    const rowData = tableInstance.getCellOriginRecord(col, row);
                    if (rowData && rowData.vtableMerge) ; else {
                        const cellOriginValue = tableInstance.getCellOriginValue(col, row), data = Object.assign({
                            __value: cellValue,
                            __dataValue: cellOriginValue
                        }, rowData);
                        if (isFunction(templateLink)) linkUrl = templateLink(data, col, row, tableInstance); else {
                            const re = /\{\s*(\S+?)\s*\}/g;
                            linkUrl = templateLink.replace(re, ((matchs, key) => data[key]));
                        }
                    }
                }
            }
            cell.value = getCellValue(cellValue, cellType, linkUrl), cell.font = getCellFont(cellStyle, cellType), 
            cell.fill = getCellFill(cellStyle), cell.border = getCellBorder(cellStyle);
            const offset = getHierarchyOffset(col, row, tableInstance);
            cell.alignment = getCellAlignment(cellStyle, Math.ceil(offset / cell.font.size));
        } else if ("chart" === cellType) if (needCellImageExport("chart", !1, !1, !1, options)) {
            const cellGroup = tableInstance.scenegraph.getCell(col, row);
            renderChart(cellGroup.firstChild);
            const cellImageBase64 = exportCellImg(col, row, tableInstance), imageId = workbook.addImage({
                base64: cellImageBase64,
                extension: "png"
            });
            worksheet.addImage(imageId, {
                tl: {
                    col: col + 1 / 80,
                    row: row + 1 / 120
                },
                br: {
                    col: col + 1,
                    row: row + 1
                },
                editAs: "oneCell"
            }), tableInstance.scenegraph.updateNextFrame();
        } else cell = worksheet.getCell(encodeCellAddress(col, row));
        if (cell && (null == options ? void 0 : options.formatExcelJSCell)) {
            const formatedCell = options.formatExcelJSCell({
                cellType: cellType,
                cellValue: cellValue,
                table: tableInstance,
                col: col,
                row: row
            }, cell);
            formatedCell && (cell = formatedCell);
        }
        return cell;
    }));
}

function getCellValue(cellValue, cellType, linkUrl) {
    return "link" === cellType ? {
        text: cellValue,
        hyperlink: linkUrl || cellValue,
        tooltip: cellValue
    } : cellValue;
}

function exportCellImg(col, row, tableInstance) {
    var _a;
    let cellGroup = tableInstance.scenegraph.getCell(col, row), needRemove = !1;
    "empty" === cellGroup.role && (cellGroup = updateCell(col, row, tableInstance, !0), 
    cellGroup.setStage(tableInstance.scenegraph.stage), needRemove = !0, cellGroup.stage.dirtyBounds.set(-1 / 0, -1 / 0, 1 / 0, 1 / 0));
    const oldStroke = cellGroup.attribute.stroke;
    cellGroup.attribute.stroke = !1;
    const canvas = graphicUtil.drawGraphicToCanvas(cellGroup, tableInstance.scenegraph.stage);
    return cellGroup.attribute.stroke = oldStroke, needRemove && (null === (_a = cellGroup.parent) || void 0 === _a || _a.removeChild(cellGroup)), 
    canvas.toDataURL();
}

function needCellImageExport(cellType, isAxisCell, isCustomCell, isTextWithIcon, options) {
    return !(null == options ? void 0 : options.skipImageExportCellType) || ("image" === cellType || "video" === cellType || "progressbar" === cellType || "sparkline" === cellType || "chart" === cellType ? !options.skipImageExportCellType.includes(cellType) : isAxisCell ? !options.skipImageExportCellType.includes("chart") : isCustomCell ? !options.skipImageExportCellType.includes("custom") : !isTextWithIcon || !options.skipImageExportCellType.includes("textWithIcon"));
}
//# sourceMappingURL=index.js.map
