/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
'use strict';

var bundle = require('./bundle-BhTmftd-.js');
var bundle$1 = require('./bundle-96sYCpzz.js');

/**
 * The `PinController` is responsible for adding pin entities to the viewer canvas
 */
class PinController {
    constructor(model, mode = 'view', type = 'pin-icon', styleAttributes = undefined) {
        this.model = model;
        this.mode = mode;
        this.type = type;
        this.styleAttributes = styleAttributes;
    }
    /**
     * Registers an entity to place on the canvas and places the pin on the associated part.
     *
     * @param pin The pin entity
     * @returns A void promise
     */
    addPin(pin) {
        this.model.addPin(pin);
    }
    /**
     * Clears all entities and returns a promise that resolves with an empty list
     * of pin results.
     */
    clearPins() {
        this.model.clearPins();
    }
    /**
     * Deregisters an entity and performs a pin if this entity was
     * removed.
     *
     * @param entity The entity to remove.
     * @returns A promise that resolves with the results after removing this
     * entity.
     */
    removePin(pin) {
        this.model.removePin(pin);
    }
    /**
     * Registers a set of entities and adds a pin
     *
     * @param entities The pin entities to draw.
     * @returns A promise that resolves with the results after registering these
     * entities.
     */
    setPins(pins) {
        this.model.setPins(pins);
    }
    /**
     * Sets the set of entities to be placed with the model.
     *
     * @param pin A pin to set
     * @returns `true` if the entity has been added.
     */
    setPin(pin) {
        this.model.setPin(pin);
    }
    /**
     * Updates an existing pin
     * @param pin A pin to set
     * @returns `true` if the entity has been updated, false otherwise
     */
    updatePin(pin) {
        this.model.updatePin(pin);
    }
    /**
     * Tells the controller which pin is selected in the model
     * @param pinId
     */
    setSelectedPinId(pinId) {
        this.model.setSelectedPin(pinId);
    }
    getToolMode() {
        return this.mode;
    }
    getToolType() {
        return this.type;
    }
    setToolMode(mode) {
        this.mode = mode;
    }
    setToolType(type) {
        this.type = type;
    }
    getDraggable() {
        return this.draggable;
    }
    setDraggable(draggable) {
        this.draggable = draggable;
    }
    setPrimaryColor(color) {
        this.styleAttributes = {
            ...this.styleAttributes,
            primaryColor: color,
        };
    }
    setAccentColor(color) {
        this.styleAttributes = {
            ...this.styleAttributes,
            accentColor: color,
        };
    }
    getStyleAttributes() {
        return this.styleAttributes;
    }
    updateDraggable(draggable, worldPosition, partId) {
        if (this.draggable != null) {
            this.draggable = draggable;
        }
        const pin = this.model.getPinById(draggable.id);
        if (pin != null) {
            this.updatePin({
                ...pin,
                worldPosition,
                partId,
            });
        }
    }
}

function constrainRelativePoint(pt, range) {
    const constrainedX = Math.max(range.start, Math.min(range.end, pt.x));
    const constrainedY = Math.max(range.start, Math.min(range.end, pt.y));
    return bundle.point.create(constrainedX, constrainedY);
}
/**
 * Translates a point in relative units to a point in screen units.
 */
function translatePointToScreen(pt, canvasDimensions) {
    return bundle.point.add(bundle.point.scale(pt, canvasDimensions.width, canvasDimensions.height), bundle.dimensions.center(canvasDimensions));
}
/**
 * Translates a point in screen units to a point in relative units.
 */
function translatePointToRelative(pt, canvasDimensions, includeOffset, xOffset, yOffset) {
    const verticalScaleFactor = 1 / canvasDimensions.height;
    const horizontalScaleFactor = 1 / canvasDimensions.width;
    const canvasCenterPoint = bundle.dimensions.center(canvasDimensions);
    const point = bundle.point.scale(bundle.point.subtract(pt, canvasCenterPoint), horizontalScaleFactor, verticalScaleFactor);
    if (includeOffset) {
        const offset = bundle.point.scale(bundle.point.create(xOffset, yOffset), horizontalScaleFactor, verticalScaleFactor);
        // We want to place the label towards the center of the screen.
        // The given point corresponds to the upper left corner of the label, so increase the offset
        // when placing it to the left or above to ensure that part of the label line is visible
        const centerIsToTheRightInXDirection = canvasCenterPoint.x > pt.x;
        const xOffsetCalculated = centerIsToTheRightInXDirection
            ? offset.x
            : -3 * offset.x;
        const centerIsBelowInYDirection = canvasCenterPoint.y > pt.y;
        const yOffsetCalculated = centerIsBelowInYDirection
            ? offset.y
            : -3 * offset.y;
        const offsetPoint = bundle.point.add(point, bundle.point.create(xOffsetCalculated, yOffsetCalculated));
        return constrainRelativePoint(offsetPoint, bundle$1.range.create(-0.5, 0.5));
    }
    else {
        return constrainRelativePoint(point, bundle$1.range.create(-0.5, 0.5));
    }
}

function isTextPin(pin) {
    return (pin === null || pin === void 0 ? void 0 : pin.type) === 'text';
}
function isIconPin(pin) {
    return (pin === null || pin === void 0 ? void 0 : pin.type) === 'icon';
}
function convertColorToString(color) {
    return typeof color === 'string' ? color : bundle$1.color.toHexString(color);
}
function getPinColors(pin) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    return {
        primaryColor: ((_b = (_a = pin === null || pin === void 0 ? void 0 : pin.attributes) === null || _a === void 0 ? void 0 : _a.style) === null || _b === void 0 ? void 0 : _b.primaryColor) == null
            ? undefined
            : convertColorToString((_d = (_c = pin === null || pin === void 0 ? void 0 : pin.attributes) === null || _c === void 0 ? void 0 : _c.style) === null || _d === void 0 ? void 0 : _d.primaryColor),
        accentColor: ((_f = (_e = pin === null || pin === void 0 ? void 0 : pin.attributes) === null || _e === void 0 ? void 0 : _e.style) === null || _f === void 0 ? void 0 : _f.accentColor) == null
            ? undefined
            : convertColorToString((_h = (_g = pin === null || pin === void 0 ? void 0 : pin.attributes) === null || _g === void 0 ? void 0 : _g.style) === null || _h === void 0 ? void 0 : _h.accentColor),
    };
}
class PinModel {
    constructor() {
        this.entities = {};
        this.entityAdded = new bundle$1.EventDispatcher();
        this.entityUpdated = new bundle$1.EventDispatcher();
        this.entitiesChanged = new bundle$1.EventDispatcher();
        this.selectionChanged = new bundle$1.EventDispatcher();
    }
    /**
     * Registers an entity to be drawn in the canvas
     *
     * @param pin A pin entity to draw.
     * @returns `true` if the entity has been added.
     */
    addPin(pin, suppressEvent = false) {
        if (this.entities[pin.id] == null) {
            this.entities = {
                ...this.entities,
                [pin.id]: pin,
            };
            if (!suppressEvent) {
                this.entitiesChanged.emit(this.getPins());
                this.entityAdded.emit(pin);
            }
            return true;
        }
        else {
            return false;
        }
    }
    /**
     * Clears all registered entities from the model.
     */
    clearPins() {
        this.getPins().forEach((e) => this.removePin(e));
    }
    /**
     * Returns all the entities registered with the model.
     */
    getPins() {
        return Object.keys(this.entities).map((key) => this.entities[key]);
    }
    /**
     * Returns single entity by id if present in the model.
     */
    getPinById(id) {
        return this.entities[id];
    }
    getSelectedPinId() {
        return this.selectedPinId;
    }
    /**
     * Unregisters an entity from the model.
     *
     * @param entity The entity to remove.
     * @returns `true` if the entity was removed.
     */
    removePin(entity) {
        if (this.entities[entity.id] != null) {
            delete this.entities[entity.id];
            this.entitiesChanged.emit(this.getPins());
            return true;
        }
        else {
            return false;
        }
    }
    /**
     * Sets the set of entities to be placed with the model.
     *
     * @param entities A set of entities to draw.
     * @returns `true` if the entity has been added.
     */
    setPins(pins) {
        this.clearPins();
        pins.forEach((e) => this.addPin(e, true));
        this.entitiesChanged.emit(this.getPins());
        return true;
    }
    /**
     * Sets the set of entities to be placed with the model.
     *
     * @param pin A pin to set
     * @returns `true` if the entity has been set
     */
    setPin(pin) {
        const isNewPin = this.entities[pin.id] == null;
        this.entities = {
            ...this.entities,
            [pin.id]: pin,
        };
        this.entitiesChanged.emit(this.getPins());
        if (isNewPin) {
            this.entityAdded.emit(pin);
        }
        return true;
    }
    /**
     * Updates a pin in the model.
     *
     * @param pin A pin to update
     * @returns `true` if the entity has been updated
     */
    updatePin(pin) {
        const pinById = this.getPinById(pin.id);
        if (pinById != null) {
            this.entities = {
                ...this.entities,
                [pin.id]: pin,
            };
            this.entitiesChanged.emit(this.getPins());
            this.entityUpdated.emit(pin);
            return true;
        }
        return false;
    }
    /**
     * Registers an event listener that will be invoked when the model's
     * pin entities change.
     *
     * @param listener The listener to add.
     * @returns A disposable that can be used to remove the listener.
     */
    onEntitiesChanged(listener) {
        return this.entitiesChanged.on(listener);
    }
    /**
     * Registers an event listener that will be invoked when a new pin
     * is added to the model.
     *
     * @param listener The listener to add.
     * @returns A disposable that can be used to remove the listener.
     */
    onEntityAdded(listener) {
        return this.entityAdded.on(listener);
    }
    /**
     * Registers an event listener that will be invoked when a pin
     * is updated in the model.
     *
     * @param listener The listener to add.
     * @returns A disposable that can be used to remove the listener.
     */
    onEntityUpdated(listener) {
        return this.entityUpdated.on(listener);
    }
    /**
     * Registers an event listener that will be invoked when the model's
     * pin selection changes
     *
     * @param listener The listener to add.
     * @returns A disposable that can be used to remove the listener.
     */
    onSelectionChange(listener) {
        return this.selectionChanged.on(listener);
    }
    /**
     * Sets the selected pin id
     * @param pinId
     */
    setSelectedPin(pinId) {
        this.selectedPinId = pinId;
        this.selectionChanged.emit(this.selectedPinId);
    }
}

exports.PinController = PinController;
exports.PinModel = PinModel;
exports.getPinColors = getPinColors;
exports.isIconPin = isIconPin;
exports.isTextPin = isTextPin;
exports.translatePointToRelative = translatePointToRelative;
exports.translatePointToScreen = translatePointToScreen;
//# sourceMappingURL=model-KigpwyFZ.js.map

//# sourceMappingURL=model-KigpwyFZ.js.map