/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { isElement } from '@tylertech/forge-core';
import { PopupAnimationType, POPUP_CONSTANTS } from './popup-constants';
export class PopupFoundation {
    constructor(_adapter) {
        this._adapter = _adapter;
        this._placement = 'bottom-start';
        this._fallbackPlacements = [];
        this._open = false;
        this._manageFocus = false;
        this._animationType = PopupAnimationType.None;
        this._static = false;
        this._hideWhenClipped = false;
        this._blurListener = () => this._onBlur();
    }
    disconnect() {
        if (this.open) {
            this.open = false;
        }
    }
    _openPopup() {
        if (this._animationType !== PopupAnimationType.None) {
            this._applyOpenAnimation();
            if (this._animationType === PopupAnimationType.Dropdown) {
                this._adapter.addClass(POPUP_CONSTANTS.classes.SELECT);
            }
        }
        else {
            this._adapter.addClass(POPUP_CONSTANTS.classes.OPEN);
        }
        this._adapter.setAttribute(POPUP_CONSTANTS.attributes.OPEN, '');
        this._adapter.addPopup(this.targetElement, this._manageFocus);
        this._adapter.trySetInitialFocus();
        if (this._destroyBlurListener) {
            this._destroyBlurListener();
        }
        if (!this._static) {
            this._destroyBlurListener = this._adapter.setBlurListener(this._blurListener);
        }
        this._adapter.manageWindowEvents(true);
        this._adapter.dispatchEvent(POPUP_CONSTANTS.events.OPEN);
    }
    _closePopup() {
        if (this._destroyBlurListener) {
            this._destroyBlurListener();
            this._destroyBlurListener = undefined;
        }
        if (this._animationType !== PopupAnimationType.None) {
            this._applyCloseAnimation();
        }
        else {
            this._destroyPopup();
        }
    }
    _destroyPopup() {
        this._adapter.manageWindowEvents(false);
        this._adapter.removePopup(this._manageFocus);
        const eventData = this._adapter.getCloseEventData();
        this._adapter.dispatchEvent(POPUP_CONSTANTS.events.CLOSE, eventData);
        this._adapter.emitHostEvent(POPUP_CONSTANTS.events.CLOSE, eventData);
        this._adapter.removeAttribute(POPUP_CONSTANTS.attributes.OPEN);
    }
    _applyOpenAnimation() {
        switch (this._animationType) {
            case PopupAnimationType.Dropdown:
            case PopupAnimationType.Menu:
                this._adapter.addClass(POPUP_CONSTANTS.classes.OPENING);
                const transitionEndListener = (evt) => {
                    if (evt.propertyName === 'transform') {
                        this._adapter.removeClass(POPUP_CONSTANTS.classes.OPENING);
                        this._adapter.removeEventListener('transitionend', transitionEndListener);
                    }
                };
                this._adapter.setAnimationEndListener(transitionEndListener, POPUP_CONSTANTS.classes.OPEN);
                break;
        }
    }
    _applyCloseAnimation() {
        switch (this._animationType) {
            case PopupAnimationType.Dropdown:
            case PopupAnimationType.Menu:
                this._adapter.removeClass(POPUP_CONSTANTS.classes.OPEN);
                this._adapter.addClass(POPUP_CONSTANTS.classes.CLOSED);
                const transitionEndListener = (evt) => {
                    if (evt.propertyName === 'opacity') {
                        if (fallbackTimer) {
                            clearTimeout(fallbackTimer);
                        }
                        this._destroyPopup();
                    }
                };
                this._adapter.setAnimationEndListener(transitionEndListener);
                const fallbackTimer = setTimeout(() => this._destroyPopup(), POPUP_CONSTANTS.numbers.ANIMATION_DURATION);
                break;
        }
    }
    _onBlur() {
        const cancelled = this._adapter.dispatchEvent(POPUP_CONSTANTS.events.BLUR, undefined, true, true);
        if (!cancelled) {
            this.open = false;
        }
    }
    _applyOpen() {
        if (this._open) {
            if (!this.targetElement || !isElement(this.targetElement)) {
                throw new Error('targetElement on Popup component must be an HTMLElement');
            }
            if (typeof this._openCallback === 'function') {
                this._executeOpenCallback();
            }
            else {
                this._openPopup();
            }
        }
        else {
            if (typeof this._closeCallback === 'function') {
                this._executeCloseCallback();
            }
            else {
                this._closePopup();
            }
        }
    }
    async _executeOpenCallback() {
        try {
            if (await Promise.resolve(this._openCallback()) !== false) {
                this._openPopup();
            }
            else {
                this._open = false;
            }
        }
        catch (e) {
            this._open = false;
        }
    }
    async _executeCloseCallback() {
        try {
            if (await Promise.resolve(this._closeCallback()) !== false) {
                this._closePopup();
            }
            else {
                this._open = true;
            }
        }
        catch (e) {
            this._open = true;
        }
    }
    get targetElement() {
        return this._targetElement;
    }
    set targetElement(element) {
        if (!element || !isElement(element)) {
            throw new Error('targetElement on Popup component must be an HTMLElement');
        }
        this._targetElement = element;
    }
    get placement() {
        return this._placement;
    }
    set placement(value) {
        if (this._placement !== value) {
            this._placement = value || 'bottom-start';
            this._adapter.setAttribute(POPUP_CONSTANTS.attributes.PLACEMENT, this._placement);
        }
    }
    get fallbackPlacements() {
        return this._fallbackPlacements;
    }
    set fallbackPlacements(value) {
        this._fallbackPlacements = Array.isArray(value) ? value : [];
    }
    get open() {
        return this._open;
    }
    set open(value) {
        value = Boolean(value);
        if (this._open !== value) {
            this._open = value;
            this._applyOpen();
        }
    }
    get manageFocus() {
        return this._manageFocus;
    }
    set manageFocus(value) {
        if (this._manageFocus !== value) {
            this._manageFocus = value;
        }
    }
    get animationType() {
        return this._animationType;
    }
    set animationType(value) {
        if (this._animationType !== value) {
            this._animationType = value;
        }
    }
    get static() {
        return this._static;
    }
    set static(value) {
        if (this._static !== value) {
            this._static = value;
            if (this._static && this._destroyBlurListener) {
                this._destroyBlurListener();
                this._destroyBlurListener = undefined;
            }
        }
    }
    get hideWhenClipped() {
        return this._hideWhenClipped;
    }
    set hideWhenClipped(value) {
        if (this._hideWhenClipped !== value) {
            this._hideWhenClipped = value;
        }
    }
    get offset() {
        var _a;
        return (_a = this._offset) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
    }
    set offset(value) {
        var _a, _b;
        if (!value) {
            this._offset = undefined;
        }
        else {
            this._offset = {
                x: (_a = value.x) !== null && _a !== void 0 ? _a : 0,
                y: (_b = value.y) !== null && _b !== void 0 ? _b : 0
            };
        }
        if (this._open) {
            this._adapter.positionPopup();
        }
    }
    get openCallback() {
        return this._openCallback;
    }
    set openCallback(callback) {
        this._openCallback = callback;
    }
    get closeCallback() {
        return this._closeCallback;
    }
    set closeCallback(callback) {
        this._closeCallback = callback;
    }
    position() {
        this._adapter.positionPopup();
    }
}
