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

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

import { Factory } from "../core/factory";

export class CustomCellStylePlugin {
    constructor(table, customCellStyle, customCellStyleArrangement) {
        this.table = table, this.customCellStyle = customCellStyle, this.customCellStyleArrangement = customCellStyleArrangement, 
        this._customCellStyleArrangementIndex = new Map, this._customCellStyleArrangementTombstoneCount = 0, 
        this._rebuildCustomCellStyleArrangementIndex();
    }
    _getCustomCellStyleArrangementKey(cellPos) {
        if (cellPos.range) {
            const {start: start, end: end} = cellPos.range;
            return `range:${start.col},${start.row},${end.col},${end.row}`;
        }
        if (void 0 !== cellPos.col && void 0 !== cellPos.row) return `cell:${cellPos.col},${cellPos.row}`;
    }
    _rebuildCustomCellStyleArrangementIndex() {
        this._customCellStyleArrangementIndex.clear(), this._customCellStyleArrangementTombstoneCount = 0;
        for (let i = 0; i < this.customCellStyleArrangement.length; i++) {
            if (!isValid(this.customCellStyleArrangement[i].customStyleId)) {
                this._customCellStyleArrangementTombstoneCount++;
                continue;
            }
            const key = this._getCustomCellStyleArrangementKey(this.customCellStyleArrangement[i].cellPosition);
            key && this._customCellStyleArrangementIndex.set(key, i);
        }
    }
    _compactCustomCellStyleArrangementIfNeeded() {
        const length = this.customCellStyleArrangement.length;
        if (this._customCellStyleArrangementTombstoneCount < 2048) return;
        if (4 * this._customCellStyleArrangementTombstoneCount < length) return;
        const compacted = this.customCellStyleArrangement.filter((style => isValid(style.customStyleId)));
        compacted.length !== this.customCellStyleArrangement.length ? (this.customCellStyleArrangement.length = 0, 
        this.customCellStyleArrangement.push(...compacted), this._rebuildCustomCellStyleArrangementIndex()) : this._customCellStyleArrangementTombstoneCount = 0;
    }
    getCustomCellStyle(col, row) {
        const customStyleIds = this.getCustomCellStyleIds(col, row);
        if (customStyleIds.length) {
            const styles = [];
            if (customStyleIds.forEach((customStyleId => {
                const styleOption = this.getCustomCellStyleOption(customStyleId);
                if (isFunction(null == styleOption ? void 0 : styleOption.style)) {
                    const style = styleOption.style({
                        col: col,
                        row: row,
                        table: this.table,
                        value: this.table.getCellValue(col, row),
                        dataValue: this.table.getCellOriginValue(col, row),
                        cellHeaderPaths: this.table.getCellHeaderPaths(col, row)
                    });
                    styles.push(style);
                } else (null == styleOption ? void 0 : styleOption.style) && styles.push(styleOption.style);
            })), !styles.length) return;
            return merge({}, ...styles);
        }
    }
    getCustomCellStyleIds(col, row) {
        const customStyleIds = [], range = this.table.getCellRange(col, row);
        for (let c = range.start.col; c <= range.end.col; c++) for (let r = range.start.row; r <= range.end.row; r++) this.customCellStyleArrangement.forEach((style => {
            isValid(style.customStyleId) && (style.cellPosition.range ? style.cellPosition.range.start.col <= c && style.cellPosition.range.end.col >= c && style.cellPosition.range.start.row <= r && style.cellPosition.range.end.row >= r && customStyleIds.push(style.customStyleId) : style.cellPosition.col === c && style.cellPosition.row === r && customStyleIds.push(style.customStyleId));
        }));
        return customStyleIds;
    }
    getCustomCellStyleOption(customStyleId) {
        return this.customCellStyle.find((style => style.id === customStyleId));
    }
    registerCustomCellStyle(customStyleId, customStyle) {
        const index = this.customCellStyle.findIndex((style => style.id === customStyleId));
        -1 === index ? this.customCellStyle.push({
            id: customStyleId,
            style: customStyle
        }) : this.customCellStyle[index] = {
            id: customStyleId,
            style: customStyle
        }, this.customCellStyleArrangement.forEach((cellStyle => {
            const cellPos = cellStyle.cellPosition;
            if (cellStyle.customStyleId === customStyleId) if (cellPos.range) for (let col = Math.max(0, cellPos.range.start.col); col <= Math.min(this.table.colCount - 1, cellPos.range.end.col); col++) for (let row = Math.max(0, cellPos.range.start.row); row <= Math.min(this.table.rowCount - 1, cellPos.range.end.row); row++) this.table.scenegraph.updateCellContent(col, row); else this.table.scenegraph.updateCellContent(cellPos.col, cellPos.row);
        })), this.table.scenegraph.updateNextFrame();
    }
    arrangeCustomCellStyle(cellPos, customStyleId, forceFastUpdate) {
        var _a, _b;
        const inputKey = this._getCustomCellStyleArrangementKey(cellPos);
        let index = inputKey && null !== (_a = this._customCellStyleArrangementIndex.get(inputKey)) && void 0 !== _a ? _a : -1;
        if (inputKey && -1 !== index) {
            const item = this.customCellStyleArrangement[index], itemKey = item ? this._getCustomCellStyleArrangementKey(item.cellPosition) : void 0;
            item && isValid(item.customStyleId) && itemKey === inputKey || (index = this.customCellStyleArrangement.findIndex((style => !!isValid(style.customStyleId) && this._getCustomCellStyleArrangementKey(style.cellPosition) === inputKey)), 
            -1 !== index ? this._customCellStyleArrangementIndex.set(inputKey, index) : this._customCellStyleArrangementIndex.delete(inputKey));
        }
        if (-1 !== index || inputKey || (index = this.customCellStyleArrangement.findIndex((style => !!isValid(style.customStyleId) && (style.cellPosition.range && cellPos.range ? style.cellPosition.range.start.col === cellPos.range.start.col && style.cellPosition.range.start.row === cellPos.range.start.row && style.cellPosition.range.end.col === cellPos.range.end.col && style.cellPosition.range.end.row === cellPos.range.end.row : style.cellPosition.col === cellPos.col && style.cellPosition.row === cellPos.row)))), 
        -1 === index && !customStyleId) return;
        if (-1 === index && customStyleId) {
            this.customCellStyleArrangement.push({
                cellPosition: {
                    col: cellPos.col,
                    row: cellPos.row,
                    range: cellPos.range
                },
                customStyleId: customStyleId
            });
            const pushedIndex = this.customCellStyleArrangement.length - 1, pushedKey = this._getCustomCellStyleArrangementKey(this.customCellStyleArrangement[pushedIndex].cellPosition);
            pushedKey && this._customCellStyleArrangementIndex.set(pushedKey, pushedIndex);
        } else {
            if (this.customCellStyleArrangement[index].customStyleId === customStyleId) return;
            if (customStyleId) this.customCellStyleArrangement[index].customStyleId = customStyleId; else {
                const existedKey = this._getCustomCellStyleArrangementKey(this.customCellStyleArrangement[index].cellPosition);
                isValid(this.customCellStyleArrangement[index].customStyleId) && this._customCellStyleArrangementTombstoneCount++, 
                this.customCellStyleArrangement[index].customStyleId = null, existedKey && this._customCellStyleArrangementIndex.delete(existedKey), 
                this._compactCustomCellStyleArrangementIfNeeded();
            }
        }
        const style = customStyleId ? null === (_b = this.getCustomCellStyleOption(customStyleId)) || void 0 === _b ? void 0 : _b.style : void 0;
        if (style) {
            forceFastUpdate = !0;
            for (const key in style) if (-1 === cellStyleKeys.indexOf(key)) {
                forceFastUpdate = !1;
                break;
            }
        }
        if (cellPos.range) for (let col = Math.max(0, cellPos.range.start.col); col <= Math.min(this.table.colCount - 1, cellPos.range.end.col); col++) for (let row = Math.max(0, cellPos.range.start.row); row <= Math.min(this.table.rowCount - 1, cellPos.range.end.row); row++) {
            const range = this.table.getCellRange(col, row);
            for (let c = range.start.col; c <= range.end.col; c++) for (let r = range.start.row; r <= range.end.row; r++) this.table.scenegraph.updateCellContent(c, r, forceFastUpdate);
        } else this.table.scenegraph.updateCellContent(cellPos.col, cellPos.row, forceFastUpdate);
        this.table.scenegraph.updateNextFrame();
    }
    updateCustomCell(customCellStyle, customCellStyleArrangement) {
        this.customCellStyle.length = 0, this.customCellStyleArrangement.length = 0, this._customCellStyleArrangementIndex.clear(), 
        this._customCellStyleArrangementTombstoneCount = 0, customCellStyle.forEach((cellStyle => {
            this.registerCustomCellStyle(cellStyle.id, cellStyle.style);
        })), customCellStyleArrangement.forEach((cellStyle => {
            this.arrangeCustomCellStyle(cellStyle.cellPosition, cellStyle.customStyleId);
        }));
    }
    hasCustomCellStyle(customStyleId) {
        return this.customCellStyle.some((style => style.id === customStyleId));
    }
}

export function mergeStyle(cacheStyle, customCellStyle) {
    cacheStyle = cacheStyle.clone();
    for (const key in customCellStyle) {
        const value = customCellStyle[key];
        isValid(value) && (cacheStyle[`_${key}`] = value);
    }
    return cacheStyle;
}

export const registerCustomCellStylePlugin = () => {
    Factory.registerComponent("customCellStylePlugin", CustomCellStylePlugin);
};
//# sourceMappingURL=custom-cell-style.js.map