/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { addClass, closestElement, emitEvent, getShadowElement, notChildEventListener, positionElementAsync, removeClass, removeElement, deepQuerySelectorAll, getActiveElement } from '@tylertech/forge-core';
import { BaseAdapter } from '../core/base/base-adapter';
import { POPUP_CONSTANTS } from './popup-constants';
export class PopupAdapter extends BaseAdapter {
    constructor(component) {
        super(component);
        this._rootElement = getShadowElement(component, POPUP_CONSTANTS.selectors.CONTAINER);
    }
    setAttribute(attribute, value, element) {
        if (element) {
            element.setAttribute(attribute, value);
        }
        else {
            this._component.setAttribute(attribute, value);
        }
    }
    removeAttribute(attribute, element) {
        if (element) {
            element.removeAttribute(attribute);
        }
        else {
            this._component.removeAttribute(attribute);
        }
    }
    async positionPopup() {
        const config = {
            element: this._component,
            targetElement: this._component.targetElement,
            placement: this._component.placement,
            hide: this._component.hideWhenClipped,
            flipOptions: {
                fallbackPlacements: ['top-start', 'top', 'top-end', 'left-start', 'left', 'left-end', 'right-start', 'right', 'right-end'],
                fallbackStrategy: 'initialPlacement'
            }
        };
        const fallbackPlacements = this._component.fallbackPlacements;
        if (fallbackPlacements === null || fallbackPlacements === void 0 ? void 0 : fallbackPlacements.length) {
            config.flipOptions = Object.assign(Object.assign({}, config.flipOptions), { fallbackPlacements });
        }
        if (this._component.offset) {
            config.offset = this._component.offset;
        }
        const data = await positionElementAsync(config);
        emitEvent(this._component, POPUP_CONSTANTS.events.POSITION, data);
    }
    addPopup(targetElement, manageFocus) {
        this._component.setAttribute('tabindex', '-1');
        this._component.setAttribute(POPUP_CONSTANTS.attributes.HOST, '');
        // Set initial position to top-left of the host element while we wait for positioning.
        // This ensures that the element is not visible, nor does it affect layouts before it
        // is properly moved into its expected location.
        this._component.style.top = '0';
        this._component.style.left = '0';
        const hostDocument = targetElement.ownerDocument || document;
        this._hostElement = closestElement(POPUP_CONSTANTS.selectors.HOST, targetElement) || hostDocument.body;
        this._hostElement.appendChild(this._component);
        this.positionPopup();
        if (manageFocus) {
            this._previouslyFocusedElement = getActiveElement(this._component.ownerDocument);
            this._component.focus();
        }
    }
    removePopup(manageFocus) {
        removeElement(this._component);
        if (manageFocus) {
            window.requestAnimationFrame(() => {
                if (this._previouslyFocusedElement) {
                    const activeElement = getActiveElement(this._component.ownerDocument);
                    if (!activeElement || activeElement === document.body) {
                        this._previouslyFocusedElement.focus();
                    }
                    this._previouslyFocusedElement = undefined;
                }
            });
        }
        this._hostElement = undefined;
    }
    manageWindowEvents(add = false) {
        if (add) {
            this._windowEventCallback = evt => this._windowInteraction(evt);
            window.addEventListener('scroll', this._windowEventCallback, true);
            window.addEventListener('resize', this._windowEventCallback, true);
        }
        else {
            if (this._windowEventCallback) {
                window.removeEventListener('scroll', this._windowEventCallback, true);
                window.removeEventListener('resize', this._windowEventCallback, true);
                this._windowEventCallback = undefined;
            }
        }
    }
    dispatchEvent(type, data, bubbles, cancelable) {
        if (this._component.targetElement) {
            return !emitEvent(this._component.targetElement, type, data, bubbles, cancelable);
        }
        return false;
    }
    getCloseEventData() {
        return { popup: this._component };
    }
    addClass(classes) {
        addClass(classes, this._rootElement);
    }
    removeClass(classes) {
        removeClass(classes, this._rootElement);
    }
    setAnimationEndListener(listener, classes) {
        window.requestAnimationFrame(() => {
            if (classes && classes.length) {
                addClass(classes, this._rootElement);
            }
            this._rootElement.addEventListener('transitionend', listener);
        });
    }
    removeEventListener(type, listener) {
        this._rootElement.removeEventListener(type, listener);
    }
    setBlurListener(listener) {
        return notChildEventListener(this._component, activeElement => {
            if (!this._component.contains(activeElement)) {
                listener();
            }
        }, true);
    }
    trySetInitialFocus() {
        window.requestAnimationFrame(() => {
            const elements = deepQuerySelectorAll(this._component, POPUP_CONSTANTS.selectors.INITIAL_FOCUS);
            if (elements && elements.length) {
                const initialElement = elements[elements.length - 1];
                initialElement.focus();
            }
        });
    }
    _windowInteraction(evt) {
        if (!this._component.open) {
            return;
        }
        switch (evt.type) {
            case 'scroll':
            case 'resize':
                this.positionPopup();
                break;
            default:
                break;
        }
    }
}
