/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
import { Dimensions, Point, Rectangle } from "@vertexvis/geometry";
import { getWindowDevicePixelRatio } from "../../lib/dom";
import { isVertexViewerArrowMarkup } from "../viewer-markup-arrow/utils";
import { isVertexViewerCircleMarkup } from "../viewer-markup-circle/utils";
import { isVertexViewerFreeformMarkup } from "../viewer-markup-freeform/utils";
export function getBoundingBox2dAnchorPosition(rect, position) {
    switch (position) {
        case 'top-left':
            return Point.create(rect.x, rect.y);
        case 'top':
            return Point.create(rect.x + rect.width / 2, rect.y);
        case 'top-right':
            return Point.create(rect.x + rect.width, rect.y);
        case 'right':
            return Point.create(rect.x + rect.width, rect.y + rect.height / 2);
        case 'bottom-right':
            return Point.create(rect.x + rect.width, rect.y + rect.height);
        case 'bottom':
            return Point.create(rect.x + rect.width / 2, rect.y + rect.height);
        case 'bottom-left':
            return Point.create(rect.x, rect.y + rect.height);
        case 'left':
            return Point.create(rect.x, rect.y + rect.height / 2);
        case 'center':
            return Rectangle.center(rect);
    }
}
export function translatePointToScreen(pt, canvasDimensions, contentDimensions = canvasDimensions, centeringBehavior = 'none', scale = 1) {
    const canvasToContentScaleFactor = Math.min(canvasDimensions.width / contentDimensions.width, canvasDimensions.height / contentDimensions.height);
    const effectiveScalar = canvasToContentScaleFactor * scale;
    const contentScaleFactor = getScaleFactor(contentDimensions);
    const contentRelativePoint = Point.add(Point.scale(pt, contentScaleFactor, contentScaleFactor), Dimensions.center(contentDimensions));
    // Include an offset for width and height to account for cases where the
    // content dimensions are smaller than the canvas dimensions.
    const scaledContentWidth = contentDimensions.width * effectiveScalar;
    const scaledContentHeight = contentDimensions.height * effectiveScalar;
    const centerOffsetX = centeringBehavior === 'both' || centeringBehavior === 'x-only'
        ? Math.max(0, (canvasDimensions.width - scaledContentWidth) / 2)
        : 0;
    const centerOffsetY = centeringBehavior === 'both' || centeringBehavior === 'y-only'
        ? Math.max(0, (canvasDimensions.height - scaledContentHeight) / 2)
        : 0;
    return Point.create(contentRelativePoint.x * effectiveScalar + centerOffsetX, contentRelativePoint.y * effectiveScalar + centerOffsetY);
}
export function translatePointToBounds(pt, rect, canvasDimensions) {
    const rectToScreen = translateRectToScreen(rect, canvasDimensions);
    return Point.add(pt, rectToScreen);
}
export function translateDimensionsToScreen(dimensions, canvasDimensions, contentDimensions = canvasDimensions, scale = 1) {
    const canvasToContentScaleFactor = Math.min(canvasDimensions.width / contentDimensions.width, canvasDimensions.height / contentDimensions.height);
    const effectiveScalar = canvasToContentScaleFactor * scale;
    const contentScaleFactor = getScaleFactor(contentDimensions);
    const contentRelativeDimensions = Dimensions.scale(contentScaleFactor, contentScaleFactor, dimensions);
    return Dimensions.scale(effectiveScalar, effectiveScalar, contentRelativeDimensions);
}
/**
 * Translates a rectangle in relative units, to a rectangle in screen units.
 *
 * Shape coordinates are persisted in relative units, so they can be presented
 * at any size.
 */
export function translateRectToScreen(rect, canvasDimensions, contentDimensions, centeringBehavior = 'none', scale = 1) {
    const position = translatePointToScreen(rect, canvasDimensions, contentDimensions, centeringBehavior, scale);
    const dimensions = translateDimensionsToScreen(rect, canvasDimensions, contentDimensions, scale);
    return Rectangle.fromPointAndDimensions(position, dimensions);
}
/**
 * Translates a point in screen units, to a point in relative units.
 */
export function translatePointToRelative(pt, canvasDimensions, contentDimensions = canvasDimensions, centeringBehavior = 'none', scale = 1, offset = Point.create(0, 0)) {
    const canvasToContentScaleFactor = Math.min(canvasDimensions.width / contentDimensions.width, canvasDimensions.height / contentDimensions.height);
    const effectiveScalar = canvasToContentScaleFactor * scale;
    // Include an offset for width and height to account for cases where the
    // content dimensions are smaller than the canvas dimensions.
    const scaledContentWidth = contentDimensions.width * effectiveScalar;
    const scaledContentHeight = contentDimensions.height * effectiveScalar;
    const centerOffsetX = centeringBehavior === 'both' || centeringBehavior === 'x-only'
        ? Math.max(0, (canvasDimensions.width - scaledContentWidth) / 2)
        : 0;
    const centerOffsetY = centeringBehavior === 'both' || centeringBehavior === 'y-only'
        ? Math.max(0, (canvasDimensions.height - scaledContentHeight) / 2)
        : 0;
    const pointWithoutOffset = Point.subtract(pt, Point.scale(offset, 1 / getWindowDevicePixelRatio(), 1 / getWindowDevicePixelRatio()));
    const centeredContentPoint = Point.create((pointWithoutOffset.x - centerOffsetX) / effectiveScalar, (pointWithoutOffset.y - centerOffsetY) / effectiveScalar);
    const contentScaleFactor = getScaleFactor(contentDimensions);
    const contentCenterRelativePoint = Point.subtract(centeredContentPoint, Dimensions.center(contentDimensions));
    return Point.scale(contentCenterRelativePoint, 1 / contentScaleFactor, 1 / contentScaleFactor);
}
/**
 * Translates a set of points in relative `original` units to
 * points in relative `bounds` units.
 */
export function translatePointsToBounds(points, original, bounds) {
    return points.map((pt) => Point.add(Point.scale(Point.subtract(pt, original), bounds.width / (original.width || 1), bounds.height / (original.height || 1)), bounds));
}
export function createRectangle(initialPoint, currentPoint, maintainAspectRatio) {
    const bounds = Rectangle.fromPoints(initialPoint, currentPoint);
    if (maintainAspectRatio) {
        const fitBoundsSize = Math.max(bounds.width, bounds.height);
        const isPortrait = bounds.height > bounds.width;
        const currentIsLeftOfInitial = currentPoint.x <= initialPoint.x;
        const currentIsAboveInitial = currentPoint.y <= initialPoint.y;
        const fitBoundsX = currentIsLeftOfInitial
            ? isPortrait
                ? initialPoint.x - fitBoundsSize
                : currentPoint.x
            : initialPoint.x;
        const fitBoundsY = currentIsAboveInitial
            ? isPortrait
                ? currentPoint.y
                : initialPoint.y - fitBoundsSize
            : initialPoint.y;
        return Rectangle.create(fitBoundsX, fitBoundsY, fitBoundsSize, fitBoundsSize);
    }
    else {
        return bounds;
    }
}
export function transformRectangle(bounds, start, current, anchor, maintainAspectRatio) {
    const delta = Point.subtract(current, start);
    const { x: left, y: top, width: w, height: h } = bounds;
    const right = left + w;
    const bottom = top + h;
    const topLeft = Point.create(left, top);
    const bottomLeft = Point.create(left, bottom);
    const topRight = Point.create(right, top);
    const bottomRight = Point.create(right, bottom);
    switch (anchor) {
        case 'top-left':
            return createRectangle(bottomRight, current, !!maintainAspectRatio);
        case 'top':
            return createRectangle(bottomRight, Point.create(left, current.y), !!maintainAspectRatio);
        case 'top-right':
            return createRectangle(bottomLeft, current, !!maintainAspectRatio);
        case 'right':
            return createRectangle(bottomLeft, Point.create(current.x, top), !!maintainAspectRatio);
        case 'bottom-right':
            return createRectangle(topLeft, current, !!maintainAspectRatio);
        case 'bottom':
            return createRectangle(topLeft, Point.create(right, current.y), !!maintainAspectRatio);
        case 'bottom-left':
            return createRectangle(topRight, current, !!maintainAspectRatio);
        case 'left':
            return createRectangle(bottomRight, Point.create(current.x, top), !!maintainAspectRatio);
        case 'center':
            return Rectangle.create(bounds.x + delta.x, bounds.y + delta.y, bounds.width, bounds.height);
    }
}
export function isVertexViewerMarkupElement(el) {
    return (isVertexViewerArrowMarkup(el) ||
        isVertexViewerCircleMarkup(el) ||
        isVertexViewerFreeformMarkup(el));
}
export function isValidPointData(...points) {
    return points.every((pt) => !isNaN(pt.x) && !isNaN(pt.y));
}
export function isValidStartEvent(event) {
    const el = event.target;
    return isVertexViewerMarkupElement(el) && el.mode !== 'edit';
}
function getScaleFactor(dimensions) {
    // We intentionally use the content's height when scaling to maintain a consistent coordinate
    // space for markup. This is to ensure the markup will be displayed in the same position
    // on the canvas regardless of the aspect ratio at the time the markup was created.
    // See https://github.com/Vertexvis/vertex-web-sdk/pull/429 for more details.
    return dimensions.height;
}
//# sourceMappingURL=markup-utils.js.map
