/**
 * @license
 * Copyright Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { KEYBOARD_SHORTCUT_CONSTANTS } from './keyboard-shortcut-constants';
import { elementAcceptsTextInput, matchKeyCombination, parseKeyCombinations } from './keyboard-shortcut-utils';
export class KeyboardShortcutFoundation {
    constructor(_adapter) {
        this._adapter = _adapter;
        this._global = false;
        this._allowWhileTyping = false;
        this._preventDefault = true;
        this._capture = false;
        this._useCode = false;
        this._disabled = false;
        this._keyDownListener = evt => this._onKeyDown(evt);
    }
    initialize() {
        this._initializeTargetElement();
        this._adapter.setHostStyles();
    }
    disconnect() {
        this._disconnectTargetElement();
        this._adapter.destroy();
    }
    _initializeTargetElement() {
        this._disconnectTargetElement();
        this._adapter.setTargetElement(this._target, this._global);
        if (!this._adapter.hasTargetElement()) {
            throw new Error('Unable to locate the target element.');
        }
        if (!this._disabled) {
            this._connectTargetElement();
        }
    }
    _connectTargetElement() {
        if (!this._adapter.hasTargetElement) {
            return;
        }
        this._adapter.addTargetEventListener('keydown', this._keyDownListener, this._capture);
    }
    _disconnectTargetElement() {
        if (!this._adapter.hasTargetElement) {
            return;
        }
        this._adapter.removeTargetEventListener('keydown', this._keyDownListener, this._capture);
    }
    _onKeyDown(evt) {
        // Here we may check if the target element is disabled, but disabled elements typically can't receive focus anyway
        var _a;
        // Ignore the event if it originates from a text field
        // TODO: bypass this and allow it if a modifier key is used?
        if (!this._allowWhileTyping && elementAcceptsTextInput(evt.target)) {
            return;
        }
        if (matchKeyCombination(evt, this._keyCombinations, this._useCode)) {
            if (this._preventDefault) {
                evt.preventDefault();
            }
            this._adapter.emitHostEvent(KEYBOARD_SHORTCUT_CONSTANTS.events.ACTIVATE, evt);
            (_a = this._activateCallback) === null || _a === void 0 ? void 0 : _a.call(null, evt);
        }
    }
    /** Sets the key combinations. */
    _setKeyCombinations() {
        this._keyCombinations = parseKeyCombinations(this._key, this._useCode);
    }
    /** Gets/sets the key binding. */
    get key() {
        return this._key;
    }
    set key(value) {
        if (this._key !== value) {
            this._key = value;
            this._adapter.toggleHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.KEY, !!this.key, this._key || '');
            this._setKeyCombinations();
        }
        // TODO: prevent multiple shortcuts with the same keys on an element (possible?)
    }
    /** Gets/sets the target element selector. */
    get target() {
        return this._target;
    }
    set target(value) {
        if (this._target !== value) {
            this._target = value;
            this._adapter.setHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.TARGET, this._target);
            if (this._adapter.isConnected) {
                this._initializeTargetElement();
            }
        }
    }
    /** Gets/sets the global listener state. */
    get global() {
        return this._global;
    }
    set global(value) {
        if (this._global !== value) {
            this._global = value;
            this._adapter.toggleHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.GLOBAL, this._global);
            if (this._adapter.isConnected) {
                this._initializeTargetElement();
            }
        }
    }
    /** Gets/sets whether the callback will be trigger while a text input has focus. */
    get allowWhileTyping() {
        return this._allowWhileTyping;
    }
    set allowWhileTyping(value) {
        if (this._allowWhileTyping !== value) {
            this._allowWhileTyping = value;
            this._adapter.toggleHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.ALLOW_WHILE_TYPING, this._allowWhileTyping);
        }
    }
    /** Gets/sets whether to prevent default on keyboard events. */
    get preventDefault() {
        return this._preventDefault;
    }
    set preventDefault(value) {
        if (this._preventDefault !== value) {
            this._preventDefault = value;
            this._adapter.toggleHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.PREVENT_DEFAULT, this._preventDefault);
        }
    }
    /** Gets/sets whether to use capturing on keyboard events. */
    get capture() {
        return this._capture;
    }
    set capture(value) {
        if (this._capture !== value) {
            this._disconnectTargetElement(); // We need to disconnect first to ensure our listener is removed properly based on capturing state
            this._capture = value;
            this._adapter.toggleHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.CAPTURE, this.capture);
            this._connectTargetElement();
        }
    }
    /** Gets/sets whether to match codes instead of keys on keyboard events. */
    get useCode() {
        return this._useCode;
    }
    set useCode(value) {
        if (this._useCode !== value) {
            this._useCode = value;
            this._adapter.toggleHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.USE_CODE, this._useCode);
            this._setKeyCombinations();
        }
    }
    /** Gets/sets whether the event will be emitted. */
    get disabled() {
        return this._disabled;
    }
    set disabled(value) {
        if (this._disabled !== value) {
            this._disabled = value;
            this._adapter.toggleHostAttribute(KEYBOARD_SHORTCUT_CONSTANTS.attributes.DISABLED, this._disabled);
            if (this._disabled) {
                this._disconnectTargetElement();
            }
            else {
                this._connectTargetElement();
            }
        }
    }
    /** Gets/sets the activation callback. */
    get activateCallback() {
        return this._activateCallback;
    }
    set activateCallback(value) {
        this._activateCallback = value;
    }
}
