// KeyEvent ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
KeyEvent = Class.create();
KeyEvent.prototype =
{
    iType : -1,
    oTarget : null,
    iCode : -1,

    initialize : function(p_iType, p_oEvent)
    {
        this.iType = p_iType;

        // Target
        {
            if(p_oEvent.target)
            {
                this.oTarget = p_oEvent.target;
            }
            else if(p_oEvent.srcElement) // IE
            {
                this.oTarget = p_oEvent.srcElement;
            }

            if(p_oEvent.nodeType == 3) // defeat Safari bug
            {
                this.oTarget = this.oTarget.parentNode;
            }
        }

        this.iCode = p_oEvent.keyCode ? p_oEvent.keyCode : p_oEvent.which;
    },

    getType : function()
    {
        return this.iType;
    },

    getTarget : function()
    {
        return this.oTarget;
    },

    getCode : function()
    {
        return this.iCode;
    },

    toString : function()
    {
        return "KeyEvent[type=\"" + this.iType + "\", code=\"" + this.iCode + "\"]";
    }
};

KeyEvent.Type = new Object();
KeyEvent.Type.PRESSED = 1;
KeyEvent.Type.RELEASED = 2;
KeyEvent.Type.TYPED = 3;
KeyEvent.ENTER = 13;
KeyEvent.SHIFT = 16;
KeyEvent.ESCAPE = 27;



// Keyboard ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Keyboard = Class.create();
Keyboard.prototype =
{
    bShiftPressed : false,
    aListeners : null,

    initialize : function()
    {
        this.aListeners = [];
    },

    addListener : function(p_oListener)
    {
        this.aListeners.push(p_oListener);
    },

    dispatch : function(p_oEvent)
    {
        var iIndex;
        switch(p_oEvent.getType())
        {
            case KeyEvent.Type.PRESSED:
            {
                for(iIndex = 0; iIndex < this.aListeners.length; ++iIndex)
                {
                    if(this.aListeners[iIndex]["onKeyPressed"])
                    {
                        this.aListeners[iIndex].onKeyPressed(p_oEvent);
                    }
                }
                break;
            }

            case KeyEvent.Type.RELEASED:
            {
                for(iIndex = 0; iIndex < this.aListeners.length; ++iIndex)
                {
                    if(this.aListeners[iIndex]["onKeyReleased"])
                    {
                        this.aListeners[iIndex].onKeyReleased(p_oEvent);
                    }
                }
                break;
            }

            case KeyEvent.Type.TYPED:
            {
                for(iIndex = 0; iIndex < this.aListeners.length; ++iIndex)
                {
                    if(this.aListeners[iIndex]["onKeyTyped"])
                    {
                        this.aListeners[iIndex].onKeyTyped(p_oEvent);
                    }
                }
                break;
            }
        }
    }
};

Keyboard.oInstance = null;
Keyboard.getInstance = function()
{
    if(Keyboard.oInstance == null)
    {
        Keyboard.oInstance = new Keyboard();
    }
    return Keyboard.oInstance;
};

Keyboard.addListener = function(p_oListener)
{
    Keyboard.getInstance().addListener(p_oListener);
};

// Default listeners
{
    document.onkeydown = function(p_oEvent)
    {
        Keyboard.getInstance().dispatch(new KeyEvent(KeyEvent.Type.PRESSED, (p_oEvent ? p_oEvent : window.event)));
    };

    document.onkeyup = function(p_oEvent)
    {
        Keyboard.getInstance().dispatch(new KeyEvent(KeyEvent.Type.RELEASED, (p_oEvent ? p_oEvent : window.event)));
    };

    document.onkeypress = function(p_oEvent)
    {
        Keyboard.getInstance().dispatch(new KeyEvent(KeyEvent.Type.TYPED, (p_oEvent ? p_oEvent : window.event)));
    };
}

