export class AxisResidentCellIndex {
    rebuildSource;
    sheetIds = [];
    rowIds = [];
    colIds = [];
    byRow = new Map();
    byColumn = new Map();
    primaryIndexDirty = false;
    secondaryIndexesDirty = false;
    constructor(rebuildSource) {
        this.rebuildSource = rebuildSource;
    }
    set(cellIndex, identity) {
        this.ensurePrimaryIndex();
        const existingRowId = this.rowIds[cellIndex];
        const existingColId = this.colIds[cellIndex];
        if (existingRowId !== undefined && existingColId !== undefined && !this.secondaryIndexesDirty) {
            deleteFromSetMap(this.byRow, existingRowId, cellIndex);
            deleteFromSetMap(this.byColumn, existingColId, cellIndex);
        }
        this.setPrimaryParts(cellIndex, identity.sheetId, identity.rowId, identity.colId);
        if (!this.secondaryIndexesDirty) {
            addToSetMap(this.byRow, identity.rowId, cellIndex);
            addToSetMap(this.byColumn, identity.colId, cellIndex);
        }
    }
    add(cellIndex, identity) {
        this.ensurePrimaryIndex();
        const existingRowId = this.rowIds[cellIndex];
        const existingColId = this.colIds[cellIndex];
        if (existingRowId !== undefined && existingColId !== undefined && !this.secondaryIndexesDirty) {
            deleteFromSetMap(this.byRow, existingRowId, cellIndex);
            deleteFromSetMap(this.byColumn, existingColId, cellIndex);
        }
        this.setPrimaryParts(cellIndex, identity.sheetId, identity.rowId, identity.colId);
        if (!this.secondaryIndexesDirty) {
            addToSetMap(this.byRow, identity.rowId, cellIndex);
            addToSetMap(this.byColumn, identity.colId, cellIndex);
        }
    }
    addDeferred(cellIndex, identity) {
        this.ensurePrimaryIndex();
        this.setPrimaryParts(cellIndex, identity.sheetId, identity.rowId, identity.colId);
        this.secondaryIndexesDirty = true;
    }
    addDeferredParts(cellIndex, rowId, colId) {
        this.ensurePrimaryIndex();
        this.setPrimaryParts(cellIndex, undefined, rowId, colId);
        this.secondaryIndexesDirty = true;
    }
    addDenseRowMajorDeferredParts(firstCellIndex, rowIds, colIds) {
        if (this.rebuildSource) {
            this.deferRebuild();
            return;
        }
        this.ensurePrimaryIndex();
        const colCount = colIds.length;
        const cellCount = rowIds.length * colCount;
        if (cellCount === 0) {
            return;
        }
        const endCellIndex = firstCellIndex + cellCount;
        this.sheetIds.length = Math.max(this.sheetIds.length, endCellIndex);
        this.rowIds.length = Math.max(this.rowIds.length, endCellIndex);
        this.colIds.length = Math.max(this.colIds.length, endCellIndex);
        let cellIndex = firstCellIndex;
        for (let rowOffset = 0; rowOffset < rowIds.length; rowOffset += 1) {
            const rowId = rowIds[rowOffset];
            for (let colOffset = 0; colOffset < colCount; colOffset += 1) {
                this.sheetIds[cellIndex] = undefined;
                this.rowIds[cellIndex] = rowId;
                this.colIds[cellIndex] = colIds[colOffset];
                cellIndex += 1;
            }
        }
        this.secondaryIndexesDirty = true;
    }
    deferRebuild() {
        this.sheetIds.length = 0;
        this.rowIds.length = 0;
        this.colIds.length = 0;
        this.byRow.clear();
        this.byColumn.clear();
        this.primaryIndexDirty = true;
        this.secondaryIndexesDirty = false;
    }
    get(cellIndex) {
        this.ensurePrimaryIndex();
        const rowId = this.rowIds[cellIndex];
        const colId = this.colIds[cellIndex];
        if (rowId === undefined || colId === undefined) {
            return undefined;
        }
        const sheetId = this.sheetIds[cellIndex];
        return sheetId === undefined ? { rowId, colId } : { sheetId, rowId, colId };
    }
    delete(cellIndex) {
        this.ensurePrimaryIndex();
        const existingRowId = this.rowIds[cellIndex];
        const existingColId = this.colIds[cellIndex];
        if (existingRowId === undefined || existingColId === undefined) {
            return false;
        }
        this.sheetIds[cellIndex] = undefined;
        this.rowIds[cellIndex] = undefined;
        this.colIds[cellIndex] = undefined;
        if (this.secondaryIndexesDirty) {
            return true;
        }
        deleteFromSetMap(this.byRow, existingRowId, cellIndex);
        deleteFromSetMap(this.byColumn, existingColId, cellIndex);
        return true;
    }
    clear() {
        this.sheetIds.length = 0;
        this.rowIds.length = 0;
        this.colIds.length = 0;
        this.byRow.clear();
        this.byColumn.clear();
        this.primaryIndexDirty = false;
        this.secondaryIndexesDirty = false;
    }
    cellsInRow(rowId) {
        this.ensureSecondaryIndexes();
        return sortedCells(this.byRow.get(rowId));
    }
    cellsInColumn(colId) {
        this.ensureSecondaryIndexes();
        return sortedCells(this.byColumn.get(colId));
    }
    forEachCellInRow(rowId, callback) {
        this.ensureSecondaryIndexes();
        this.byRow.get(rowId)?.forEach(callback);
    }
    forEachCellInColumn(colId, callback) {
        this.ensureSecondaryIndexes();
        this.byColumn.get(colId)?.forEach(callback);
    }
    cellsInRows(rowIds) {
        return sortedUniqueCells(rowIds.flatMap((rowId) => this.cellsInRow(rowId)));
    }
    cellsInColumns(colIds) {
        return sortedUniqueCells(colIds.flatMap((colId) => this.cellsInColumn(colId)));
    }
    cellsInRowsUnordered(rowIds) {
        this.ensureSecondaryIndexes();
        return uniqueCells(rowIds.flatMap((rowId) => [...(this.byRow.get(rowId) ?? [])]));
    }
    cellsInColumnsUnordered(colIds) {
        this.ensureSecondaryIndexes();
        return uniqueCells(colIds.flatMap((colId) => [...(this.byColumn.get(colId) ?? [])]));
    }
    ensurePrimaryIndex() {
        if (!this.primaryIndexDirty) {
            return;
        }
        this.sheetIds.length = 0;
        this.rowIds.length = 0;
        this.colIds.length = 0;
        this.rebuildSource?.((cellIndex, identity) => {
            this.setPrimaryParts(cellIndex, identity.sheetId, identity.rowId, identity.colId);
        });
        this.primaryIndexDirty = false;
        this.secondaryIndexesDirty = true;
    }
    ensureSecondaryIndexes() {
        this.ensurePrimaryIndex();
        if (!this.secondaryIndexesDirty) {
            return;
        }
        this.byRow.clear();
        this.byColumn.clear();
        for (let cellIndex = 0; cellIndex < this.rowIds.length; cellIndex += 1) {
            const rowId = this.rowIds[cellIndex];
            const colId = this.colIds[cellIndex];
            if (rowId === undefined || colId === undefined) {
                continue;
            }
            addToSetMap(this.byRow, rowId, cellIndex);
            addToSetMap(this.byColumn, colId, cellIndex);
        }
        this.secondaryIndexesDirty = false;
    }
    setPrimaryParts(cellIndex, sheetId, rowId, colId) {
        this.sheetIds[cellIndex] = sheetId;
        this.rowIds[cellIndex] = rowId;
        this.colIds[cellIndex] = colId;
    }
}
function addToSetMap(map, key, value) {
    let values = map.get(key);
    if (!values) {
        values = new Set();
        map.set(key, values);
    }
    values.add(value);
}
function deleteFromSetMap(map, key, value) {
    const values = map.get(key);
    if (!values) {
        return;
    }
    values.delete(value);
    if (values.size === 0) {
        map.delete(key);
    }
}
function sortedCells(values) {
    return values ? [...values].toSorted((left, right) => left - right) : [];
}
function sortedUniqueCells(values) {
    return [...new Set(values)].toSorted((left, right) => left - right);
}
function uniqueCells(values) {
    return [...new Set(values)];
}
//# sourceMappingURL=axis-resident-cell-index.js.map