import { TableRecordDelayedHierarchyState } from '../types';
/**
 * Manages the expanded/collapsed state of rows in the table.
 *
 * We must track the expansion state separately from TanStack because:
 *   1. TanStack does not support having a different initial expansion state per row unless explicitly
 *      specified for each row by ID. This causes problems in the nimble-table because we could have
 *      a different initial expansion state for group rows, parent rows, and parent rows with delay-loaded
 *      children.
 *   2. TanStack does not remove entries from its expanded state when those rows are no longer present
 *      in the data. This is not ideal because the object maintaining the expansion state can grow unbounded.
 */
export class ExpansionManager {
    constructor(tanStackTable) {
        this.tanStackTable = tanStackTable;
        this.explicitExpansionStates = new Map();
        this.hierarchyOptions = new Map();
        this.isHierarchyEnabled = false;
        this.parentRowsWithChildren = new Set();
    }
    isRowExpanded(row) {
        if (!this.isRowExpandable(row)) {
            return false;
        }
        const expansionState = this.explicitExpansionStates.get(row.id);
        return expansionState ?? this.getDefaultExpansionState(row);
    }
    toggleRowExpansion(row) {
        if (!this.isRowExpandable(row)) {
            return;
        }
        const wasExpanded = this.isRowExpanded(row);
        this.explicitExpansionStates.set(row.id, !wasExpanded);
        row.toggleExpanded();
    }
    collapseAll() {
        this.resetExpansionState();
        const rows = this.tanStackTable.getRowModel().flatRows;
        for (const row of rows) {
            if (this.isRowExpandable(row)) {
                this.explicitExpansionStates.set(row.id, false);
            }
        }
        this.tanStackTable.toggleAllRowsExpanded(false);
    }
    resetExpansionState() {
        this.explicitExpansionStates.clear();
    }
    resetHierarchyOptions() {
        this.hierarchyOptions.clear();
    }
    processDataUpdate(rows) {
        if (this.explicitExpansionStates.size === 0
            && this.hierarchyOptions.size === 0) {
            return;
        }
        const updatedExplicitExpansionStates = new Map();
        const updatedHierarchyOptions = new Map();
        const updatedParentRowsWithChildren = new Set();
        for (const row of rows) {
            const rowId = row.id;
            const isGroupRow = row.getIsGrouped();
            const rowHierarchyOptions = this.hierarchyOptions.get(rowId);
            if (!isGroupRow && rowHierarchyOptions) {
                updatedHierarchyOptions.set(rowId, rowHierarchyOptions);
            }
            if (this.isRowExpandable(row)) {
                const expansionState = this.explicitExpansionStates.get(rowId);
                if (expansionState !== undefined) {
                    updatedExplicitExpansionStates.set(rowId, expansionState);
                }
                if (!isGroupRow) {
                    const hasChildRows = row.subRows.length !== 0;
                    if (hasChildRows) {
                        updatedParentRowsWithChildren.add(rowId);
                    }
                    else if (this.parentRowsWithChildren.has(rowId)) {
                        // The row used to have children, but now it does not. Therefore,
                        // collapse the row.
                        updatedExplicitExpansionStates.set(rowId, false);
                    }
                }
            }
        }
        this.explicitExpansionStates = updatedExplicitExpansionStates;
        this.hierarchyOptions = updatedHierarchyOptions;
        this.parentRowsWithChildren = updatedParentRowsWithChildren;
    }
    setHierarchyOptions(hierarchyOptions) {
        const updatedHierarchyOptions = new Map();
        for (const { recordId, options } of hierarchyOptions) {
            updatedHierarchyOptions.set(recordId, options);
            const oldState = this.hierarchyOptions.get(recordId)?.delayedHierarchyState;
            const newState = options.delayedHierarchyState;
            if (oldState === TableRecordDelayedHierarchyState.loadingChildren
                && newState === TableRecordDelayedHierarchyState.canLoadChildren
                && !this.parentRowsWithChildren.has(recordId)) {
                // If a row without children transitions from loadingChildren to canLoadChildren,
                // put it back in its default state of collapsed.
                this.explicitExpansionStates.delete(recordId);
            }
        }
        this.hierarchyOptions = updatedHierarchyOptions;
    }
    isRowExpandable(row) {
        return row.subRows.length > 0 || this.canLoadDelayedChildren(row.id);
    }
    setHierarchyEnabled(isHierarchyEnabled) {
        this.isHierarchyEnabled = isHierarchyEnabled;
    }
    isLoadingChildren(id) {
        if (!this.isHierarchyEnabled) {
            return false;
        }
        return (this.hierarchyOptions.get(id)?.delayedHierarchyState
            === TableRecordDelayedHierarchyState.loadingChildren);
    }
    canLoadDelayedChildren(id) {
        if (!this.isHierarchyEnabled) {
            return false;
        }
        const delayedHierarchyState = this.hierarchyOptions.get(id)?.delayedHierarchyState;
        return delayedHierarchyState !== TableRecordDelayedHierarchyState.none;
    }
    getDefaultExpansionState(row) {
        // Rows with children (group rows and parent rows with populated children)
        // default to expanded. Other rows (parent rows with lazy-loaded children)
        // default to collapsed.
        return row.subRows.length !== 0;
    }
}
//# sourceMappingURL=expansion-manager.js.map