/**
 * @license
 * Copyright Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { getShadowElement, randomChars } from '@tylertech/forge-core';
import { setDefaultAria } from '../constants';
import { locateElementById } from '../core/utils/utils';
import { BaseAdapter } from '../core/base/base-adapter';
import { OVERLAY_CONSTANTS } from '../overlay';
import { TOOLTIP_CONSTANTS } from './tooltip-constants';
export class TooltipAdapter extends BaseAdapter {
    constructor(component) {
        super(component);
        this._anchorElement = null;
        this._overlayElement = null;
        this._contentElement = getShadowElement(this._component, TOOLTIP_CONSTANTS.selectors.CONTENT);
        this._arrowElement = getShadowElement(this._component, TOOLTIP_CONSTANTS.selectors.ARROW);
    }
    get anchorElement() {
        return this._anchorElement;
    }
    syncAria() {
        const role = this._component.type === 'description' ? 'tooltip' : null;
        this._component[setDefaultAria]({ role });
        this._component[setDefaultAria]({ ariaHidden: 'true' }, { setAttribute: !this._component.hasAttribute('aria-hidden') });
        if (this._anchorElement) {
            if (this._component.type === 'label' && this._anchorElement.hasAttribute('aria-labelledby')) {
                return;
            }
            if (this._component.type === 'description' && this._anchorElement.hasAttribute('aria-describedby')) {
                return;
            }
            if (!this._component.hasAttribute('id') && this._component.type !== 'presentation') {
                this._component.id = `forge-tooltip-${randomChars()}`;
            }
            switch (this._component.type) {
                case 'description':
                    this._anchorElement.setAttribute('aria-describedby', this._component.id);
                    break;
                case 'label':
                    this._anchorElement.setAttribute('aria-labelledby', this._component.id);
                    break;
            }
        }
    }
    detachAria() {
        var _a, _b, _c, _d;
        if (this._component.type === 'description' && ((_a = this._anchorElement) === null || _a === void 0 ? void 0 : _a.getAttribute('aria-describedby')) === this._component.id) {
            (_b = this._anchorElement) === null || _b === void 0 ? void 0 : _b.removeAttribute('aria-describedby');
        }
        if (this._component.type === 'label' && ((_c = this._anchorElement) === null || _c === void 0 ? void 0 : _c.getAttribute('aria-labelledby')) === this._component.id) {
            (_d = this._anchorElement) === null || _d === void 0 ? void 0 : _d.removeAttribute('aria-labelledby');
        }
    }
    setAnchorElement(element) {
        this._anchorElement = element;
    }
    tryLocateAnchorElement(id) {
        this._anchorElement = this._tryFindAnchorElement(id);
    }
    addAnchorListener(type, listener, opts) {
        var _a;
        (_a = this._anchorElement) === null || _a === void 0 ? void 0 : _a.addEventListener(type, listener, opts);
    }
    removeAnchorListener(type, listener) {
        var _a;
        (_a = this._anchorElement) === null || _a === void 0 ? void 0 : _a.removeEventListener(type, listener);
    }
    addLightDismissListener(listener) {
        var _a;
        (_a = this._overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(OVERLAY_CONSTANTS.events.LIGHT_DISMISS, listener);
    }
    removeLightDismissListener(listener) {
        var _a;
        (_a = this._overlayElement) === null || _a === void 0 ? void 0 : _a.removeEventListener(OVERLAY_CONSTANTS.events.LIGHT_DISMISS, listener);
    }
    show() {
        var _a;
        // Tooltips are shown above all content via <forge-overlay>
        // We do this by dynamically creating an overlay element and appending it to the shadow root
        // then we move the tooltip content into the overlay element so that it can be presented.
        if (!this._overlayElement) {
            this._overlayElement = document.createElement(OVERLAY_CONSTANTS.elementName);
            this._overlayElement.setAttribute('part', 'root:overlay');
        }
        this._overlayElement.placement = this._component.placement;
        this._overlayElement.anchorElement = this._anchorElement;
        this._overlayElement.arrowElement = this._arrowElement;
        this._overlayElement.offset = { mainAxis: this._component.offset };
        this._overlayElement.flip = this._component.flip;
        if (this._component.fallbackPlacements) {
            this._overlayElement.fallbackPlacements = this._component.fallbackPlacements;
        }
        if (this._component.boundaryElement) {
            this._overlayElement.boundaryElement = this._component.boundaryElement;
        }
        else if (this._component.boundary) {
            const boundaryEl = locateElementById(this._component, this._component.boundary);
            this._overlayElement.boundaryElement = boundaryEl;
        }
        else {
            this._overlayElement.boundaryElement = null;
        }
        (_a = this._component.shadowRoot) === null || _a === void 0 ? void 0 : _a.appendChild(this._overlayElement);
        this._overlayElement.appendChild(this._contentElement);
        this._overlayElement.open = true;
    }
    hide() {
        var _a, _b;
        // Move the tooltip content back into the component, and remove the overlay element to hide the tooltip visually
        // Tooltips are still accessible when hidden, so we don't need to do anything else.
        if (this._overlayElement) {
            this._overlayElement.open = false;
        }
        (_a = this._component.shadowRoot) === null || _a === void 0 ? void 0 : _a.appendChild(this._contentElement);
        (_b = this._overlayElement) === null || _b === void 0 ? void 0 : _b.remove();
    }
    /**
     * Attempts to find an element with the given id. If no element is found, the previous sibling or parent element is returned.
     *
     * For backwards compatibility we allow for `id` to be a selector string, so that is evaluated if no element is found for the id.
     */
    _tryFindAnchorElement(id) {
        var _a, _b;
        if (id) {
            const rootNode = this._component.getRootNode();
            const targetEl = (_a = rootNode.getElementById(id)) !== null && _a !== void 0 ? _a : rootNode.querySelector(id);
            if (targetEl) {
                return targetEl;
            }
        }
        return ((_b = this._component.previousElementSibling) !== null && _b !== void 0 ? _b : this._component.parentElement);
    }
}
