/**
 * Binding observer.fire to keydown event.
 */
document.addEventListener("keydown", function(event){keydown_observer.fire(event)}, false);

/**
 * KeyDown event observer.
 */
var keydown_observer = new function(){
    
    this.listeners = {};
    
    this.emulate_key = function(key_code){
        
        this.fire({"keyCode" : key_code});
    };
    
    this.fire = function(e){

        var code = e.keyCode || e.which;
        
        if (stb && stb.key_lock === true && code != key.FRAME){
            _debug('key locked');
            return;
        }
        
        if (e.shiftKey){
            code += 1000;
        }
        
        if (e.altKey){
            code += 2000;
        }

        e.key = code;
        
        _debug('code:', code);

        if ([0, 1000, 2000, 3000].indexOf(code) >= 0){
            return;
        }
        
        var item;
        var priority_item;
        var normal_item;

        if (!this.triggerCustomEventListener('keypress', e)){
            return;
        }
        
        if (this.listeners.hasOwnProperty(code)){
            for(var i=0; i<this.listeners[code].length; i++){
                
                item = this.listeners[code][i];
                
                if (item.c.hasOwnProperty('con_menu')){
                    if (item.c.con_menu.on){
                        continue;
                    }
                }
                
                if (item.c.on && item.priority){
                    priority_item = item;
                    break;
                } else if (item.c.on || item.c === window){
                    if (!normal_item){
                        normal_item = item;
                    }
                }
            }
            
            if (priority_item){                
                priority_item.f.apply(priority_item.c, priority_item.a);
            }else if (normal_item){
                normal_item.f.apply(normal_item.c, normal_item.a);
            }
            
        }

        if ([9, 1009].indexOf(code) != -1){
            e.preventDefault && e.preventDefault();
        }

        _debug('keydown handler exit');
    }
};

/**
 * Binding function to key.
 * @param {number} key
 * @param {Object} context The object to be used as the value of 'this' within 'f'
 * @param {*} args
 * @return {Function}
 */
Function.prototype.bind = function(key, context, args){
    context = context || window;
    keydown_observer.listeners[key] = keydown_observer.listeners[key] || [];
    args = Array.prototype.splice.apply(arguments, [2, arguments.length]);
    keydown_observer.listeners[key].unshift({"f" : this, "c" : context, "a" : args});
    return this;
};

Function.prototype.priority_bind = function(key, context, args){
    context = context || window;
    keydown_observer.listeners[key] = keydown_observer.listeners[key] || [];
    args = Array.prototype.splice.apply(arguments, [2, arguments.length]);
    keydown_observer.listeners[key].unshift({"f" : this, "c" : context, "a" : args, "priority" : true});
    return this;
};

window.oncontextmenu = function () {
    if (typeof(keydown_observer) != 'undefined') {
        keydown_observer.emulate_key(key.EXIT);
    }
    return false;
};