/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { calculateFontWidth, getShadowElement, toggleClass, toggleAttribute } from '@tylertech/forge-core';
import { FloatingLabel } from '../../floating-label/floating-label';
import { SELECT_CONSTANTS } from './select-constants';
import { BaseSelectAdapter } from '../core';
import { FIELD_CONSTANTS } from '../../field/field-constants';
import { tryCreateAriaControlsPlaceholder, setAriaControls } from '../../core/utils';
/**
 * The DOM adapter behind the `<forge-select>` component.
 */
export class SelectAdapter extends BaseSelectAdapter {
    constructor(component) {
        super(component);
        this._selectElement = getShadowElement(component, SELECT_CONSTANTS.selectors.ROOT);
        this._leadingSlot = getShadowElement(component, SELECT_CONSTANTS.selectors.LEADING_SLOT);
        this._addonEndSlot = getShadowElement(this._component, SELECT_CONSTANTS.selectors.ADDON_END_SLOT);
        this._selectedTextElement = getShadowElement(component, SELECT_CONSTANTS.selectors.SELECTED_TEXT);
        this._targetElement = this._selectElement;
    }
    initializeLabel() {
        this._labelElement = getShadowElement(this._component, SELECT_CONSTANTS.selectors.LABEL);
    }
    hasLabel() {
        return !!this._labelElement;
    }
    initializeAccessibility() {
        this._component.setAttribute('role', 'combobox');
        this._component.setAttribute('aria-haspopup', 'true');
        this._component.setAttribute('aria-expanded', 'false');
        tryCreateAriaControlsPlaceholder();
        setAriaControls(this._component);
        // We need to ensure the host element receives a non-negative tabindex for our interactions to work properly
        if (!this._component.hasAttribute('tabindex') || this._component.tabIndex === -1) {
            this._component.tabIndex = 0;
        }
    }
    initializeFloatingLabel() {
        return new FloatingLabel(this._labelElement);
    }
    setLabel(value) {
        if (!this._component.hasAttribute('aria-label') || this._component.getAttribute('aria-label') === this._labelElement.textContent) {
            this._component.setAttribute('aria-label', value);
        }
        this._labelElement.textContent = value;
    }
    addRootClass(name) {
        this._selectElement.classList.add(name);
    }
    removeRootClass(name) {
        this._selectElement.classList.remove(name);
    }
    setPlaceholderText(value) {
        toggleAttribute(this._selectedTextElement, !!value, 'placeholder', value);
    }
    addClickListener(listener) {
        this._component.addEventListener('click', listener);
    }
    removeClickListener(listener) {
        this._component.removeEventListener('click', listener);
    }
    addMouseDownListener(listener) {
        this._component.addEventListener('mousedown', listener);
    }
    removeMouseDownListener(listener) {
        this._component.removeEventListener('mousedown', listener);
    }
    addTargetListener(type, listener) {
        this._component.addEventListener(type, listener);
    }
    removeTargetListener(type, listener) {
        this._component.removeEventListener(type, listener);
    }
    open(config) {
        super.open(config);
        this._component.setAttribute('aria-controls', `list-dropdown-popup-${config.id}`);
        this._component.setAttribute('aria-expanded', 'true');
        toggleClass(this._selectElement, true, SELECT_CONSTANTS.classes.OPENED);
    }
    close() {
        this._component.setAttribute('aria-expanded', 'false');
        this._component.removeAttribute('aria-activedescendant');
        setAriaControls(this._component);
        toggleClass(this._selectElement, false, SELECT_CONSTANTS.classes.OPENED);
        super.close();
    }
    updateActiveDescendant(id) {
        toggleAttribute(this._component, !!id, 'aria-activedescendant', id);
    }
    setSelectedText(value) {
        this._selectedTextElement.textContent = value;
    }
    setLeadingListener(listener) {
        this._leadingSlot.addEventListener('slotchange', listener);
    }
    removeLeadingListener(listener) {
        this._leadingSlot.removeEventListener('slotchange', listener);
    }
    setAddonEndListener(listener) {
        this._addonEndSlot.addEventListener('slotchange', listener);
    }
    removeAddonEndListener(listener) {
        this._addonEndSlot.removeEventListener('slotchange', listener);
    }
    hasLeadingElement() {
        return this._leadingSlot.assignedNodes().length > 0;
    }
    setDisabled(isDisabled) {
        toggleClass(this._selectElement, isDisabled, FIELD_CONSTANTS.classes.DISABLED);
        toggleAttribute(this._component, isDisabled, 'aria-disabled', 'true');
        this._component.tabIndex = isDisabled ? -1 : 0;
    }
    setInvalid(isInvalid) {
        toggleClass(this._selectElement, isInvalid, FIELD_CONSTANTS.classes.INVALID);
        toggleAttribute(this._component, isInvalid, 'aria-invalid', 'true');
    }
    setRequired(isRequired) {
        toggleClass(this._selectElement, isRequired, FIELD_CONSTANTS.classes.REQUIRED);
        toggleAttribute(this._component, isRequired, 'aria-required', 'true');
    }
    setRoomy(isRoomy) {
        toggleClass(this._selectElement, isRoomy, FIELD_CONSTANTS.classes.ROOMY);
    }
    setDense(isDense) {
        toggleClass(this._selectElement, isDense, FIELD_CONSTANTS.classes.DENSE);
    }
    getLabelWidth(fontSize, fontFamily) {
        return calculateFontWidth(this._labelElement.innerText, { fontSize, fontFamily });
    }
    getLabelFontMetrics() {
        const style = getComputedStyle(this._labelElement);
        return {
            fontSize: parseInt(style.fontSize || '16', 10),
            fontFamily: style.fontFamily || 'Roboto'
        };
    }
    getTargetWidth() {
        return this._selectElement.getBoundingClientRect().width;
    }
    hasAddonEndNodes() {
        if (!this._addonEndSlot) {
            return false;
        }
        return this._addonEndSlot.assignedNodes().length > 0;
    }
    setFocus() {
        this._component.focus();
    }
    isWithinSelf(element) {
        const isShadowChild = !!this._component.shadowRoot && this._component.shadowRoot.contains(element);
        return isShadowChild || this._component.contains(element);
    }
}
