"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildTableGridMap = buildTableGridMap;
exports.findFirstCell = findFirstCell;
exports.findFirstCellInRow = findFirstCellInRow;
exports.findLastCell = findLastCell;
exports.findLastCellInRow = findLastCellInRow;
exports.findNextFocusableCell = findNextFocusableCell;
exports.getNextGridPosition = getNextGridPosition;
exports.isCellFocusable = isCellFocusable;
const table_focus_1 = require("./table-focus");
/**
 * Builds a utility grid allowing for easier keyboard-navigation between cells on columns and rows
 */
function buildTableGridMap(tableRef) {
    const rows = tableRef.rows;
    const grid = [];
    const positions = new Map();
    /* Walk trough each row in order */
    for (let rowIndex = 0; rowIndex < rows.length; rowIndex += 1) {
        const row = rows[rowIndex];
        const cells = row.cells;
        if (!grid[rowIndex]) {
            grid[rowIndex] = [];
        }
        let colIndex = 0;
        /* Walk trough each cell in row */
        for (let cellIndex = 0; cellIndex < cells.length; cellIndex += 1) {
            const cell = cells[cellIndex];
            /* Skip over slots already occupied by previous row/col spans. */
            while (grid[rowIndex][colIndex]) {
                colIndex += 1;
            }
            const colSpan = Math.max(cell.colSpan || 1, 1);
            const rowSpan = Math.max(cell.rowSpan || 1, 1);
            /* Fill the grid with references to this cell for its row/col span. */
            for (let y = rowIndex; y < rowIndex + rowSpan; y += 1) {
                if (!grid[y]) {
                    grid[y] = [];
                }
                for (let x = colIndex; x < colIndex + colSpan; x += 1) {
                    grid[y][x] = cell;
                }
            }
            /* Track the top-left coordinate for each unique cell. */
            if (!positions.has(cell)) {
                positions.set(cell, { x: colIndex, y: rowIndex });
            }
            colIndex += colSpan;
        }
    }
    return { grid, positions };
}
/**
 * Pure function that calculates the next grid position given a current position and delta.
 * Returns the position if valid, or null if out of bounds.
 */
function getNextGridPosition(grid, currentPos, delta) {
    var _a;
    const x = currentPos.x + delta.x;
    const y = currentPos.y + delta.y;
    if (y < 0 || y >= grid.length) {
        return null;
    }
    const row = (_a = grid[y]) !== null && _a !== void 0 ? _a : [];
    if (x < 0 || x >= row.length) {
        return null;
    }
    return { x, y };
}
/**
 * Checks if a cell is focusable (contains focusable elements).
 * Type guard that narrows Element | undefined to Element.
 */
function isCellFocusable(cell) {
    if (!cell) {
        return false;
    }
    return !!(0, table_focus_1.findFocusableElementInCell)(cell);
}
/**
 * Finds the next cell in the given direction, starting from the current position.
 * Skips over cells that are not focusable.
 * Returns null if no next cell is found in the given direction.
 */
function findNextFocusableCell(grid, currentPos, delta, currentCell) {
    let position = currentPos;
    while (true) {
        const nextPos = getNextGridPosition(grid, position, delta);
        if (!nextPos) {
            return null;
        }
        const cell = grid[nextPos.y][nextPos.x];
        /* We check against current cell to avoid returning the same cell in cases of rowspan/colspan. */
        if (cell !== currentCell && isCellFocusable(cell)) {
            return cell;
        }
        position = nextPos;
    }
}
/**
 * Finds the first focusable cell in the given row.
 */
function findFirstCellInRow(grid, rowIndex) {
    var _a;
    const row = (_a = grid[rowIndex]) !== null && _a !== void 0 ? _a : [];
    for (let x = 0; x < row.length; x += 1) {
        const cell = row[x];
        if (isCellFocusable(cell)) {
            return cell;
        }
    }
    return null;
}
/**
 * Finds the last focusable cell in the given row.
 */
function findLastCellInRow(grid, rowIndex) {
    var _a;
    const row = (_a = grid[rowIndex]) !== null && _a !== void 0 ? _a : [];
    for (let x = row.length - 1; x >= 0; x -= 1) {
        const cell = row[x];
        if (isCellFocusable(cell)) {
            return cell;
        }
    }
    return null;
}
/**
 * Finds the first focusable cell in the entire table.
 */
function findFirstCell(grid) {
    var _a;
    for (let y = 0; y < grid.length; y += 1) {
        const row = (_a = grid[y]) !== null && _a !== void 0 ? _a : [];
        for (let x = 0; x < row.length; x += 1) {
            const cell = row[x];
            if (isCellFocusable(cell)) {
                return cell;
            }
        }
    }
    return null;
}
/**
 * Finds the last focusable cell in the entire table.
 */
function findLastCell(grid) {
    var _a;
    for (let y = grid.length - 1; y >= 0; y -= 1) {
        const row = (_a = grid[y]) !== null && _a !== void 0 ? _a : [];
        for (let x = row.length - 1; x >= 0; x -= 1) {
            const cell = row[x];
            if (isCellFocusable(cell)) {
                return cell;
            }
        }
    }
    return null;
}
//# sourceMappingURL=table-grid-nav.js.map