/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Popup
 */
import * as React from "react";
import { Logger } from "@itwin/core-bentley";
import { PropertyRecord, PropertyValueFormat, UiEvent, } from "@itwin/appui-abstract";
import { Orientation, Rectangle } from "@itwin/core-react";
import { offsetAndContainInContainer } from "@itwin/appui-layout-react";
import { UiFramework } from "../UiFramework";
import { CardPopup } from "./CardPopup";
import { HTMLElementPopup } from "./HTMLElementPopup";
import { InputEditorCommitHandler, InputEditorPopup } from "./InputEditorPopup";
import { KeyinPalettePopup } from "./KeyinPalettePopup";
import { ToolbarPopup } from "./ToolbarPopup";
import { ToolSettingsPopup } from "./ToolSettingsPopup";
/** Popups Changed Event class.
 * @public
 */
export class PopupsChangedEvent extends UiEvent {
}
/** ReactContent type guard.
 * @internal
 */
export const isReactContent = (content) => {
    return content.reactNode !== undefined;
};
/** Popup Manager class
 * @public
 */
class PopupManager {
    static get popupCount() {
        return this._popups.length;
    }
    static get popups() {
        return this._popups;
    }
    static set popups(popups) {
        // istanbul ignore if
        if (this._popups === popups)
            return;
        this._popups = popups;
        this.onPopupsChangedEvent.emit({ popups });
    }
    /** @internal */
    static clearPopups() {
        this.popups = [];
    }
    static addPopup(popupInfo) {
        const popups = [...PopupManager._popups, popupInfo];
        this.popups = popups;
    }
    static updatePopup(popupInfo, itemIndex) {
        // istanbul ignore if
        if (itemIndex < 0)
            return;
        const popups = [
            ...PopupManager._popups.slice(0, itemIndex),
            popupInfo,
            ...PopupManager._popups.slice(itemIndex + 1),
        ];
        this.popups = popups;
    }
    static addOrUpdatePopup(popupInfo) {
        const itemIndex = PopupManager._popups.findIndex((info) => info.id === popupInfo.id);
        if (itemIndex >= 0)
            PopupManager.updatePopup(popupInfo, itemIndex);
        else
            PopupManager.addPopup(popupInfo);
    }
    static removePopup(id) {
        const index = PopupManager._popups.findIndex((info) => id === info.id);
        let result = true;
        if (index >= 0) {
            const popups = PopupManager._popups.filter((info) => {
                return info.id !== id;
            });
            this.popups = popups;
        }
        else {
            Logger.logError(UiFramework.loggerCategory(this), `removePopup: Could not find popup with id of '${id}'`);
            result = false;
        }
        return result;
    }
    static get defaultOffset() {
        return PopupManager._defaultOffset;
    }
    static set defaultOffset(offset) {
        PopupManager._defaultOffset = offset;
    }
    static showInputEditor(el, pt, value, propertyDescription, onCommit, onCancel) {
        const primitiveValue = {
            value,
            valueFormat: PropertyValueFormat.Primitive,
        };
        const record = new PropertyRecord(primitiveValue, propertyDescription);
        const commitHandler = new InputEditorCommitHandler(onCommit);
        const id = PopupManager._editorId;
        const component = (React.createElement(InputEditorPopup, { id: id, el: el, pt: pt, offset: PopupManager.defaultOffset, record: record, onCancel: onCancel, commitHandler: commitHandler }));
        const popupInfo = {
            id,
            pt,
            component,
            parentDocument: el.ownerDocument,
        };
        PopupManager.addOrUpdatePopup(popupInfo);
        return true;
    }
    static hideInputEditor() {
        return PopupManager.removePopup(PopupManager._editorId);
    }
    static showKeyinPalette(keyins, el, onItemExecuted, onCancel) {
        const id = PopupManager._keyPalettePopupId;
        const component = (React.createElement(KeyinPalettePopup, { keyins: keyins, id: id, el: el, onCancel: onCancel, onItemExecuted: onItemExecuted }));
        // since the command palette popup is always at top center of specified HTML element and it does not need to move like
        // cursor popups just set pt to 0,0.
        const pt = { x: 0, y: 0 };
        const popupInfo = {
            id,
            pt,
            component,
            parentDocument: el.ownerDocument,
        };
        PopupManager.addOrUpdatePopup(popupInfo);
        return true;
    }
    static hideKeyinPalette() {
        return PopupManager.removePopup(PopupManager._keyPalettePopupId);
    }
    static showToolbar(toolbarProps, el, pt, offset, onItemExecuted, onCancel, relativePosition) {
        const id = PopupManager._toolbarId;
        const component = (React.createElement(ToolbarPopup, { id: id, el: el, pt: pt, offset: offset, items: toolbarProps.items, relativePosition: relativePosition, orientation: Orientation.Horizontal, onCancel: onCancel, onItemExecuted: onItemExecuted }));
        const popupInfo = {
            id,
            pt,
            component,
            parentDocument: el.ownerDocument,
        };
        PopupManager.addOrUpdatePopup(popupInfo);
        return true;
    }
    static hideToolbar() {
        return PopupManager.removePopup(PopupManager._toolbarId);
    }
    static showHTMLElement(displayElement, el, pt, offset, onCancel, relativePosition) {
        const id = PopupManager._htmlElementId;
        const component = (React.createElement(HTMLElementPopup, { id: id, el: el, pt: pt, offset: offset, element: displayElement, relativePosition: relativePosition, orientation: Orientation.Horizontal, onCancel: onCancel }));
        const popupInfo = {
            id,
            pt,
            component,
            parentDocument: el.ownerDocument,
        };
        PopupManager.addOrUpdatePopup(popupInfo);
        return true;
    }
    static hideHTMLElement() {
        return PopupManager.removePopup(PopupManager._htmlElementId);
    }
    static showCard(content, title, toolbarProps, el, pt, offset, onItemExecuted, onCancel, relativePosition) {
        const id = PopupManager._cardId;
        const component = (React.createElement(CardPopup, { id: id, el: el, pt: pt, offset: offset, content: content, title: title, items: toolbarProps
                ? toolbarProps.items
                : /* istanbul ignore next */ undefined, relativePosition: relativePosition, orientation: Orientation.Horizontal, onCancel: onCancel, onItemExecuted: onItemExecuted }));
        const popupInfo = {
            id,
            pt,
            component,
            parentDocument: el.ownerDocument,
        };
        PopupManager.addOrUpdatePopup(popupInfo);
        return true;
    }
    static hideCard() {
        const index = PopupManager._popups.findIndex((info) => PopupManager._cardId === info.id);
        if (index >= 0)
            return PopupManager.removePopup(PopupManager._cardId);
        return false;
    }
    static openToolSettings(dataProvider, el, pt, offset, onCancel, relativePosition) {
        const id = PopupManager._toolSettingsId;
        const component = (React.createElement(ToolSettingsPopup, { id: id, el: el, pt: pt, offset: offset, dataProvider: dataProvider, relativePosition: relativePosition, orientation: Orientation.Horizontal, onCancel: onCancel }));
        const popupInfo = {
            id,
            pt,
            component,
            parentDocument: el.ownerDocument,
        };
        PopupManager.addOrUpdatePopup(popupInfo);
        return true;
    }
    static closeToolSettings() {
        return PopupManager.removePopup(PopupManager._toolSettingsId);
    }
    static getPopupPosition(el, pt, offset, size) {
        const containerBounds = Rectangle.create(el.getBoundingClientRect());
        const relativeBounds = Rectangle.createFromSize(size).offset(pt);
        const adjustedPosition = offsetAndContainInContainer(relativeBounds, containerBounds.getSize(), offset);
        const position = adjustedPosition.offset(containerBounds.topLeft());
        return position;
    }
}
PopupManager._popups = [];
PopupManager._editorId = "InputEditor";
PopupManager._toolbarId = "Toolbar";
PopupManager._htmlElementId = "HTMLElement";
PopupManager._cardId = "Card";
PopupManager._toolSettingsId = "ToolSettings";
PopupManager._keyPalettePopupId = "KeyinPalette";
PopupManager._defaultOffset = { x: 8, y: 8 };
PopupManager.onPopupsChangedEvent = new PopupsChangedEvent();
export { PopupManager };
/**  Popup Renderer
 * @public
 */
export class PopupRenderer extends React.Component {
    constructor() {
        super(...arguments);
        /** @internal */
        this.state = {
            parentDocument: null,
            popups: PopupManager.popups,
        };
        this._handleRefSet = (popupDiv) => {
            this.setState({ parentDocument: popupDiv?.ownerDocument ?? null });
        };
        this._handlePopupsChangedEvent = (args) => {
            this.setState({ popups: args.popups });
        };
    }
    componentDidMount() {
        PopupManager.onPopupsChangedEvent.addListener(this._handlePopupsChangedEvent);
    }
    componentWillUnmount() {
        PopupManager.onPopupsChangedEvent.removeListener(this._handlePopupsChangedEvent);
    }
    render() {
        if (PopupManager.popupCount <= 0)
            return null;
        return (React.createElement("div", { className: "appui-react-popup-render-container", ref: this._handleRefSet }, this.state.parentDocument &&
            this.state.popups
                .filter((info) => info.parentDocument === this.state.parentDocument)
                .map((popupInfo) => {
                return (React.createElement(React.Fragment, { key: popupInfo.id }, popupInfo.component));
            })));
    }
}
//# sourceMappingURL=PopupManager.js.map