/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { addClass, calculateFontWidth, getShadowElement, listenOwnProperty, removeClass, getActiveElement, createElementAttributeObserver, toggleClass } from '@tylertech/forge-core';
import { BaseAdapter } from '../core/base/base-adapter';
import { FloatingLabel } from '../floating-label/floating-label';
import { FIELD_CONSTANTS } from './field-constants';
export class FieldAdapter extends BaseAdapter {
    constructor(component) {
        super(component);
        this._valueChangeListeners = [];
    }
    initialize(rootSelector) {
        this._rootElement = getShadowElement(this._component, rootSelector);
        this._labelSlot = getShadowElement(this._component, 'slot[name=label]');
        this._leadingSlot = getShadowElement(this._component, 'slot[name=leading]');
        this._trailingSlot = getShadowElement(this._component, 'slot[name=trailing]');
        this._addonEndSlot = getShadowElement(this._component, 'slot[name=addon-end]');
        this._inputElement = this._component.querySelector('input:not([type=checkbox]):not([type=radio])');
        this.detectLabel();
    }
    destroy() {
        if (this._inputMutationObserver) {
            this._inputMutationObserver.disconnect();
        }
    }
    hasLabel() {
        return !!this._labelElement;
    }
    ensureSlottedLabel() {
        this._labelElement.slot = 'label';
    }
    addLabelSlotListener(listener) {
        this._labelSlot.addEventListener('slotchange', listener);
    }
    removeLabelSlotListener(listener) {
        if (this._labelSlot) {
            this._labelSlot.removeEventListener('slotchange', listener);
        }
    }
    addLeadingSlotListener(listener) {
        this._leadingSlot.addEventListener('slotchange', listener);
    }
    removeLeadingSlotListener(listener) {
        if (this._leadingSlot) {
            this._leadingSlot.removeEventListener('slotchange', listener);
        }
    }
    addTrailingSlotListener(listener) {
        this._trailingSlot.addEventListener('slotchange', listener);
    }
    removeTrailingSlotListener(listener) {
        if (this._trailingSlot) {
            this._trailingSlot.removeEventListener('slotchange', listener);
        }
    }
    addAddonEndSlotListener(listener) {
        this._addonEndSlot.addEventListener('slotchange', listener);
    }
    removeAddonEndSlotListener(listener) {
        if (this._addonEndSlot) {
            this._addonEndSlot.removeEventListener('slotchange', listener);
        }
    }
    addInputListener(type, listener) {
        this._inputElement.addEventListener(type, listener);
    }
    removeInputListener(type, listener) {
        if (this._inputElement) {
            this._inputElement.removeEventListener(type, listener);
        }
    }
    setValueChangedListener(context, listener) {
        this.destroyValueChangeListener();
        const destroyListener = listenOwnProperty(context, this._inputElement, 'value', listener);
        this._valueChangeListeners.push(destroyListener);
    }
    destroyValueChangeListener() {
        this._valueChangeListeners.forEach(cb => cb());
    }
    detectLabel() {
        this._labelElement = this._component.querySelector('label');
    }
    initializeFloatingLabel() {
        return new FloatingLabel(this._labelElement);
    }
    inputHasValue() {
        return this._inputElement.value ? this._inputElement.value.trim().length > 0 : false;
    }
    // An overrideable method for more generic field values where input.value is not the value.
    fieldHasValue() {
        return this.inputHasValue();
    }
    hasPlaceholder() {
        return this._inputElement.placeholder ? this._inputElement.placeholder.trim().length > 0 : false;
    }
    inputHasFocus(target) {
        return this._inputElement === target || this._inputElement === getActiveElement(this._component.ownerDocument);
    }
    setLabelClass(name) {
        if (this._labelElement) {
            this._labelElement.classList.add(name);
        }
    }
    removeLabelClass(name) {
        if (this._labelElement) {
            this._labelElement.classList.remove(name);
        }
    }
    isLabelFloating() {
        return this._component.hasAttribute(FIELD_CONSTANTS.attributes.HOST_LABEL_FLOATING);
    }
    setRoomy(isRoomy) {
        toggleClass(this._rootElement, isRoomy, FIELD_CONSTANTS.classes.ROOMY);
    }
    setDense(isDense) {
        toggleClass(this._rootElement, isDense, FIELD_CONSTANTS.classes.DENSE);
    }
    hasLeadingNodes() {
        if (!this._leadingSlot) {
            return false;
        }
        return this._leadingSlot.assignedNodes().length > 0;
    }
    hasTrailingNodes() {
        if (!this._trailingSlot) {
            return false;
        }
        return this._trailingSlot.assignedNodes().length > 0;
    }
    hasAddonEndNodes() {
        if (!this._addonEndSlot) {
            return false;
        }
        return this._addonEndSlot.assignedNodes().length > 0;
    }
    setInputClass(className) {
        this._inputElement.classList.add(className);
    }
    removeInputClass(className) {
        this._inputElement.classList.remove(className);
    }
    setRootClass(classes) {
        addClass(classes, this._rootElement);
    }
    removeRootClass(classes) {
        removeClass(classes, this._rootElement);
    }
    setInputAttributeObserver(listener) {
        this._inputMutationObserver = createElementAttributeObserver(this._inputElement, listener, FIELD_CONSTANTS.observedInputAttributes);
    }
    isDisabled() {
        return this._inputElement.hasAttribute('disabled');
    }
    isReadonly() {
        return this._inputElement.hasAttribute('readonly');
    }
    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'
        };
    }
}
