// #region Imports
import { TileManagerResizeUtil } from './TileManagerResizeUtil';
// #endregion
const CSS_VALUES_REGEX = /(?<start>\d+)?\s*\/?\s*span\s*(?<span>\d+)?/giu;
/**
 * Parses the grid position of a tile from its computed styles.
 *
 * @param tile - The tile element.
 * @returns The grid position.
 */
function parseTileGridRect(tile) {
    const computed = getComputedStyle(tile);
    const { gridColumn, gridRow } = computed;
    const columnMatches = Array.from(gridColumn.matchAll(CSS_VALUES_REGEX));
    const rowMatches = Array.from(gridRow.matchAll(CSS_VALUES_REGEX));
    const column = columnMatches[0]?.groups ?? {
        start: '-1',
        span: '-1'
    };
    const row = rowMatches[0]?.groups ?? {
        start: '-1',
        span: '-1'
    };
    const columnStart = column.start || '-1';
    const columnSpan = column.span || '-1';
    const rowStart = row.start || '-1';
    const rowSpan = row.span || '-1';
    return {
        column: {
            start: parseInt(columnStart, 10),
            span: parseInt(columnSpan, 10)
        },
        row: {
            start: parseInt(rowStart, 10),
            span: parseInt(rowSpan, 10)
        }
    };
}
/**
 * Parses the grid container properties.
 *
 * @param gridContainer - The grid container element.
 * @returns The parsed grid properties.
 */
function parseTileParentGrid(gridContainer) {
    const computed = getComputedStyle(gridContainer);
    const { gap, gridTemplateColumns, gridTemplateRows } = computed;
    const columns = gridTemplateColumns.split(' ').map((v) => parseFloat(v) || 0);
    const rows = gridTemplateRows.split(' ').map((v) => parseFloat(v) || 0);
    return {
        gap: parseFloat(gap) || 0,
        columns: {
            count: columns.length,
            entries: columns,
            minSize: parseFloat(computed.getPropertyValue('--min-col-width')) || 0
        },
        rows: {
            count: rows.length,
            entries: rows,
            minSize: parseFloat(computed.getPropertyValue('--min-row-height')) || 0
        }
    };
}
/**
 * Manages the resize state for a tile during resize operations.
 *
 * @public
 */
export class TileManagerResizeState {
    // #region Fields
    _gap;
    _prevDeltaX;
    _prevDeltaY;
    _prevSnappedWidth;
    _prevSnappedHeight;
    _position;
    _columns;
    _rows;
    _initialPosition;
    _resizeUtil;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `TileManagerResizeState` class.
     *
     * @public
     */
    constructor() {
        this._gap = 0;
        this._prevDeltaX = 0;
        this._prevDeltaY = 0;
        this._prevSnappedWidth = 0;
        this._prevSnappedHeight = 0;
        this._position = {
            column: {
                start: 0,
                span: 0
            },
            row: {
                start: 0,
                span: 0
            }
        };
        this._columns = {
            count: 0,
            entries: [],
            minSize: 0
        };
        this._rows = {
            count: 0,
            entries: [],
            minSize: 0
        };
        this._initialPosition = {
            column: {
                start: 0,
                span: 0
            },
            row: {
                start: 0,
                span: 0
            }
        };
        this._resizeUtil = new TileManagerResizeUtil(0);
        this.resizedDimensions = {
            width: null,
            height: null
        };
    }
    // #endregion
    // #region Properties
    /**
     * The resized dimensions.
     *
     * @public
     */
    resizedDimensions;
    /**
     * Gets the gap size.
     *
     * @public
     * @readonly
     */
    get gap() {
        return this._gap;
    }
    /**
     * Gets a clone of the current position.
     *
     * @public
     * @readonly
     */
    get position() {
        return structuredClone(this._position);
    }
    /**
     * Gets a clone of the columns information.
     *
     * @public
     * @readonly
     */
    get columns() {
        return structuredClone(this._columns);
    }
    /**
     * Gets a clone of the rows information.
     *
     * @public
     * @readonly
     */
    get rows() {
        return structuredClone(this._rows);
    }
    // #endregion
    // #region Methods
    /**
     * Calculates the snapped width during resize.
     *
     * @param state - The resize state containing current dimensions.
     * @returns The snapped width.
     *
     * @public
     */
    calculateSnappedWidth(state) {
        const resizeProps = this.getResizeProps(state);
        const snappedDimension = this._resizeUtil.calculateSnappedDimension(resizeProps);
        this._prevDeltaX = snappedDimension.newDelta;
        this._prevSnappedWidth = snappedDimension.snappedSize;
        return snappedDimension.snappedSize;
    }
    /**
     * Calculates the snapped height during resize.
     *
     * @param state - The resize state containing current dimensions.
     * @returns The snapped height.
     *
     * @public
     */
    calculateSnappedHeight(state) {
        const resizeProps = this.getResizeProps(state, true);
        const snappedDimension = this._resizeUtil.calculateSnappedDimension(resizeProps);
        this._prevDeltaY = snappedDimension.newDelta;
        this._prevSnappedHeight = snappedDimension.snappedSize;
        return snappedDimension.snappedSize;
    }
    /**
     * Updates the resize state with new values.
     *
     * @param tileRect - The tile's bounding rectangle.
     * @param tile - The tile element.
     * @param grid - The grid container element.
     *
     * @public
     */
    updateState(tileRect, tile, grid) {
        const { gap, columns, rows } = parseTileParentGrid(grid);
        this._resizeUtil = new TileManagerResizeUtil(gap);
        this._initialPosition = parseTileGridRect(tile);
        this._position = structuredClone(this._initialPosition);
        this._gap = gap;
        this._columns = columns;
        this._rows = rows;
        this._prevDeltaX = 0;
        this._prevDeltaY = 0;
        this._prevSnappedWidth = 0;
        this._prevSnappedHeight = 0;
        if (this._position.column.start < 0) {
            const offsetX = this.getGridOffset(grid, 'horizontal');
            this._position.column.start = this._resizeUtil.calculatePosition(tileRect.left + window.scrollX + grid.scrollLeft - offsetX, this._columns.entries);
        }
        if (this._position.row.start < 0) {
            const offsetY = this.getGridOffset(grid, 'vertical');
            this._position.row.start = this._resizeUtil.calculatePosition(tileRect.top + window.scrollY - offsetY, this._rows.entries);
        }
    }
    /**
     * Calculates the resized grid position after a resize operation.
     *
     * @param rect - The new bounding rectangle.
     * @returns The new column and row spans.
     *
     * @public
     */
    calculateResizedGridPosition(rect) {
        const colProps = this.getResizeSpanProps(rect);
        const rowProps = this.getResizeSpanProps(rect, true);
        this._position.column.span = this._resizeUtil.calculateResizedSpan(colProps);
        this._position.row.span = this._resizeUtil.calculateResizedSpan(rowProps);
        return {
            colSpan: this._position.column.span,
            rowSpan: this._position.row.span
        };
    }
    /**
     * Gets the grid offset for a given axis.
     *
     * @param grid - The grid container element.
     * @param axis - The axis ('horizontal' or 'vertical').
     * @returns The offset value.
     */
    getGridOffset(grid, axis) {
        const gridRect = grid.getBoundingClientRect();
        const computed = getComputedStyle(grid);
        if (axis === 'horizontal') {
            return gridRect.left + window.scrollX + grid.scrollLeft + parseFloat(computed.paddingLeft);
        }
        return gridRect.top + window.scrollY + parseFloat(computed.paddingTop);
    }
    /**
     * Gets the resize properties for the current state.
     *
     * @param state - The resize state.
     * @param isRow - Whether this is for row (vertical) resize.
     * @returns The resize properties.
     */
    getResizeProps(state, isRow = false) {
        if (isRow) {
            return {
                currentDelta: state.deltaY ?? 0,
                currentSize: state.current.height ?? 0,
                prevDelta: this._prevDeltaY,
                gridEntries: this._rows.entries,
                startIndex: this._position.row.start,
                prevSnapped: this._prevSnappedHeight
            };
        }
        return {
            currentDelta: state.deltaX ?? 0,
            currentSize: state.current.width ?? 0,
            prevDelta: this._prevDeltaX,
            gridEntries: this._columns.entries,
            startIndex: this._position.column.start,
            prevSnapped: this._prevSnappedWidth
        };
    }
    /**
     * Gets the resize span properties.
     *
     * @param rect - The bounding rectangle.
     * @param isRow - Whether this is for row (vertical) resize.
     * @returns The resize span properties.
     */
    getResizeSpanProps(rect, isRow = false) {
        if (isRow) {
            return {
                targetSize: rect.height,
                tilePosition: this.position.row,
                tileGridDimension: this.rows,
                gap: this.gap,
                isRow
            };
        }
        return {
            targetSize: rect.width,
            tilePosition: this.position.column,
            tileGridDimension: this.columns,
            gap: this.gap,
            isRow
        };
    }
}
/**
 * Factory function to create a new TileManagerResizeState instance.
 *
 * @returns A new TileManagerResizeState instance.
 *
 * @public
 */
export function createTileManagerResizeState() {
    return new TileManagerResizeState();
}
//# sourceMappingURL=TileManagerResizeState.js.map