import { isValid } from "@visactor/vutils";

export class NumberRangeMap {
    constructor(table) {
        this.isUpdate = !1, this._keys = [], this._sorted = !1, this.data = new Map, this._keys.length = 0, 
        this.cumulativeSum = new Map, this.difference = new Map, this.totalSum = 0, this.table = table;
    }
    get length() {
        return this.data.size;
    }
    clear() {
        this._keys = [], this.data.clear(), this.cumulativeSum.clear(), this.difference.clear(), 
        this.totalSum = 0;
    }
    clearRange() {
        this.cumulativeSum.clear(), this.difference.clear();
    }
    add(position, value) {
        if (!isValid(value)) return;
        const defaultValue = this.table.getRowHeight(position);
        this.data.has(position) || (this._keys.push(position), this._sorted = !1), this.data.set(position, value), 
        this.totalSum += value, this.updateDifference(position, value - defaultValue);
    }
    remove(position) {
        if (this.data.has(position)) {
            const value = this.data.get(position);
            this.data.delete(position);
            const index = this._keys.indexOf(position);
            -1 !== index && this._keys.splice(index, 1), this.totalSum -= value;
            const defaultValue = this.table.getRowHeight(position);
            this.updateDifference(position, defaultValue - value);
        }
    }
    put(position, newValue) {
        if (isValid(newValue)) if (this.data.has(position)) {
            const oldValue = this.data.get(position);
            if (oldValue === newValue) return;
            this.data.set(position, newValue);
            const difference = newValue - oldValue;
            this.totalSum += difference, this.updateDifference(position, difference);
        } else this.add(position, newValue);
    }
    get(position) {
        return this.data.get(position);
    }
    has(position) {
        return this.data.has(position);
    }
    _sort() {
        const {_keys: keys} = this;
        this._sorted || (keys.sort(((a, b) => a < b ? -1 : a > b ? 1 : 0)), this._sorted = !0);
    }
    updateDifference(position, difference) {
        var _a;
        const oldDifference = null !== (_a = this.difference.get(position)) && void 0 !== _a ? _a : 0;
        this.difference.set(position, oldDifference + difference), this.update();
    }
    getSumInRange(start, end) {
        return this.calculatePrefixSum(end) - this.calculatePrefixSum(start - 1);
    }
    updateCumulativeSum(position, difference) {
        for (const [pos, sum] of this.cumulativeSum) pos >= position && this.cumulativeSum.set(pos, sum + difference);
    }
    calculatePrefixSum(position) {
        if (position < 0) return 0;
        if (this.cumulativeSum.has(position)) {
            let cache = this.cumulativeSum.get(position);
            for (const [pos, difference] of this.difference) pos <= position && (cache += difference);
            return cache;
        }
        return this.dealDiffenence(), this.getCumulativeSum(position);
    }
    getCumulativeSum(position) {
        var _a, _b;
        let sum = 0, currentBottomFrozenRowsHeight = 0, isBottomFrozenRowNoCache = !1;
        const bottomFrozenStartRow = this.table.rowCount > 0 && this.table.bottomFrozenRowCount > 0 ? this.table.rowCount - this.table.bottomFrozenRowCount : -1;
        for (let i = position; i >= 0; i--) {
            if (this.cumulativeSum.has(i)) {
                sum += this.cumulativeSum.get(i);
                break;
            }
            sum += null !== (_a = this.data.get(i)) && void 0 !== _a ? _a : this.table.getRowHeight(i), 
            i >= bottomFrozenStartRow && -1 !== bottomFrozenStartRow && (currentBottomFrozenRowsHeight = sum, 
            isBottomFrozenRowNoCache = i === bottomFrozenStartRow);
        }
        if (isBottomFrozenRowNoCache && (null === (_b = this.table.containerFit) || void 0 === _b ? void 0 : _b.height) && this.table.bottomFrozenRowCount) {
            const tableHeight = this.table.tableNoFrameHeight || 0;
            sum < tableHeight && (sum = tableHeight - this.table.getBottomFrozenRowsHeight() + currentBottomFrozenRowsHeight);
        }
        return this.cumulativeSum.set(position, sum), sum;
    }
    update() {
        this.isUpdate || (this.isUpdate = !0, setTimeout((() => {
            this.dealDiffenence(), this.isUpdate = !1;
        }), 0));
    }
    dealDiffenence() {
        for (const [sumPos] of this.cumulativeSum) for (const [difPos, difference] of this.difference) if (sumPos >= difPos) {
            const oldSum = this.cumulativeSum.get(sumPos);
            this.cumulativeSum.set(sumPos, oldSum + difference);
        }
        this.difference.clear();
    }
    insert(position, value) {
        for (let i = position; i <= this.getLastIndex(); i++) this.cumulativeSum.delete(i);
        const lastIndex = this.getLastIndex() + 1;
        this.adjustOrder(position, position + 1, lastIndex - position), isValid(value) && this.put(position, value);
    }
    getLastIndex() {
        return this._sort(), this._keys[this._keys.length - 1];
    }
    delLast() {
        const lastIndex = this.getLastIndex();
        this.remove(lastIndex);
    }
    delete(position) {
        if (!this.has(position)) return;
        for (let i = position; i <= this.getLastIndex(); i++) this.cumulativeSum.delete(i);
        const lastIndex = this.getLastIndex();
        this.adjustOrder(position + 1, position, lastIndex - position), this.delLast();
    }
    adjustOrder(sourceIndex, targetIndex, moveCount) {
        this.clearRange(), this._sort();
        const {_keys: keys} = this;
        if (sourceIndex > targetIndex) {
            const sourceVals = [];
            for (let i = indexFirst(keys, sourceIndex + moveCount - 1); i >= 0; i--) {
                const key = keys[i];
                if (key >= sourceIndex) sourceVals.push(this.get(key)); else if (targetIndex <= key && key < sourceIndex) this.put(key + moveCount, this.get(key)); else if (key < targetIndex) break;
            }
            for (let i = 0; i < moveCount; i++) this.put(targetIndex + i, sourceVals[moveCount - 1 - i]);
        }
        const {length: length} = keys;
        if (sourceIndex < targetIndex) {
            const sourceVals = [];
            for (let i = indexFirst(keys, sourceIndex); i < length; i++) {
                const key = keys[i];
                if (key >= sourceIndex && key < sourceIndex + moveCount) sourceVals.push(this.get(key)); else if (sourceIndex + moveCount <= key && key <= targetIndex) this.put(key - moveCount, this.get(key)); else if (key > targetIndex) break;
            }
            for (let i = 0; i < moveCount; i++) this.put(targetIndex + i, sourceVals[i]);
        }
    }
    exchangeOrder(sourceIndex, sourceCount, targetIndex, targetCount, insertIndex) {
        const {_keys: keys} = this;
        if (this._sorted || (keys.sort(((a, b) => a < b ? -1 : a > b ? 1 : 0)), this._sorted = !0), 
        sourceIndex > targetIndex) {
            const targetVals = [], sourceVals = [];
            for (let i = indexFirst(keys, targetIndex); i < indexFirst(keys, sourceIndex) + sourceCount; i++) {
                const key = keys[i];
                key >= sourceIndex && key < sourceIndex + sourceCount ? sourceVals.push(this.get(key)) : targetVals.push(this.get(key));
            }
            for (let i = 0; i < sourceCount; i++) this.put(insertIndex + i, sourceVals[i]);
            for (let i = 0; i < targetVals.length; i++) this.put(insertIndex + sourceCount + i, targetVals[i]);
        } else {
            const targetVals = [], sourceVals = [];
            for (let i = indexFirst(keys, sourceIndex); i < indexFirst(keys, targetIndex) + targetCount; i++) {
                const key = keys[i];
                key >= sourceIndex && key < sourceIndex + sourceCount ? sourceVals.push(this.get(key)) : targetVals.push(this.get(key));
            }
            for (let i = 0; i < sourceCount; i++) this.put(insertIndex + i, sourceVals[i]);
            for (let i = 0; i < targetVals.length; i++) this.put(sourceIndex + i, targetVals[i]);
        }
    }
}

function indexFirst(arr, elm) {
    let low = 0, high = arr.length - 1;
    for (;low <= high; ) {
        const i = Math.floor((low + high) / 2);
        if (arr[i] === elm) return i;
        arr[i] > elm ? high = i - 1 : low = i + 1;
    }
    return high < 0 ? 0 : high;
}
//# sourceMappingURL=row-height-map.js.map