"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.keyToIcon = exports.KeyboardController = void 0;
exports.sameSetArray = sameSetArray;
exports.isSupportedKeyboardEvent = isSupportedKeyboardEvent;
exports.makeShortcutListener = makeShortcutListener;
exports.listenShortcut = listenShortcut;
exports.listenKeydown = listenKeydown;
exports.listenKeypress = listenKeypress;
exports.makeKeydownListener = makeKeydownListener;
exports.makeKeypressListener = makeKeypressListener;
exports.listenKeyup = listenKeyup;
exports.makeKeyupListener = makeKeyupListener;
exports.isKeyPressed = isKeyPressed;
exports.isKeyRepeat = isKeyRepeat;
exports.isShiftPressed = isShiftPressed;
exports.isAltPressed = isAltPressed;
const f_1 = __importDefault(require("../../../system/f/comparison/Equals/f"));
const f_2 = require("../../../system/f/object/Keys/f");
const id_1 = require("../../../util/id");
const addGlobalBlurListener_1 = require("../../addGlobalBlurListener");
const key_1 = require("./key");
function sameSetArray(a, b) {
    const _ = (a, b) => {
        return a.localeCompare(b);
    };
    return (0, f_1.default)(a.sort(_), b.sort(_));
}
function isSupportedKeyboardEvent(event) {
    const { key, metaKey } = event;
    // if (metaKey) {
    //   return false
    // }
    if (key === 'imeprocess') {
        return false;
    }
    if (key === 'CapsLock') {
        return false;
    }
    return true;
}
class KeyboardController {
    constructor($system, $element) {
        this._ctrl = false;
        this._meta = false;
        this._shift = false;
        this._alt = false;
        this._repeat = false;
        this._pressed = [];
        this._listen = () => {
            this.$element.addEventListener('keydown', this._onKeydown);
            this.$element.addEventListener('keyup', this._onKeyup);
            this.$element.addEventListener('focusin', this._onFocusIn);
            this.$element.addEventListener('focusout', this._onFocusOut);
        };
        this._unlisten = () => {
            // console.log('KeyboardController', '_unlisten')
            this.$element.removeEventListener('keydown', this._onKeydown);
            this.$element.removeEventListener('keyup', this._onKeyup);
            this.$element.removeEventListener('focusin', this._onFocusIn);
            this.$element.removeEventListener('focusout', this._onFocusOut);
        };
        this._reset = () => {
            const { $system } = this;
            const { input: { keyboard: { pressed }, }, } = $system;
            // AD HOC
            this._repeat = false;
            // for (const key of pressed) {
            //   this._keydown(key)
            // }
            this._pressed = [...pressed.map(this._lowerCaseAlpha)];
        };
        this._lowerCaseAlpha = (key) => {
            if ((0, key_1.isControlKey)(key)) {
                return key;
            }
            else {
                return key.toLowerCase();
            }
        };
        this._onFocusIn = () => {
            // console.log('KeyboardController', '_onFocusIn')
            this._reset();
        };
        this._onFocusOut = () => {
            // console.log('KeyboardController', '_onFocusOut')
            // this._flush()
        };
        this._flush = () => {
            ;
            [...this._pressed].forEach((p) => this._keyup(p));
        };
        this._keydown = (key) => {
            key = this._lowerCaseAlpha(key);
            const index = this._pressed.indexOf(key);
            if (index === -1) {
                this._pressed.push(key);
            }
            const filtered = this._filterShortcuts('keydown');
            for (const shortcut of filtered) {
                if (this._repeat && !shortcut.multiple) {
                    continue;
                }
                shortcut.keydown(key, {
                    key,
                    ctrlKey: this._ctrl,
                    shiftKey: this._shift,
                    altKey: this._alt,
                    metaKey: this._meta,
                    repeat: this._repeat,
                });
            }
            // if (sameSetArray(current, ['meta', 'alt', 'i'])) {
            //   this._flush()
            // }
            return filtered;
        };
        this._keyup = (key) => {
            key = this._lowerCaseAlpha(key);
            const index = this._pressed.indexOf(key);
            if (index > -1) {
                const filtered = this._filterShortcuts('keyup');
                this._remove(key);
                for (const shortcut of filtered) {
                    shortcut.keyup(key, {
                        key,
                        ctrlKey: this._ctrl,
                        shiftKey: this._shift,
                        altKey: this._alt,
                        metaKey: this._meta,
                        repeat: this._repeat,
                    });
                }
            }
        };
        this._onKeydown = (event) => {
            const {} = this.$system;
            const { key, ctrlKey, shiftKey, metaKey, altKey, repeat } = event;
            if (metaKey) {
                // event.preventDefault()
                return;
            }
            if (!isSupportedKeyboardEvent(event)) {
                event.preventDefault();
                return;
            }
            this._ctrl = ctrlKey;
            this._meta = metaKey;
            this._shift = shiftKey;
            this._alt = altKey;
            this._repeat = repeat;
            const shortcuts = this._keydown(key);
            for (const shortcut of shortcuts) {
                if (shortcut.preventDefault) {
                    event.preventDefault();
                }
                if (shortcut.stopPropagation) {
                    event.stopPropagation();
                }
            }
        };
        this._onKeyup = (event) => {
            if (!isSupportedKeyboardEvent(event)) {
                return;
            }
            const { key, ctrlKey, shiftKey, metaKey, altKey } = event;
            this._ctrl = ctrlKey;
            this._meta = metaKey;
            this._shift = shiftKey;
            this._alt = altKey;
            this._keyup(key);
            // if (this._pressed.length > 0) {
            //   this._keydown(this._pressed[this._pressed.length - 1])
            // }
            // meta/alt key prevents other keys from firing up
            // if (key === 'meta') {
            //   this._flush()
            // }
        };
        this.$system = $system;
        this.$element = $element;
        this._ctrl = false;
        this._meta = false;
        this._shift = false;
        this._alt = false;
        this._pressed = [];
        this._shortcuts = {};
        const { root: $root } = $system;
        (0, addGlobalBlurListener_1.addGlobalBlurListener)($root, () => {
            this._flush();
        });
        this._reset();
    }
    isCtrlPressed() {
        return this._ctrl;
    }
    isAltPressed() {
        return this._alt;
    }
    isShiftPressed() {
        return this._shift;
    }
    addShortcutGroup(shortcutGroup) {
        const id = (0, id_1.randomIdNotIn)(this._shortcuts);
        this._shortcuts[id] = shortcutGroup;
        if ((0, f_2.keys)(this._shortcuts).length === 1) {
            this._listen();
        }
        return id;
    }
    removeShortcutGroup(id) {
        delete this._shortcuts[id];
        if ((0, f_2.keys)(this._shortcuts).length === 0) {
            this._unlisten();
        }
    }
    isKeyPressed(key) {
        return this._pressed.indexOf(key) > -1;
    }
    _filterShortcuts(type) {
        const filtered = [];
        for (const id in this._shortcuts) {
            const shortcutGroup = this._shortcuts[id];
            const currentCombo = this.getCurrentCombo();
            const currentComboStr = currentCombo.join('+');
            for (const shortcut of shortcutGroup) {
                let match = false;
                if ((type === 'keydown' && shortcut.keydown) ||
                    (type === 'keyup' && shortcut.keyup)) {
                    let { combo } = shortcut;
                    const { strict } = shortcut;
                    combo = Array.isArray(combo) ? combo : [combo];
                    for (const c of combo) {
                        if (c.toLowerCase().replace(/ /g, '') ===
                            currentComboStr.toLowerCase().replace(/ /g, '') ||
                            (strict === false &&
                                currentCombo
                                    .map((key) => key.toLowerCase())
                                    .includes(c.toLowerCase().replace(/ /g, '')))) {
                            match = true;
                            break;
                        }
                    }
                }
                if (match) {
                    filtered.push(shortcut);
                }
            }
        }
        return filtered;
    }
    _remove(key) {
        const index = this._pressed.indexOf(key);
        if (index > -1) {
            this._pressed.splice(index, 1);
        }
    }
    _isSystemCombo(event) {
        const { key, ctrlKey, metaKey } = event;
        if ((metaKey || ctrlKey) && ['c', 'v', 'x', 'z'].includes(key)) {
            return true;
        }
        return false;
    }
    getCurrentCombo() {
        return this._pressed;
    }
}
exports.KeyboardController = KeyboardController;
function makeShortcutListener(shortcuts, _global = false) {
    return (component) => {
        return listenShortcut(component, shortcuts, _global);
    };
}
function listenShortcut(component, shortcuts, _global = false) {
    const { $element, $system } = component;
    const $keyboard = new KeyboardController($system, $element);
    const shortcutGroupId = $keyboard.addShortcutGroup(shortcuts);
    return () => {
        $keyboard.removeShortcutGroup(shortcutGroupId);
    };
}
function listenKeydown(component, onKeydown) {
    const { $element } = component;
    const keydownListener = (_event) => {
        const { key, ctrlKey, shiftKey, altKey, metaKey, repeat } = _event;
        onKeydown &&
            onKeydown({ key, ctrlKey, shiftKey, altKey, metaKey, repeat }, _event);
    };
    $element.addEventListener('keydown', keydownListener);
    return () => {
        $element.removeEventListener('keydown', keydownListener);
    };
}
function listenKeypress(component, onKeydown) {
    const { $element } = component;
    const keypressListener = (_event) => {
        const { key, ctrlKey, shiftKey, altKey, metaKey, repeat } = _event;
        onKeydown &&
            onKeydown({ key, ctrlKey, shiftKey, altKey, metaKey, repeat }, _event);
    };
    $element.addEventListener('keypress', keypressListener);
    return () => {
        $element.removeEventListener('keypress', keypressListener);
    };
}
function makeKeydownListener(listener) {
    return (component) => {
        return listenKeydown(component, listener);
    };
}
function makeKeypressListener(listener) {
    return (component) => {
        return listenKeypress(component, listener);
    };
}
function listenKeyup(component, onKeyup) {
    const { $element } = component;
    const keyupListener = (_event) => {
        const { key, ctrlKey, shiftKey, altKey, metaKey, repeat } = _event;
        onKeyup &&
            onKeyup({ key, ctrlKey, shiftKey, altKey, metaKey, repeat }, _event);
    };
    $element.addEventListener('keyup', keyupListener);
    return () => {
        $element.removeEventListener('keyup', keyupListener);
    };
}
function makeKeyupListener(listener) {
    return (component) => {
        return listenKeyup(component, listener);
    };
}
function isKeyPressed(system, key) {
    const { input: { keyboard: { pressed }, }, } = system;
    return pressed.indexOf(key) > -1;
}
function isKeyRepeat($system) {
    const { input: $input } = $system;
    const { keyboard: $keyboard } = $input;
    const { repeat: $repeat } = $keyboard;
    return $repeat;
}
function isShiftPressed($system) {
    return isKeyPressed($system, 'Shift');
}
function isAltPressed($system) {
    return isKeyPressed($system, 'Alt');
}
exports.keyToIcon = {
    Enter: 'enter',
    Shift: 'shift',
    Backspace: 'backspace',
    ArrowDown: 'arrow-down',
    ArrowLeft: 'arrow-left',
    ArrowRight: 'arrow-right',
    ArrowUp: 'arrow-up',
    AltLeft: 'option',
    AltRight: 'option',
    CtrlRight: 'chevron-up',
    CtrlLeft: 'chevron-up',
    MetaLeft: 'cmd',
};
//# sourceMappingURL=index.js.map