/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { addClass, getShadowElement, removeClass } from '@tylertech/forge-core';
import { createUserInteractionListener } from '../core';
import { BaseAdapter } from '../core/base/base-adapter';
import { ForgeRipple, ForgeRippleFoundation } from '../ripple';
import { CHECKBOX_CONSTANTS } from './checkbox-constants';
export class CheckboxAdapter extends BaseAdapter {
    constructor(component) {
        super(component);
    }
    // ForgeRippleCapableSurface
    get root() {
        return this._rootElement;
    }
    get unbounded() {
        return true;
    }
    get disabled() {
        return this.isDisabled();
    }
    initialize() {
        this._configureElements();
        this._attachInternalInputListeners();
        this._deferRippleInitialization();
    }
    async _deferRippleInitialization() {
        if (typeof this._destroyUserInteractionListener === 'function') {
            this._destroyUserInteractionListener();
        }
        const { userInteraction, destroy } = createUserInteractionListener(this._rootElement);
        this._destroyUserInteractionListener = destroy;
        const { type } = await userInteraction;
        this._destroyUserInteractionListener = undefined;
        if (!this.isConnected) {
            return;
        }
        this._rippleInstance = this._createRipple();
        if (type === 'focusin') {
            this._rippleInstance.handleFocus();
        }
    }
    setDense(value) {
        var _a;
        if (value) {
            this._setHostAttribute(CHECKBOX_CONSTANTS.attributes.DENSE);
            this.setRootClass(CHECKBOX_CONSTANTS.classes.CHECKBOX_DENSE);
        }
        else {
            this._removeHostAttribute(CHECKBOX_CONSTANTS.attributes.DENSE);
            this.removeRootClass(CHECKBOX_CONSTANTS.classes.CHECKBOX_DENSE);
        }
        (_a = this._rippleInstance) === null || _a === void 0 ? void 0 : _a.layout();
    }
    isAttachedToDOM() {
        return Boolean(this._component.parentNode);
    }
    _configureElements() {
        this._inputElement = this._component.querySelector(CHECKBOX_CONSTANTS.selectors.INPUT);
        this._wrapperElement = getShadowElement(this._component, CHECKBOX_CONSTANTS.selectors.WRAPPER);
        this._rootElement = getShadowElement(this._component, CHECKBOX_CONSTANTS.selectors.ROOT);
        this._labelElement = this._component.querySelector(CHECKBOX_CONSTANTS.selectors.LABEL);
        if (this._labelElement) {
            this._labelElement.setAttribute(CHECKBOX_CONSTANTS.attributes.SLOT, CHECKBOX_CONSTANTS.selectors.LABEL);
        }
        if (this._inputElement) {
            this._inputElement.setAttribute(CHECKBOX_CONSTANTS.attributes.SLOT, CHECKBOX_CONSTANTS.selectors.INPUT);
        }
        addClass(CHECKBOX_CONSTANTS.classes.UPGRADED, this._rootElement);
    }
    _setHostAttribute(name, value = '') {
        this._component.setAttribute(name, value);
    }
    _removeHostAttribute(name) {
        this._component.removeAttribute(name);
    }
    disconnect() {
        if (typeof this._destroyUserInteractionListener === 'function') {
            this._destroyUserInteractionListener();
            this._destroyUserInteractionListener = undefined;
        }
        if (this._labelElement) {
            this._labelElement.removeAttribute(CHECKBOX_CONSTANTS.attributes.SLOT);
        }
        if (this._inputElement) {
            this._inputElement.removeAttribute(CHECKBOX_CONSTANTS.attributes.SLOT);
        }
        if (this._inputMutationObserver) {
            this._inputMutationObserver.disconnect();
        }
        this._detachInternalInputListeners();
        if (this._rippleInstance) {
            this._rippleInstance.destroy();
        }
    }
    setRootClass(classes) {
        if (this._rootElement) {
            addClass(classes, this._rootElement);
        }
    }
    removeRootClass(classes) {
        if (this._rootElement) {
            removeClass(classes, this._rootElement);
        }
    }
    setWrapperClass(classes) {
        if (this._wrapperElement) {
            addClass(classes, this._wrapperElement);
        }
    }
    removeWrapperClass(classes) {
        if (this._wrapperElement) {
            removeClass(classes, this._wrapperElement);
        }
    }
    setNativeAttribute(qualifiedName, value) {
        this._inputElement.setAttribute(qualifiedName, value);
    }
    isDisabled() {
        return this._inputElement.disabled;
    }
    isChecked() {
        return this._inputElement && this._inputElement.checked;
    }
    isIndeterminate() {
        return this._inputElement && this._inputElement.indeterminate;
    }
    removeNativeAttribute(qualifiedName) {
        this._inputElement.removeAttribute(qualifiedName);
    }
    installPropertyChangeHooks(callback) {
        const nativeCb = this._inputElement;
        const cbProto = Object.getPrototypeOf(nativeCb);
        CHECKBOX_CONSTANTS.CB_PROTO_PROPS.forEach(controlState => {
            const desc = Object.getOwnPropertyDescriptor(cbProto, controlState);
            // We have to check for this descriptor, since some browsers (Safari) don't support its return.
            // See: https://bugs.webkit.org/show_bug.cgi?id=49739
            if (!this._validDescriptor(desc)) {
                return;
            }
            // Type cast is needed for compatibility with Closure Compiler.
            const nativeGetter = desc.get;
            if (desc) {
                const nativeCbDesc = {
                    configurable: desc.configurable,
                    enumerable: desc.enumerable,
                    get: nativeGetter,
                    set: (state) => {
                        var _a;
                        (_a = desc.set) === null || _a === void 0 ? void 0 : _a.call(nativeCb, state);
                        callback();
                    }
                };
                Object.defineProperty(nativeCb, controlState, nativeCbDesc);
            }
        });
    }
    listen(qualifiedName, callback, onRoot = false) {
        if (onRoot) {
            this._rootElement.addEventListener(qualifiedName, callback);
        }
        else {
            this._inputElement.addEventListener(qualifiedName, callback);
        }
    }
    unlisten(qualifiedName, callback, onRoot = false) {
        if (!this._inputElement) {
            return;
        }
        if (onRoot) {
            this._rootElement.removeEventListener(qualifiedName, callback);
        }
        else {
            this._inputElement.removeEventListener(qualifiedName, callback);
        }
    }
    uninstallPropertyChangeHooks() {
        if (!this._inputElement) {
            return;
        }
        const nativeCb = this._inputElement;
        const cbProto = Object.getPrototypeOf(nativeCb);
        CHECKBOX_CONSTANTS.CB_PROTO_PROPS.forEach(controlState => {
            const desc = Object.getOwnPropertyDescriptor(cbProto, controlState);
            if (!this._validDescriptor(desc)) {
                return;
            }
            Object.defineProperty(nativeCb, controlState, desc);
        });
    }
    setInputAttributeObserver(listener) {
        this._inputMutationObserver = new MutationObserver(mutations => {
            for (const mutation of mutations) {
                if (mutation.attributeName) {
                    listener(mutation.attributeName, this._inputElement.getAttribute(mutation.attributeName));
                }
            }
        });
        this._inputMutationObserver.observe(this._inputElement, {
            attributes: true,
            attributeFilter: ['disabled', 'checked']
        });
    }
    _validDescriptor(inputPropDesc) {
        return !!inputPropDesc && typeof inputPropDesc.set === 'function';
    }
    _attachInternalInputListeners() {
        this._inputFocusHandler = () => this._handleInputFocusListener();
        this._inputBlurHandler = () => this._handleInputBlurListener();
        this._inputElement.addEventListener('focus', this._inputFocusHandler);
        this._inputElement.addEventListener('blur', this._inputBlurHandler);
    }
    _detachInternalInputListeners() {
        removeEventListener('focus', this._inputFocusHandler);
        removeEventListener('blur', this._inputBlurHandler);
    }
    _handleInputFocusListener() {
        addClass(CHECKBOX_CONSTANTS.classes.FOCUSED, this._rootElement);
    }
    _handleInputBlurListener() {
        removeClass(CHECKBOX_CONSTANTS.classes.FOCUSED, this._rootElement);
    }
    _createRipple() {
        const adapter = Object.assign(Object.assign({}, ForgeRipple.createAdapter(this)), { deregisterInteractionHandler: (evtType, handler) => this._inputElement.removeEventListener(evtType, handler, { passive: true }), isSurfaceActive: () => this._inputElement.matches(':active'), isUnbounded: () => Boolean(this.unbounded), registerInteractionHandler: (evtType, handler) => this._inputElement.addEventListener(evtType, handler, { passive: true }), isSurfaceDisabled: () => this._inputElement.disabled, addClass: (className) => addClass(className, this._rootElement), removeClass: (className) => removeClass(className, this._rootElement), updateCssVariable: (varName, value) => this._rootElement.style.setProperty(varName, value) });
        const ripple = new ForgeRipple(this._rootElement, new ForgeRippleFoundation(adapter));
        return ripple;
    }
}
