/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { addClass, getShadowElement, removeClass, requireParent, isDeepEqual, toggleClass } from '@tylertech/forge-core';
import { BaseAdapter } from '../../core/base/base-adapter';
import { createUserInteractionListener } from '../../core/utils';
import { LIST_CONSTANTS } from '../list/list-constants';
import { LIST_ITEM_CONSTANTS } from './list-item-constants';
import { ForgeRipple } from '../../ripple';
export class ListItemAdapter extends BaseAdapter {
    constructor(component) {
        super(component);
        this._initialize();
    }
    _initialize() {
        this._listItemElement = getShadowElement(this._component, LIST_ITEM_CONSTANTS.selectors.LIST_ITEM);
        this._defaultSlot = getShadowElement(this._component, LIST_ITEM_CONSTANTS.selectors.DEFAULT_SLOT);
    }
    initializeAccessibility() {
        if (!this._component.hasAttribute('role')) {
            this._component.setAttribute('role', 'listitem');
        }
    }
    getListItem() {
        return this._component;
    }
    /**
     * Adds an event listener to the `<forge-list-item>` host element.
     * @param {string} type The event type.
     * @param {Function} listener The event callback.
     */
    addListener(type, listener, options) {
        this._listItemElement.addEventListener(type, listener, options);
    }
    /**
     * Removes an event listener from the `<forge-list-item>` host element.
     * @param {string} type The event type.
     * @param {Function} listener The event callback.
     */
    removeListener(type, listener) {
        this._listItemElement.removeEventListener(type, listener);
    }
    /**
     * Creates a ripple instance on the list item.
     * @returns {ForgeRipple}
     */
    createRipple() {
        return new ForgeRipple(this._listItemElement);
    }
    /**
     * Toggles the static state of this list item.
     * @param {boolean} value The static state.
     */
    setStatic(value) {
        if (value) {
            this._listItemElement.tabIndex = -1;
            addClass(LIST_ITEM_CONSTANTS.classes.STATIC, this._listItemElement);
        }
        else {
            if (this._listItemElement.hasAttribute('tabindex')) {
                this._listItemElement.tabIndex = 0;
            }
            removeClass(LIST_ITEM_CONSTANTS.classes.STATIC, this._listItemElement);
        }
    }
    /**
     * Sets this list item as a two-line list item.
     * @param {boolean} value The two-line state.
     */
    setTwoLine(value) {
        if (value) {
            addClass(LIST_ITEM_CONSTANTS.classes.TWO_LINE, this._listItemElement);
        }
        else {
            removeClass(LIST_ITEM_CONSTANTS.classes.TWO_LINE, this._listItemElement);
        }
    }
    /**
     * Sets this list item as a three-line list item.
     * @param {boolean} value The three-line state.
     */
    setThreeLine(value) {
        if (value) {
            addClass(LIST_ITEM_CONSTANTS.classes.THREE_LINE, this._listItemElement);
        }
        else {
            removeClass(LIST_ITEM_CONSTANTS.classes.THREE_LINE, this._listItemElement);
        }
    }
    /**
     * Determines how many lines the list item is displaying.
     */
    getLineCount() {
        return this._defaultSlot.assignedNodes().filter(e => e.nodeType === Node.ELEMENT_NODE).length; // assignedElements does not exist in the polyfilled version so filtering nodes instead
    }
    /**
     * Toggles the active class of the list item.
     * @param {boolean} value The active state.
     */
    setActive(value) {
        if (value) {
            addClass(LIST_ITEM_CONSTANTS.classes.ACTIVE, this._listItemElement);
        }
        else {
            removeClass(LIST_ITEM_CONSTANTS.classes.ACTIVE, this._listItemElement);
        }
    }
    /**
     * Toggles the selected class of the list item.
     * @param {boolean} value The active state.
     */
    setSelected(value) {
        if (value) {
            addClass(LIST_ITEM_CONSTANTS.classes.SELECTED, this._listItemElement);
        }
        else {
            removeClass(LIST_ITEM_CONSTANTS.classes.SELECTED, this._listItemElement);
        }
    }
    /**
     * Attempts to toggle a checkbox or radio button within the list item if it can find one.
     */
    tryToggleCheckboxRadio(value) {
        const checkable = this._component.querySelector(LIST_ITEM_CONSTANTS.selectors.CHECKBOX_RADIO_SELECTOR);
        if (checkable) {
            const force = typeof value === 'boolean';
            const currentState = checkable.checked;
            // We don't uncheck radio buttons unless we are forcing a value from the selection state
            if (!force && checkable.matches('input[type=radio]:checked')) {
                return;
            }
            // Check if we are just toggling or forcing to a specific checked state
            checkable.checked = force ? value : !checkable.checked;
            if (!force || currentState !== value) {
                checkable.dispatchEvent(new Event('change', { bubbles: true }));
            }
        }
    }
    /** Attempts to set focus to this list item. */
    setFocus() {
        this._listItemElement.focus();
    }
    /** Returns whether the component has focus or not. */
    hasFocus() {
        var _a;
        return document.activeElement === this._component || !!((_a = this._component.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement);
    }
    /**
     * Sets the role on the list item element.
     * @param role The role.
     */
    setRole(role) {
        this._listItemElement.setAttribute('role', role);
    }
    setDisabled(disabled) {
        toggleClass(this._listItemElement, disabled, LIST_ITEM_CONSTANTS.classes.DISABLED);
    }
    setDense(dense) {
        toggleClass(this._listItemElement, dense, LIST_ITEM_CONSTANTS.classes.DENSE);
    }
    setIndented(indented) {
        toggleClass(this._listItemElement, indented, LIST_ITEM_CONSTANTS.classes.INDENTED);
    }
    setWrap(value) {
        toggleClass(this._listItemElement, value, LIST_ITEM_CONSTANTS.classes.WRAP);
    }
    /**
     * Attempts to set the selected state of the list item element and it's visual indicators
     * @param value The value to compare to the parent list element's selected value
     * @returns Returns whether the list item is selected or not
     */
    trySelect(value) {
        const list = requireParent(this._component, LIST_CONSTANTS.elementName);
        if (!list || list.selectedValue === undefined) {
            return null;
        }
        const listValues = list.selectedValue instanceof Array ? list.selectedValue : [list.selectedValue];
        const isSelected = listValues.some(v => isDeepEqual(v, value));
        this.setSelected(isSelected);
        this.tryToggleCheckboxRadio(isSelected);
        return isSelected;
    }
    createUserInteractionListener() {
        return createUserInteractionListener(this._listItemElement);
    }
}
