class Keyboard
{
    constructor()
    {
        this.KEY = {
            BACKSPACE: 8,
            TAB:       9,
            SHIFT:    16,
            CTRL:     17,
            ALT:      18, 
            RETURN:   13,
            ESC:      27,
            SPACE:    32,
            PAGEUP:   33,
            PAGEDOWN: 34,
            END:      35,
            HOME:     36,
            LEFT:     37,
            UP:       38,
            RIGHT:    39,
            DOWN:     40,
            INSERT:   45,
            DELETE:   46,
            ZERO:     48, ONE: 49, TWO: 50, THREE: 51, FOUR: 52, FIVE: 53, SIX: 54, SEVEN: 55, EIGHT: 56, NINE: 57,
            ZEROPAD:  96, ONEPAD: 97, TWOPAD: 98, THREEPAD: 99, FOURPAD: 100, FIVEPAD: 101, SIXPAD: 102, SEVENPAD: 103, EIGHTPAD: 104, NINEPAD: 105,
            F1:       112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123,
            A:        65, B: 66, C: 67, D: 68, E: 69, F: 70, G: 71, H: 72, I: 73, J: 74, K: 75, L: 76, M: 77, N: 78, O: 79, P: 80, Q: 81, R: 82, S: 83, T: 84, U: 85, V: 86, W: 87, X: 88, Y: 89, Z: 90,
            TILDA:    192,
            COMMAND:  224
        };

        this.keyStates = [];
        for (var i = 0; i < 225; i++) this.keyStates[i] = 0;

        this.keydownListeners = new Map();
        this.keyupListeners = new Map();

        this.onKeyDownEvent = (event) => this.onKeyDown(event);
        this.onKeyUpEvent = (event) => this.onKeyUp(event);
        this.onBlurEvent = (event) => this.onBlur(event);

        this.enabled = false;
        this.enable();
    }

    // -1 => trigger keyup
    // 0 => key is up
    // 1 => been pressed/trigger keydown
    // 1+ => key is down

    key(keyCode)
    {
        return this.keyStates[keyCode] >= 1;
    }

    keyDown(keyCode)
    {
        return this.keyStates[keyCode] == 1;
    }

    keyUp(keyCode)
    {
        return this.keyStates[keyCode] == -1;
    }

    addEventListener(name, obj, func)
    {
        if (name == "keydown") this.keydownListeners.set(obj, func);
        if (name == "keyup") this.keyupListeners.set(obj, func);
    }

    removeEventListener(name, obj)
    {
        if (name == "keydown") this.keydownListeners.delete(obj);
        if (name == "keyup") this.keyupListeners.delete(obj);
    }

    onKeyDown(event)
    {
		if (event.keyCode == this.KEY.F5) return;
		if (event.keyCode == this.KEY.L && event.ctrlKey) return;
		if (event.keyCode == this.KEY.I && event.ctrlKey && event.shiftKey) return;

        event.preventDefault();
        if (event.repeat) return;
        this.keyStates[event.keyCode] = 1;
        for (let obj of this.keydownListeners.keys())
        {
            var func = this.keydownListeners.get(obj);
            func.call(obj, event.keyCode, event);
        }
    }

    onKeyUp(event)
    {
		if (event.keyCode == this.KEY.F5) return;
		if (event.keyCode == this.KEY.L && event.ctrlKey) return;
		if (event.keyCode == this.KEY.I && event.ctrlKey && event.shiftKey) return;

        event.preventDefault();
        if (event.repeat) return;
        this.keyStates[event.keyCode] = -1;
        for (let obj of this.keyupListeners.keys())
        {
            var func = this.keyupListeners.get(obj);
            func.call(obj, event.keyCode, event);
        }
    }

    update(dt)
    {
        for (var i = 0; i < this.keyStates.length; i++)
        {
            if (this.keyStates[i] != 0)
            {
                this.keyStates[i] += 1;
            }
        }
    }

    releaseAllKeys()
    {
        for (var i = 0; i < this.keyStates.length; i++)
        {
            if (this.keyStates[i] > 0)
            {
                this.keyStates[i] = -2;
                for (let obj of this.keyupListeners.keys())
                {
                    var func = this.keyupListeners.get(obj);
                    func.call(obj, i, { shiftKey: false, ctrlKey: false, altKey: false });
                }
            }
        }
    }

    enable()
    {
        if (this.enabled) return;
        this.enabled = true;

        /*if (!document.hasFocus())
        {
            window.focus();
        }*/

        //window.onkeydown = (event) => this.onkeydown(event);
        //window.onkeyup = (event) => this.onkeyup(event);
        window.addEventListener('keydown', this.onKeyDownEvent, true);
        window.addEventListener('keyup', this.onKeyUpEvent, true);
        window.addEventListener('blur', this.onBlurEvent, true);
    }

    disable()
    {
        if (!this.enabled) return;
        this.enabled = false;

        //window.onkeydown = null;//this.onkeydownEvent;
        //window.onkeyup = null;//this.onkeyupEvent;
        window.removeEventListener('keydown', this.onKeyDownEvent, true);
        window.removeEventListener('keyup', this.onKeyUpEvent, true);
        window.removeEventListener('blur', this.onBlurEvent, true);
    }

    onBlur()
    {
        this.releaseAllKeys();
    }
}

var KeyboardManager = new Keyboard();