function _CommandHooker() { }
_CommandHooker.prototype = {
    setUp : function () {
        CommandHooker._keySeq = [];
        CommandHooker._commandMap = {};

        $(function() {
            //$('html').keyup(function (e) { alert(e.keyCode); });
            $('html').keyup(function (e) { CommandHooker._addKeySequence(e); });
        });
    }
    , _addKeySequence : function (e) {
        this._keySeq.push(e.keyCode);
        var map = CommandHooker._commandMap;

        for (var i = 0, n = this._keySeq.length; i < n; i++) {
            var val = this._keySeq[i];
            map = map[val];

            if (map == null) {
                this._keySeq = [];
                if (i != 0) {
                    if (this.onInvalidCommand != null) {
                        this.onInvalidCommand();
                    }
                }
                return;
            }
            if (this.onKeyProcess != null) {
                this.onKeyProcess(this._keySeq);
            }
        }

        if (map['__ACTION__']) {
            map['__ACTION__']();
            this._keySeq = [];
        }
    }
    , addMapping : function (keySeq, action) {
        var map = CommandHooker._commandMap;
        keySeq = CommandHooker._friendlySeqToNumberSeq(keySeq);
        $.each(keySeq, function (i, v) {
            if (map[v] == null) {
                map[v] = {};
            }
            map = map[v];
        });
        map['__ACTION__'] = action;
    }
    , _friendlySeqMap : {
         'up'     : 38
        ,'left'   : 37
        ,'right'  : 39
        ,'down'   : 40
    }
    , _friendlySeqToNumberSeq : function (keySeq) {
        return $.map(keySeq, function (val) {
            if (typeof(val) == "number") {
                return val;
            } else if (CommandHooker._friendlySeqMap[val.toLowerCase()] != null) {
                return CommandHooker._friendlySeqMap[val.toLowerCase()];
            } else if (val.length == 1) {
                return val.toUpperCase().charCodeAt(0);
            } else {
                throw "key '"+val+"' not supported";
            }
        });
    }
};
var CommandHooker = new _CommandHooker();
CommandHooker.setUp();
CommandHooker.onInvalidCommand = function () { };
