"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "useRecorder", {
    enumerable: true,
    get: function() {
        return useRecorder;
    }
});
const _keyObserver = require("./keyObserver");
const _utils = require("./utils");
const _event = require("../helpers/dom/event");
const _element = require("../helpers/dom/element");
const _browser = require("../helpers/browser");
const _function = require("../helpers/function");
const modifierKeysObserver = (0, _keyObserver.createKeysObserver)();
const modKeyListeners = [];
let instanceCounter = 0;
function useRecorder(ownerWindow, handleEvent, beforeKeyDown, afterKeyDown, callback, dispatchGlobalShortcutsWhenTableBlocked = null) {
    /**
   * `KeyboardEvent`'s callback function
   *
   * @private
   * @param {KeyboardEvent} event The event object
   */ const onkeydown = (event)=>{
        const tableShortcutsAllowed = handleEvent(event) !== false;
        if (tableShortcutsAllowed) {
            const result = beforeKeyDown(event);
            // keyCode 229 aka 'uninitialized' doesn't take into account with editors. This key code is
            // produced when unfinished character is entering using the IME editor. It is fired on macOS,
            // Windows and linux (ubuntu) with installed ibus-pinyin package.
            if (result === false || event.keyCode === 229 || typeof event.key !== 'string' || (0, _event.isImmediatePropagationStopped)(event)) {
                return;
            }
            const pressedKey = (0, _utils.normalizeEventKey)(event);
            let extraModifierKeys = [];
            if (!(0, _utils.isModifierKey)(pressedKey)) {
                extraModifierKeys = (0, _utils.getPressedModifierKeys)(event);
            }
            const pressedKeys = [
                pressedKey
            ].concat(extraModifierKeys);
            let isExecutionCancelled = callback(event, pressedKeys);
            if (!isExecutionCancelled && ((0, _browser.isMacOS)() && extraModifierKeys.includes('meta') || !(0, _browser.isMacOS)() && extraModifierKeys.includes('control'))) {
                // Trigger the callback for the virtual OS-dependent "control/meta" key
                isExecutionCancelled = callback(event, [
                    pressedKey
                ].concat((0, _utils.getPressedModifierKeys)(event, true)));
            }
            afterKeyDown(event);
            return;
        }
        if ((0, _function.isFunction)(dispatchGlobalShortcutsWhenTableBlocked) === false) {
            return;
        }
        if (event.keyCode === 229 || typeof event.key !== 'string' || (0, _event.isImmediatePropagationStopped)(event)) {
            return;
        }
        const pressedKey = (0, _utils.normalizeEventKey)(event);
        let extraModifierKeys = [];
        if (!(0, _utils.isModifierKey)(pressedKey)) {
            extraModifierKeys = (0, _utils.getPressedModifierKeys)(event);
        }
        const pressedKeys = [
            pressedKey
        ].concat(extraModifierKeys);
        let isExecutionCancelled = dispatchGlobalShortcutsWhenTableBlocked(event, pressedKeys);
        if (!isExecutionCancelled && ((0, _browser.isMacOS)() && extraModifierKeys.includes('meta') || !(0, _browser.isMacOS)() && extraModifierKeys.includes('control'))) {
            isExecutionCancelled = dispatchGlobalShortcutsWhenTableBlocked(event, [
                pressedKey
            ].concat((0, _utils.getPressedModifierKeys)(event, true)));
        }
        afterKeyDown(event);
    };
    /**
   * `KeyboardEvent`'s callback function for observing the pressed state of the mod keys.
   *
   * @private
   * @param {KeyboardEvent} event The event object
   */ const onkeydownForModKeys = (event)=>{
        if (typeof event.key === 'string') {
            const pressedKey = (0, _utils.normalizeEventKey)(event);
            if ((0, _utils.isModifierKey)(pressedKey)) {
                modifierKeysObserver.press(pressedKey);
            }
        }
    };
    /**
   * `KeyboardEvent`'s callback function for observing the pressed state of the mod keys.
   *
   * @private
   * @param {KeyboardEvent} event The event object
   */ const onkeyupForModKeys = (event)=>{
        if (typeof event.key === 'string') {
            const pressedKey = (0, _utils.normalizeEventKey)(event);
            if ((0, _utils.isModifierKey)(pressedKey)) {
                modifierKeysObserver.release(pressedKey);
            }
        }
    };
    /**
   * `FocusEvent`'s callback function
   *
   * @private
   */ const onblur = ()=>{
        modifierKeysObserver.releaseAll();
    };
    /**
   * Add event listeners to the starting window and its parents' windows.
   */ const mount = ()=>{
        let eventTarget = ownerWindow;
        instanceCounter += 1;
        while(eventTarget){
            if (instanceCounter === 1) {
                eventTarget.document.documentElement.addEventListener('keydown', onkeydownForModKeys);
                modKeyListeners.push({
                    event: 'keydown',
                    listener: onkeydownForModKeys
                });
                eventTarget.document.documentElement.addEventListener('keyup', onkeyupForModKeys);
                modKeyListeners.push({
                    event: 'keyup',
                    listener: onkeyupForModKeys
                });
            }
            eventTarget.document.documentElement.addEventListener('keydown', onkeydown);
            eventTarget.document.documentElement.addEventListener('blur', onblur);
            eventTarget = (0, _element.getParentWindow)(eventTarget);
        }
    };
    /**
   * Remove event listeners from the starting window and its parents' windows.
   */ const unmount = ()=>{
        let eventTarget = ownerWindow;
        instanceCounter -= 1;
        while(eventTarget){
            if (instanceCounter === 0) {
                for(let i = 0; i < modKeyListeners.length; i++){
                    const { event, listener } = modKeyListeners[i];
                    eventTarget.document.documentElement.removeEventListener(event, listener);
                }
                modKeyListeners.length = 0;
            }
            eventTarget.document.documentElement.removeEventListener('keydown', onkeydown);
            eventTarget.document.documentElement.removeEventListener('blur', onblur);
            eventTarget = (0, _element.getParentWindow)(eventTarget);
        }
    };
    return {
        mount,
        unmount,
        isPressed: (key)=>modifierKeysObserver.isPressed(key),
        releasePressedKeys: ()=>modifierKeysObserver.releaseAll()
    };
}
