/** @license MIT | @cube-dev/ui-kit v0.147.0 | Cube Dev Team */
import { getAllCollisions, getFirstCollision } from "./collision.js";
import { sortLayoutItems } from "./sort.js";

//#region src/components/layout/Board/grid-core/layout.ts
/**
* Core layout manipulation utilities.
*
* Vendored from react-grid-layout v2 (`src/core/layout.ts`).
* See ./NOTICE.md for attribution and license.
*
* These functions create, modify, and query grid layouts. Most functions treat
* layouts as immutable and return new arrays/objects, but a few mutate items in
* place for performance (documented per function).
*/
/**
* Get the bottom-most Y coordinate of the layout (max of y + h).
*/
function bottom(layout) {
	let max = 0;
	for (let i = 0; i < layout.length; i++) {
		const item = layout[i];
		if (item !== void 0) {
			const bottomY = item.y + item.h;
			if (bottomY > max) max = bottomY;
		}
	}
	return max;
}
/** Get a layout item by its ID. */
function getLayoutItem(layout, id) {
	for (let i = 0; i < layout.length; i++) {
		const item = layout[i];
		if (item !== void 0 && item.i === id) return item;
	}
}
/** Get all static items from the layout. */
function getStatics(layout) {
	return layout.filter((l) => l.static === true);
}
/** Clone a layout item (shallow copy, boolean flags normalized). */
function cloneLayoutItem(layoutItem) {
	return {
		i: layoutItem.i,
		x: layoutItem.x,
		y: layoutItem.y,
		w: layoutItem.w,
		h: layoutItem.h,
		minW: layoutItem.minW,
		maxW: layoutItem.maxW,
		minH: layoutItem.minH,
		maxH: layoutItem.maxH,
		moved: Boolean(layoutItem.moved),
		static: Boolean(layoutItem.static),
		isDraggable: layoutItem.isDraggable,
		isResizable: layoutItem.isResizable,
		resizeHandles: layoutItem.resizeHandles,
		constraints: layoutItem.constraints,
		isBounded: layoutItem.isBounded
	};
}
/** Clone an entire layout. */
function cloneLayout(layout) {
	const newLayout = new Array(layout.length);
	for (let i = 0; i < layout.length; i++) {
		const item = layout[i];
		if (item !== void 0) newLayout[i] = cloneLayoutItem(item);
	}
	return newLayout;
}
/** Replace a layout item in a layout (matched by `i`). Other items untouched. */
function modifyLayout(layout, layoutItem) {
	const newLayout = new Array(layout.length);
	for (let i = 0; i < layout.length; i++) {
		const item = layout[i];
		if (item !== void 0) if (layoutItem.i === item.i) newLayout[i] = layoutItem;
		else newLayout[i] = item;
	}
	return newLayout;
}
/**
* Ensure all layout items fit within the grid bounds.
*
* **IMPORTANT**: mutates the layout items in place for performance. Clone the
* layout first (e.g. with `cloneLayout()`) if you need immutability.
*/
function correctBounds(layout, bounds) {
	const collidesWith = getStatics(layout);
	for (let i = 0; i < layout.length; i++) {
		const l = layout[i];
		if (l === void 0) continue;
		if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w;
		if (l.x < 0) {
			l.x = 0;
			l.w = bounds.cols;
		}
		if (!l.static) collidesWith.push(l);
		else while (getFirstCollision(collidesWith, l)) l.y++;
	}
	return layout;
}
/**
* Move a layout element to a new position.
*
* Handles collision detection and cascading movements. Does not compact the
* layout - call the compactor separately.
*
* **Note**: mutates the `l` parameter directly for performance.
*/
function moveElement(layout, l, x, y, isUserAction, preventCollision, compactType, cols, allowOverlap) {
	if (l.static && l.isDraggable !== true) return [...layout];
	if (l.y === y && l.x === x) return [...layout];
	const oldX = l.x;
	const oldY = l.y;
	if (typeof x === "number") l.x = x;
	if (typeof y === "number") l.y = y;
	l.moved = true;
	let sorted = sortLayoutItems(layout, compactType);
	if (compactType === "vertical" && typeof y === "number" ? oldY >= y : compactType === "horizontal" && typeof x === "number" ? oldX >= x : false) sorted = sorted.reverse();
	const collisions = getAllCollisions(sorted, l);
	const hasCollisions = collisions.length > 0;
	if (hasCollisions && allowOverlap) return cloneLayout(layout);
	if (hasCollisions && preventCollision) {
		l.x = oldX;
		l.y = oldY;
		l.moved = false;
		return layout;
	}
	let resultLayout = [...layout];
	for (let i = 0; i < collisions.length; i++) {
		const collision = collisions[i];
		if (collision === void 0) continue;
		if (collision.moved) continue;
		if (collision.static) resultLayout = moveElementAwayFromCollision(resultLayout, collision, l, isUserAction, compactType, cols);
		else resultLayout = moveElementAwayFromCollision(resultLayout, l, collision, isUserAction, compactType, cols);
	}
	return resultLayout;
}
/**
* Move an item away from a collision. Attempts to move up/left first if there's
* room, otherwise moves it down/right.
*/
function moveElementAwayFromCollision(layout, collidesWith, itemToMove, isUserAction, compactType, cols) {
	const compactH = compactType === "horizontal";
	const compactV = compactType === "vertical";
	const preventCollision = collidesWith.static;
	if (isUserAction) {
		isUserAction = false;
		const fakeItem = {
			x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x,
			y: compactV ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
			w: itemToMove.w,
			h: itemToMove.h,
			i: "-1"
		};
		const firstCollision = getFirstCollision(layout, fakeItem);
		const collisionNorth = firstCollision !== void 0 && firstCollision.y + firstCollision.h > collidesWith.y;
		const collisionWest = firstCollision !== void 0 && collidesWith.x + collidesWith.w > firstCollision.x;
		if (!firstCollision) return moveElement(layout, itemToMove, compactH ? fakeItem.x : void 0, compactV ? fakeItem.y : void 0, isUserAction, preventCollision, compactType, cols);
		if (collisionNorth && compactV) return moveElement(layout, itemToMove, void 0, itemToMove.y + 1, isUserAction, preventCollision, compactType, cols);
		if (collisionNorth && compactType === null) {
			collidesWith.y = itemToMove.y;
			itemToMove.y = itemToMove.y + itemToMove.h;
			return [...layout];
		}
		if (collisionWest && compactH) return moveElement(layout, collidesWith, itemToMove.x, void 0, isUserAction, preventCollision, compactType, cols);
	}
	const newX = compactH ? itemToMove.x + 1 : void 0;
	const newY = compactV ? itemToMove.y + 1 : void 0;
	if (newX === void 0 && newY === void 0) return [...layout];
	return moveElement(layout, itemToMove, newX, newY, isUserAction, preventCollision, compactType, cols);
}

//#endregion
export { bottom, cloneLayout, cloneLayoutItem, correctBounds, getLayoutItem, getStatics, modifyLayout, moveElement };
//# sourceMappingURL=layout.js.map