// #region Imports
// #endregion
/**
 * Utility class for resize calculations in the tile manager.
 *
 * @public
 */
export class TileManagerResizeUtil {
    // #region Fields
    _gap;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `TileManagerResizeUtil` class.
     *
     * @param gap - The gap size between tiles.
     *
     * @public
     */
    constructor(gap) {
        this._gap = gap;
    }
    // #endregion
    // #region Properties
    /**
     * Gets the gap size.
     *
     * @public
     * @readonly
     */
    get gap() {
        return this._gap;
    }
    // #endregion
    // #region Methods
    /**
     * Calculates the snapped dimension during resize.
     *
     * @param resizeProps - The resize properties.
     * @returns The snapped dimension result.
     *
     * @public
     */
    calculateSnappedDimension(resizeProps) {
        const { currentDelta, prevDelta, currentSize, gridEntries, startIndex, prevSnapped } = resizeProps;
        const effectiveDelta = currentDelta - prevDelta;
        let snappedSize = currentSize;
        // If current size is below minimum, force to the size of the starting cell.
        if (Math.trunc(currentSize) < gridEntries[startIndex - 1]) {
            return {
                snappedSize: gridEntries[startIndex - 1],
                newDelta: currentDelta
            };
        }
        // If no change in delta and we have a snapped value, reuse it.
        if (effectiveDelta === 0 && prevSnapped) {
            return {
                snappedSize: prevSnapped,
                newDelta: currentDelta
            };
        }
        let accumulated = 0;
        for (let i = startIndex - 1; i < gridEntries.length; i++) {
            const currentEntry = gridEntries[i];
            const nextEntry = gridEntries[i + 1] ?? currentEntry;
            const prevEntry = i > 0 ? gridEntries[i - 1] : currentEntry;
            // Thresholds for snapping to the next or previous tile boundary.
            const halfwayExpand = accumulated + currentEntry + this._gap + (nextEntry / 2);
            const halfwayShrink = accumulated + (prevEntry / 2);
            const entryEnd = accumulated + currentEntry + this._gap;
            if (effectiveDelta > 0) {
                // Expanding: snap when passing the halfway threshold.
                if (currentSize >= halfwayExpand &&
                    currentSize <= entryEnd + nextEntry) {
                    snappedSize = entryEnd + nextEntry;
                }
            }
            else if (effectiveDelta < 0) {
                // Shrinking: snap when falling below the halfway threshold.
                if (currentSize <= halfwayShrink &&
                    currentSize > accumulated - this._gap) {
                    snappedSize = accumulated - this._gap;
                }
            }
            accumulated += currentEntry + this._gap;
        }
        return {
            snappedSize,
            newDelta: currentDelta
        };
    }
    /**
     * Calculates the resized span based on the target size.
     *
     * @param props - The resize span properties.
     * @returns The new span value.
     *
     * @public
     */
    calculateResizedSpan(props) {
        const { targetSize, tilePosition, tileGridDimension, gap, isRow } = props;
        const { entries, minSize } = tileGridDimension;
        let accumulatedSize = 0;
        let newSpan = tilePosition.span;
        const sizesAfterStart = entries.slice(tilePosition.start - 1);
        const availableSize = sizesAfterStart.reduce((sum, s) => sum + s, 0) +
            ((sizesAfterStart.length - 1) * gap);
        if (targetSize <= sizesAfterStart[0] + gap) {
            return 1;
        }
        if (Math.trunc(targetSize) > Math.trunc(availableSize)) {
            const remainingSize = targetSize - availableSize;
            const additionalSpan = Math.ceil(remainingSize / (minSize + gap));
            newSpan = sizesAfterStart.length + additionalSpan;
            return isRow ? newSpan : Math.min(entries.length, newSpan);
        }
        for (let i = tilePosition.start - 1; i < entries.length; i++) {
            const currentSize = entries[i];
            const nextSize = entries[i + 1] ?? currentSize;
            const halfwayPoint = accumulatedSize + currentSize + gap + (nextSize / 2);
            if (targetSize > halfwayPoint) {
                newSpan = i + 3 - tilePosition.start;
            }
            else {
                break;
            }
            accumulatedSize += currentSize + gap;
        }
        return newSpan;
    }
    /**
     * Calculates the grid position based on target position and sizes.
     *
     * @param targetPosition - The target position in pixels.
     * @param sizes - The array of grid entry sizes.
     * @returns The grid position index (1-based).
     *
     * @public
     */
    calculatePosition(targetPosition, sizes) {
        let accumulatedSize = 0;
        for (const [i, size] of sizes.entries()) {
            accumulatedSize += size + this._gap;
            if (Math.trunc(targetPosition) < Math.trunc(accumulatedSize - this._gap)) {
                return i + 1;
            }
        }
        return 1;
    }
}
//# sourceMappingURL=TileManagerResizeUtil.js.map