"use strict";
/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Cursor
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.CursorPopupRenderer = exports.CursorPopupManager = void 0;
const React = require("react");
const core_bentley_1 = require("@itwin/core-bentley");
const appui_abstract_1 = require("@itwin/appui-abstract");
const core_react_1 = require("@itwin/core-react");
const UiFramework_1 = require("../../UiFramework");
const CursorPopup_1 = require("./CursorPopup");
/** CursorPopup component
 * @public
 */
class CursorPopupManager {
    /** @internal */
    static clearPopups() {
        this._popups.length = 0;
        CursorPopupManager._emitPopupsChangedEvent();
    }
    static get popups() {
        return this._popups;
    }
    static get popupCount() {
        return this._popups.length;
    }
    static _emitPopupsChangedEvent() {
        CursorPopupManager.onCursorPopupsChangedEvent.emit({});
    }
    static pushPopup(popupInfo) {
        CursorPopupManager._popups.push(popupInfo);
        CursorPopupManager._emitPopupsChangedEvent();
    }
    /** Called to open popup with a new set of properties
     */
    static open(id, content, pt, offset, relativePosition, priority = 0, options) {
        const popupInfo = CursorPopupManager._popups.find((info) => id === info.id);
        if (popupInfo) {
            popupInfo.content = content;
            popupInfo.offset = core_react_1.Point.create(offset);
            popupInfo.relativePosition = relativePosition;
            popupInfo.renderRelativePosition = relativePosition;
            popupInfo.priority = priority;
            popupInfo.options = options;
        }
        else {
            const newPopupInfo = {
                id,
                content,
                offset: core_react_1.Point.create(offset),
                relativePosition,
                options,
                renderRelativePosition: relativePosition,
                priority,
            };
            CursorPopupManager.pushPopup(newPopupInfo);
        }
        CursorPopupManager.updatePosition(pt);
    }
    /** Called to update popup with a new set of properties
     */
    static update(id, content, pt, offset, relativePosition, priority = 0) {
        const popupInfo = CursorPopupManager._popups.find((info) => id === info.id);
        if (popupInfo) {
            popupInfo.content = content;
            popupInfo.offset = core_react_1.Point.create(offset);
            popupInfo.relativePosition = relativePosition;
            popupInfo.renderRelativePosition = relativePosition;
            popupInfo.priority = priority;
        }
        else {
            core_bentley_1.Logger.logError(UiFramework_1.UiFramework.loggerCategory(this), `update: Could not find popup with id of '${id}'`);
        }
        CursorPopupManager.updatePosition(pt);
    }
    /** Called to move the open popup to new location
     */
    static updatePosition(pt) {
        CursorPopupManager.resetPopupsRenderRelativePosition(core_react_1.Point.create(pt));
        CursorPopupManager.onCursorPopupUpdatePositionEvent.emit({ pt });
    }
    /** Called when tool wants to close the popup
     */
    static close(id, apply, fadeOut) {
        const popupInfo = CursorPopupManager._popups.find((info) => id === info.id);
        if (popupInfo) {
            if (popupInfo.options) {
                if (apply && popupInfo.options.onApply)
                    popupInfo.options.onApply();
                if (popupInfo.options.onClose)
                    popupInfo.options.onClose();
            }
            if (fadeOut) {
                CursorPopupManager.onCursorPopupFadeOutEvent.emit({ id });
                setTimeout(() => {
                    CursorPopupManager.removePopup(id);
                }, CursorPopup_1.CursorPopup.fadeOutTime);
            }
            else {
                CursorPopupManager.removePopup(id);
            }
        }
        else {
            core_bentley_1.Logger.logError(UiFramework_1.UiFramework.loggerCategory(this), `close: Could not find popup with id of '${id}'`);
        }
    }
    static removePopup(id) {
        const index = CursorPopupManager._popups.findIndex((popupInfo) => id === popupInfo.id);
        if (index >= 0) {
            CursorPopupManager._popups.splice(index, 1);
            CursorPopupManager._emitPopupsChangedEvent();
        }
    }
    static resetPopupsRenderRelativePosition(pt) {
        CursorPopupManager.popups.forEach((popupInfo) => {
            popupInfo.renderRelativePosition = popupInfo.relativePosition;
            const flipped = CursorPopupManager.validateRenderRelativePosition(pt, popupInfo);
            // If flipped, call again to validate again.
            if (flipped) {
                CursorPopupManager.validateRenderRelativePosition(pt, popupInfo);
            }
        });
    }
    static validateRenderRelativePosition(pt, popupInfo) {
        const popupRect = CursorPopup_1.CursorPopup.getPopupRect(pt, core_react_1.Point.create(popupInfo.offset), popupInfo.popupSize, popupInfo.renderRelativePosition);
        const { outPos, flipped } = CursorPopupManager.autoFlip(popupInfo.renderRelativePosition, popupRect, window.innerWidth, window.innerHeight);
        if (flipped)
            popupInfo.renderRelativePosition = outPos;
        return flipped;
    }
    static autoFlip(inPos, rect, windowWidth, windowHeight) {
        let flipped = false;
        let outPos = inPos;
        if (rect.right > windowWidth) {
            flipped = true;
            switch (inPos) {
                case appui_abstract_1.RelativePosition.Top:
                case appui_abstract_1.RelativePosition.TopRight:
                    outPos = appui_abstract_1.RelativePosition.TopLeft;
                    break;
                case appui_abstract_1.RelativePosition.Right:
                    outPos = appui_abstract_1.RelativePosition.Left;
                    break;
                case appui_abstract_1.RelativePosition.Bottom:
                case appui_abstract_1.RelativePosition.BottomRight:
                    outPos = appui_abstract_1.RelativePosition.BottomLeft;
                    break;
            }
        }
        if (rect.left < 0) {
            flipped = true;
            switch (inPos) {
                case appui_abstract_1.RelativePosition.Top:
                case appui_abstract_1.RelativePosition.TopLeft:
                    outPos = appui_abstract_1.RelativePosition.TopRight;
                    break;
                case appui_abstract_1.RelativePosition.Left:
                    outPos = appui_abstract_1.RelativePosition.Right;
                    break;
                case appui_abstract_1.RelativePosition.Bottom:
                case appui_abstract_1.RelativePosition.BottomLeft:
                    outPos = appui_abstract_1.RelativePosition.BottomRight;
                    break;
            }
        }
        if (rect.bottom > windowHeight) {
            flipped = true;
            switch (inPos) {
                case appui_abstract_1.RelativePosition.Left:
                case appui_abstract_1.RelativePosition.BottomLeft:
                    outPos = appui_abstract_1.RelativePosition.TopLeft;
                    break;
                case appui_abstract_1.RelativePosition.Bottom:
                    outPos = appui_abstract_1.RelativePosition.Top;
                    break;
                case appui_abstract_1.RelativePosition.Right:
                case appui_abstract_1.RelativePosition.BottomRight:
                    outPos = appui_abstract_1.RelativePosition.TopRight;
                    break;
            }
        }
        if (rect.top < 0) {
            flipped = true;
            switch (inPos) {
                case appui_abstract_1.RelativePosition.Left:
                case appui_abstract_1.RelativePosition.TopLeft:
                    outPos = appui_abstract_1.RelativePosition.BottomLeft;
                    break;
                case appui_abstract_1.RelativePosition.Top:
                    outPos = appui_abstract_1.RelativePosition.Bottom;
                    break;
                case appui_abstract_1.RelativePosition.Right:
                case appui_abstract_1.RelativePosition.TopRight:
                    outPos = appui_abstract_1.RelativePosition.BottomRight;
                    break;
            }
        }
        return { outPos, flipped };
    }
}
exports.CursorPopupManager = CursorPopupManager;
CursorPopupManager._popups = new Array();
/** @internal */
CursorPopupManager.onCursorPopupUpdatePositionEvent = new core_bentley_1.BeUiEvent();
/** @internal */
CursorPopupManager.onCursorPopupFadeOutEvent = new core_bentley_1.BeUiEvent();
/** @internal */
CursorPopupManager.onCursorPopupsChangedEvent = new core_bentley_1.BeUiEvent();
/** CursorPopupRenderer React component.
 * @public
 */
class CursorPopupRenderer extends React.Component {
    constructor(props) {
        super(props);
        this._handlePopupChangedEvent = (_args) => {
            this.forceUpdate();
        };
        this._handleCursorPopupUpdatePositionEvent = (args) => {
            this.setState({ pt: core_react_1.Point.create(args.pt) });
        };
        this.state = {
            pt: new core_react_1.Point(),
        };
    }
    render() {
        if (CursorPopupManager.popupCount <= 0)
            return null;
        return React.createElement(React.Fragment, null, this.renderPositions());
    }
    _handleSizeKnown(popupInfo, size) {
        popupInfo.popupSize = core_react_1.Size.create(size);
    }
    renderPositions() {
        const positions = new Array();
        let renderedPosition;
        const begin = appui_abstract_1.RelativePosition.Left;
        const end = appui_abstract_1.RelativePosition.BottomRight;
        for (let position = begin; position <= end; position++) {
            renderedPosition = this.renderRelativePosition(position);
            if (renderedPosition)
                positions.push(renderedPosition);
        }
        return positions;
    }
    renderRelativePosition(relativePosition) {
        const filteredInfo = CursorPopupManager.popups.filter((popupInfo) => popupInfo.renderRelativePosition === relativePosition);
        if (filteredInfo.length > 0) {
            let totalDimension = 0;
            const ascending = relativePosition === appui_abstract_1.RelativePosition.Right ||
                relativePosition === appui_abstract_1.RelativePosition.BottomRight ||
                relativePosition === appui_abstract_1.RelativePosition.Bottom ||
                relativePosition === appui_abstract_1.RelativePosition.BottomLeft;
            const positionPopups = filteredInfo
                .sort((a, b) => ascending ? a.priority - b.priority : b.priority - a.priority)
                .map((popupInfo, index) => {
                const title = popupInfo.options !== undefined ? popupInfo.options.title : "";
                const shadow = popupInfo.options !== undefined ? popupInfo.options.shadow : false;
                let offset = popupInfo.offset;
                if (index > 0)
                    offset = this.adjustOffset(offset, popupInfo.renderRelativePosition, totalDimension);
                if (popupInfo.popupSize)
                    totalDimension += this.getDimension(popupInfo.popupSize, relativePosition);
                return (React.createElement(CursorPopup_1.CursorPopup, { key: popupInfo.id, id: popupInfo.id, content: popupInfo.content, pt: this.state.pt, offset: offset, relativePosition: popupInfo.renderRelativePosition, title: title, shadow: shadow, onSizeKnown: (size) => this._handleSizeKnown(popupInfo, size) }));
            });
            return (React.createElement(React.Fragment, { key: relativePosition.toString() }, positionPopups));
        }
        return null;
    }
    getDimension(popupSize, relativePosition) {
        let dimension = 0;
        switch (relativePosition) {
            case appui_abstract_1.RelativePosition.Top:
            case appui_abstract_1.RelativePosition.Bottom:
            case appui_abstract_1.RelativePosition.TopLeft:
            case appui_abstract_1.RelativePosition.TopRight:
            case appui_abstract_1.RelativePosition.BottomLeft:
            case appui_abstract_1.RelativePosition.BottomRight:
                dimension = popupSize.height;
                break;
            case appui_abstract_1.RelativePosition.Left:
            case appui_abstract_1.RelativePosition.Right:
                dimension = popupSize.width;
                break;
        }
        return dimension;
    }
    adjustOffset(offset, relativePosition, dimension) {
        let outOffset = core_react_1.Point.create(offset.toProps());
        switch (relativePosition) {
            case appui_abstract_1.RelativePosition.Top:
            case appui_abstract_1.RelativePosition.Bottom:
            case appui_abstract_1.RelativePosition.TopLeft:
            case appui_abstract_1.RelativePosition.TopRight:
            case appui_abstract_1.RelativePosition.BottomLeft:
            case appui_abstract_1.RelativePosition.BottomRight:
                outOffset = core_react_1.Point.create({ x: offset.x, y: offset.y + dimension });
                break;
            case appui_abstract_1.RelativePosition.Left:
            case appui_abstract_1.RelativePosition.Right:
                outOffset = core_react_1.Point.create({ x: offset.x + dimension, y: offset.y });
                break;
        }
        return outOffset;
    }
    componentDidMount() {
        CursorPopupManager.onCursorPopupsChangedEvent.addListener(this._handlePopupChangedEvent);
        CursorPopupManager.onCursorPopupUpdatePositionEvent.addListener(this._handleCursorPopupUpdatePositionEvent);
    }
    componentWillUnmount() {
        CursorPopupManager.onCursorPopupsChangedEvent.removeListener(this._handlePopupChangedEvent);
        CursorPopupManager.onCursorPopupUpdatePositionEvent.removeListener(this._handleCursorPopupUpdatePositionEvent);
    }
}
exports.CursorPopupRenderer = CursorPopupRenderer;
//# sourceMappingURL=CursorPopupManager.js.map