function indexedAxisIds(axisIds) {
    const offsets = new Map();
    for (let index = 0; index < axisIds.length; index += 1) {
        offsets.set(axisIds[index], index);
    }
    return offsets;
}
export class LogicalSheetStore {
    sheetId;
    axisMap;
    cellPages;
    cellIdentities;
    residentCells;
    denseRowMajorVisibleCellBlocks = [];
    constructor(sheetId, axisMap, cellPages, cellIdentities, residentCells) {
        this.sheetId = sheetId;
        this.axisMap = axisMap;
        this.cellPages = cellPages;
        this.cellIdentities = cellIdentities;
        this.residentCells = residentCells;
    }
    setSheetId(sheetId) {
        const previousSheetId = this.sheetId;
        this.sheetId = sheetId;
        this.cellIdentities.forEach((identity, cellIndex) => {
            if (identity.sheetId === previousSheetId) {
                this.cellIdentities.set(cellIndex, { ...identity, sheetId });
            }
        });
    }
    resolveVisibleAxis(axis, index) {
        return {
            index,
            id: this.axisMap.getId(axis, index),
        };
    }
    ensureVisibleAxis(axis, index, createId) {
        return {
            index,
            id: this.axisMap.ensureId(axis, index, createId),
        };
    }
    resolveVisibleLocation(row, col) {
        const rowId = this.axisMap.getId('row', row);
        const colId = this.axisMap.getId('column', col);
        if (rowId === undefined || colId === undefined) {
            return undefined;
        }
        return {
            sheetId: this.sheetId,
            rowId,
            colId,
        };
    }
    resolveVisibleCell(row, col) {
        return {
            sheetId: this.sheetId,
            row,
            col,
            rowRef: this.resolveVisibleAxis('row', row),
            colRef: this.resolveVisibleAxis('column', col),
        };
    }
    getVisibleCell(row, col) {
        const rowId = this.axisMap.getId('row', row);
        const colId = this.axisMap.getId('column', col);
        const denseCellIndex = rowId === undefined || colId === undefined ? undefined : this.getDenseRowMajorVisibleCell(rowId, colId);
        if (denseCellIndex !== undefined) {
            return denseCellIndex;
        }
        const location = rowId === undefined || colId === undefined
            ? undefined
            : {
                sheetId: this.sheetId,
                rowId,
                colId,
            };
        if (!location) {
            return undefined;
        }
        if (this.denseRowMajorVisibleCellBlocks.length > 0 && this.cellPages.hasDeferredRebuild()) {
            return this.cellPages.getDeferred(location);
        }
        return this.cellPages.get(location);
    }
    setVisibleCell(row, col, cellIndex, factories) {
        return this.setVisibleCellInternal(row, col, cellIndex, factories, false);
    }
    setNewVisibleCell(row, col, cellIndex, factories) {
        return this.setVisibleCellInternal(row, col, cellIndex, factories, true);
    }
    setNewVisibleCellWithAxisIds(row, col, cellIndex, rowId, colId) {
        const resolved = {
            sheetId: this.sheetId,
            row,
            col,
            rowRef: { index: row, id: rowId },
            colRef: { index: col, id: colId },
        };
        this.cellPages.set({
            sheetId: this.sheetId,
            rowId,
            colId,
        }, cellIndex);
        const identity = {
            sheetId: this.sheetId,
            rowId,
            colId,
        };
        this.cellIdentities.set(cellIndex, identity);
        this.residentCells.add(cellIndex, identity);
        return resolved;
    }
    setFreshVisibleCellWithAxisIdsDeferred(row, col, cellIndex, rowId, colId) {
        const resolved = {
            sheetId: this.sheetId,
            row,
            col,
            rowRef: { index: row, id: rowId },
            colRef: { index: col, id: colId },
        };
        this.cellPages.setDeferredParts(this.sheetId, rowId, colId, cellIndex);
        this.cellIdentities.setParts(cellIndex, this.sheetId, rowId, colId);
        this.residentCells.addDeferredParts(cellIndex, rowId, colId);
        return resolved;
    }
    deferVisibleCellPageRebuild() {
        this.cellPages.deferRebuild();
    }
    setFreshVisibleCellIdentityWithAxisIdsDeferred(cellIndex, rowId, colId) {
        this.cellIdentities.setParts(cellIndex, this.sheetId, rowId, colId);
        this.residentCells.addDeferredParts(cellIndex, rowId, colId);
    }
    setFreshVisibleDenseRowMajorIdentitiesWithAxisIdsDeferred(firstCellIndex, rowIds, colIds) {
        this.cellIdentities.setDenseRowMajorParts(firstCellIndex, this.sheetId, rowIds, colIds);
        this.residentCells.addDenseRowMajorDeferredParts(firstCellIndex, rowIds, colIds);
        if (rowIds.length > 0 && colIds.length > 0) {
            this.denseRowMajorVisibleCellBlocks.push({
                firstCellIndex,
                colCount: colIds.length,
                rowIds,
                colIds,
            });
        }
    }
    setVisibleCellInternal(row, col, cellIndex, factories, knownNewCell) {
        const resolved = {
            sheetId: this.sheetId,
            row,
            col,
            rowRef: this.ensureVisibleAxis('row', row, factories.createRowId),
            colRef: this.ensureVisibleAxis('column', col, factories.createColumnId),
        };
        const location = {
            sheetId: this.sheetId,
            rowId: resolved.rowRef.id,
            colId: resolved.colRef.id,
        };
        if (this.cellPages.hasDeferredRebuild()) {
            this.cellPages.setDeferred(location, cellIndex);
        }
        else {
            this.cellPages.set(location, cellIndex);
        }
        const identity = {
            sheetId: this.sheetId,
            rowId: resolved.rowRef.id,
            colId: resolved.colRef.id,
        };
        this.cellIdentities.set(cellIndex, identity);
        if (knownNewCell) {
            this.residentCells.add(cellIndex, identity);
        }
        else {
            this.clearDenseRowMajorVisibleCellBlocks();
            this.residentCells.set(cellIndex, identity);
        }
        return resolved;
    }
    deleteVisibleCell(row, col) {
        const location = this.resolveVisibleLocation(row, col);
        if (!location) {
            return false;
        }
        const cellIndex = this.cellPages.get(location);
        const deleted = this.cellPages.delete(location);
        if (deleted && cellIndex !== undefined) {
            this.clearDenseRowMajorVisibleCellBlocks();
            this.cellIdentities.delete(cellIndex);
            this.residentCells.delete(cellIndex);
        }
        return deleted;
    }
    deleteVisibleCellByIds(rowId, colId) {
        const location = {
            sheetId: this.sheetId,
            rowId,
            colId,
        };
        const cellIndex = this.cellPages.get(location);
        const deleted = this.cellPages.delete(location);
        if (deleted && cellIndex !== undefined) {
            this.clearDenseRowMajorVisibleCellBlocks();
            this.cellIdentities.delete(cellIndex);
            this.residentCells.delete(cellIndex);
        }
        return deleted;
    }
    moveVisibleCell(fromRow, fromCol, toRow, toCol, cellIndex, factories) {
        this.deleteVisibleCell(fromRow, fromCol);
        return this.setVisibleCell(toRow, toCol, cellIndex, factories);
    }
    getCellVisiblePosition(cellIndex) {
        const identity = this.cellIdentities.get(cellIndex);
        if (!identity || identity.sheetId !== this.sheetId) {
            return undefined;
        }
        const row = this.axisMap.indexOf('row', identity.rowId);
        const col = this.axisMap.indexOf('column', identity.colId);
        if (row < 0 || col < 0) {
            return undefined;
        }
        return { row, col };
    }
    getCellVisibleAxisIndex(cellIndex, axis) {
        const identity = this.cellIdentities.get(cellIndex);
        if (!identity || identity.sheetId !== this.sheetId) {
            return undefined;
        }
        const index = axis === 'row' ? this.axisMap.indexOf('row', identity.rowId) : this.axisMap.indexOf('column', identity.colId);
        return index < 0 ? undefined : index;
    }
    getCellIdentity(cellIndex) {
        const identity = this.cellIdentities.get(cellIndex);
        return identity?.sheetId === this.sheetId ? identity : undefined;
    }
    cellIdentityMatchesVisiblePosition(cellIndex, row, col) {
        const identity = this.cellIdentities.get(cellIndex);
        return (identity?.sheetId === this.sheetId &&
            this.axisMap.getId('row', row) === identity.rowId &&
            this.axisMap.getId('column', col) === identity.colId);
    }
    listResidentCellIndices(axis, axisIds) {
        return axis === 'row' ? this.residentCells.cellsInRows(axisIds) : this.residentCells.cellsInColumns(axisIds);
    }
    listResidentCellIndicesUnordered(axis, axisIds) {
        return axis === 'row' ? this.residentCells.cellsInRowsUnordered(axisIds) : this.residentCells.cellsInColumnsUnordered(axisIds);
    }
    forEachResidentCellInAxisEntries(axis, entries, callback) {
        const visitCell = (cellIndex, axisIndex) => {
            const identity = this.cellIdentities.get(cellIndex);
            if (identity?.sheetId === this.sheetId) {
                callback(cellIndex, identity, axisIndex);
            }
        };
        entries.forEach((entry) => {
            if (axis === 'row') {
                this.residentCells.forEachCellInRow(entry.id, (cellIndex) => {
                    visitCell(cellIndex, entry.index);
                });
                return;
            }
            this.residentCells.forEachCellInColumn(entry.id, (cellIndex) => {
                visitCell(cellIndex, entry.index);
            });
        });
    }
    someResidentCellInAxisScope(axis, scope, predicate) {
        const entries = this.axisMap.list(axis);
        for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 1) {
            const entry = entries[entryIndex];
            if (entry.index < scope.start || (scope.end !== undefined && entry.index >= scope.end)) {
                continue;
            }
            let found = false;
            const visitCell = (cellIndex) => {
                if (found) {
                    return;
                }
                const identity = this.cellIdentities.get(cellIndex);
                if (identity?.sheetId !== this.sheetId) {
                    return;
                }
                const otherAxisIndex = axis === 'row' ? this.axisMap.indexOf('column', identity.colId) : this.axisMap.indexOf('row', identity.rowId);
                if (otherAxisIndex < 0) {
                    return;
                }
                const row = axis === 'row' ? entry.index : otherAxisIndex;
                const col = axis === 'row' ? otherAxisIndex : entry.index;
                found = predicate(cellIndex, row, col);
            };
            if (axis === 'row') {
                this.residentCells.forEachCellInRow(entry.id, visitCell);
            }
            else {
                this.residentCells.forEachCellInColumn(entry.id, visitCell);
            }
            if (found) {
                return true;
            }
        }
        return false;
    }
    forEachVisibleCellEntry(callback) {
        const entries = [];
        this.cellIdentities.forEach((identity, cellIndex) => {
            if (identity.sheetId !== this.sheetId) {
                return;
            }
            const row = this.axisMap.indexOf('row', identity.rowId);
            const col = this.axisMap.indexOf('column', identity.colId);
            if (row < 0 || col < 0) {
                return;
            }
            entries.push({ cellIndex, row, col });
        });
        entries
            .toSorted((left, right) => left.row - right.row || left.col - right.col || left.cellIndex - right.cellIndex)
            .forEach((entry) => {
            callback(entry.cellIndex, entry.row, entry.col);
        });
    }
    forEachVisibleColumnCellEntry(col, callback) {
        const colId = this.axisMap.getId('column', col);
        if (colId === undefined) {
            return;
        }
        const entries = this.residentCells
            .cellsInColumn(colId)
            .flatMap((cellIndex) => {
            const position = this.getCellVisiblePosition(cellIndex);
            return position && position.col === col ? [{ cellIndex, row: position.row }] : [];
        })
            .toSorted((left, right) => left.row - right.row || left.cellIndex - right.cellIndex);
        entries.forEach((entry) => {
            callback(entry.cellIndex, entry.row);
        });
    }
    forEachVisibleRowCellEntry(row, callback) {
        const rowId = this.axisMap.getId('row', row);
        if (rowId === undefined) {
            return;
        }
        const entries = this.residentCells
            .cellsInRow(rowId)
            .flatMap((cellIndex) => {
            const position = this.getCellVisiblePosition(cellIndex);
            return position && position.row === row ? [{ cellIndex, col: position.col }] : [];
        })
            .toSorted((left, right) => left.col - right.col || left.cellIndex - right.cellIndex);
        entries.forEach((entry) => {
            callback(entry.cellIndex, entry.col);
        });
    }
    getDenseRowMajorVisibleCell(rowId, colId) {
        for (let index = this.denseRowMajorVisibleCellBlocks.length - 1; index >= 0; index -= 1) {
            const block = this.denseRowMajorVisibleCellBlocks[index];
            block.rowOffsets ??= indexedAxisIds(block.rowIds);
            const rowOffset = block.rowOffsets.get(rowId);
            if (rowOffset === undefined) {
                continue;
            }
            block.colOffsets ??= indexedAxisIds(block.colIds);
            const colOffset = block.colOffsets.get(colId);
            if (colOffset === undefined) {
                continue;
            }
            return block.firstCellIndex + rowOffset * block.colCount + colOffset;
        }
        return undefined;
    }
    clearDenseRowMajorVisibleCellBlocks() {
        this.denseRowMajorVisibleCellBlocks.length = 0;
    }
}
//# sourceMappingURL=logical-sheet-store.js.map