import { __decorate } from "tslib";
import { observable } from '@ni/fast-element';
import { Virtualizer as TanStackVirtualizer, elementScroll, observeElementOffset, observeElementRect } from '@tanstack/virtual-core';
/**
 * Helper class for the nimble-table for row virtualization.
 *
 * @internal
 */
export class Virtualizer {
    get pageSize() {
        return this._pageSize;
    }
    constructor(table, tanStackTable) {
        this.visibleItems = [];
        this.scrollHeight = 0;
        this.horizontalScrollbarHeight = 0;
        this.isScrolling = false;
        this.headerContainerMarginRight = 0;
        this.rowContainerYOffset = 0;
        this._pageSize = 0;
        this.table = table;
        this.tanStackTable = tanStackTable;
        this.viewportResizeObserver = new ResizeObserver(entries => {
            const borderBoxSize = entries[0]?.borderBoxSize[0];
            if (borderBoxSize) {
                this.updatePageSize();
                // If we have enough rows that a vertical scrollbar is shown, we need to offset the header widths
                // by the same margin so the column headers align with the corresponding rendered cells
                const viewportBoundingWidth = borderBoxSize.inlineSize;
                this.headerContainerMarginRight = viewportBoundingWidth - this.table.viewport.clientWidth;
                this.horizontalScrollbarHeight = borderBoxSize.blockSize - this.table.viewport.clientHeight;
            }
        });
    }
    connect() {
        this.viewportResizeObserver.observe(this.table.viewport);
        this.updateVirtualizer();
        const scrollOffset = this.virtualizer.scrollOffset;
        if (scrollOffset !== null) {
            this.table.viewport.scrollTo({ top: scrollOffset });
        }
    }
    disconnect() {
        this.viewportResizeObserver.disconnect();
    }
    dataChanged() {
        if (this.table.$fastController.isConnected) {
            this.updateVirtualizer();
        }
    }
    scrollToIndex(index, options) {
        this.virtualizer?.scrollToIndex(index, options);
    }
    updateRowHeight() {
        this.updatePageSize();
        if (this.virtualizer) {
            this.updateVirtualizer();
            this.virtualizer.measure();
        }
    }
    updateVirtualizer() {
        const options = this.createVirtualizerOptions();
        if (this.virtualizer) {
            this.virtualizer.setOptions(options);
        }
        else {
            this.virtualizer = new TanStackVirtualizer(options);
        }
        this.virtualizer._willUpdate();
        this.handleVirtualizerChange();
    }
    createVirtualizerOptions() {
        const rowHeight = this.table.rowHeight;
        return {
            count: this.tanStackTable.getRowModel().rows.length,
            getScrollElement: () => {
                return this.table.viewport;
            },
            estimateSize: (_) => rowHeight,
            enableSmoothScroll: true,
            overscan: 3,
            isScrollingResetDelay: 250,
            useScrollendEvent: false,
            scrollToFn: elementScroll,
            observeElementOffset,
            observeElementRect,
            onChange: () => this.handleVirtualizerChange()
        };
    }
    handleVirtualizerChange() {
        const virtualizer = this.virtualizer;
        this.visibleItems = virtualizer.getVirtualItems();
        this.scrollHeight = virtualizer.getTotalSize();
        this.isScrolling = virtualizer.isScrolling;
        // We're using a separate div ('table-scroll') to represent the full height of all rows, and
        // the row container's height is only big enough to hold the virtualized rows. So we don't
        // use the TanStackVirtual-provided 'start' offset (which is in terms of the full height)
        // to translate every individual row, we just translate the row container.
        let rowContainerYOffset = 0;
        if (this.visibleItems.length > 0) {
            const firstItem = this.visibleItems[0];
            rowContainerYOffset = firstItem.start;
        }
        this.rowContainerYOffset = rowContainerYOffset;
    }
    updatePageSize() {
        this._pageSize = Math.round(this.table.viewport.clientHeight / this.table.rowHeight);
    }
}
__decorate([
    observable
], Virtualizer.prototype, "visibleItems", void 0);
__decorate([
    observable
], Virtualizer.prototype, "scrollHeight", void 0);
__decorate([
    observable
], Virtualizer.prototype, "horizontalScrollbarHeight", void 0);
__decorate([
    observable
], Virtualizer.prototype, "isScrolling", void 0);
__decorate([
    observable
], Virtualizer.prototype, "headerContainerMarginRight", void 0);
__decorate([
    observable
], Virtualizer.prototype, "rowContainerYOffset", void 0);
//# sourceMappingURL=virtualizer.js.map