//
//  EventHandlers.js
//  Written by Stefan Habel
//  Version 2.0
//  Last modified: 04.11.2007
//


window.EventHandlers = function ()
{

    this.eventHandlers = [];

}


//
// Returns whether the given type string is one of the event handler types
// defined above.
//
window.EventHandlers.prototype.CheckType = function ( type, htmlNodeType )
{
    var found = false;
    var typeConstant = undefined;
    for (var typeValue in EventHandlers.Type) {
        found = type == EventHandlers.Type[typeValue];
        if (found) {
            typeConstant = typeValue;
            break;
        }
    }
    if (!found)
        return false;
        
    var validHtmlElements = EventHandlers.ValidHtmlElements[typeConstant];
    if (validHtmlElements == "*")
        validHtmlElements = ["A", "ABBR", "ACRONYM", "ADDRESS", "AREA", "B", "BIG", "BLOCKQUOTE", "BODY", "BUTTON", "CAPTION", "CENTER", "CITE", "CODE", "COL", "COLGROUP", "DD", "DEL", "DFN", "DIR", "DIV", "DL", "DT", "EM", "FIELDSET", "FORM", "H1", "H2", "H3", "H4", "H5", "H6", "HR", "I", "IMG", "INPUT", "INS", "KBD", "LABEL", "LEGEND", "LI", "LINK", "MAP", "MENU", "NOFRAMES", "NOSCRIPT", "OBJECT", "OL", "OPTGROUP", "OPTION", "P", "PRE", "Q", "S", "SAMP", "SELECT", "SMALL", "SPAN", "STRIKE", "STRONG", "SUB", "SUP", "TABLE", "TBODY", "TD", "TEXTAREA", "TFOOT", "TH", "THEAD", "TR", "TT", "U", "UL", "VAR"];

    return IsIn(htmlNodeType, validHtmlElements);
}


window.EventHandlers.prototype.Register = function ( elementId, type, func )
{
    var element = document.getElementById(elementId);
    if (!element) {
        console.error("Cannot register event handler for element \"" + elementId + "\". No element with the given ID found.");
        return;
    }

    // register event handler function with element
    if (element.addEventListener) {       // standard DOM
//        console.info("Adding on" + type + " event listener with element \"" + elementId + "\" via addEventListener().");
        element.addEventListener(type, func, true);
    } else if (element.attachEvent) {     // for IE
//        console.info("Adding on" + type + " event listener with element \"" + elementId + "\" via attachEvent().");
        element.attachEvent("on" + type, func);
    } else if (element.getAttributeNode) {
//        console.info("Adding on" + type + " event listener with element \"" + elementId + "\" via getAttributeNode() etc..");
        var code = "eventHandlers.Invoke(" + elementId + ", " + type + ");";
        var onClickAttrNode = element.getAttributeNode("onclick");
        if (onClickAttrNode) {
            // modify existing onclick event handler
            if (onClickAttrNode.nodeValue)
                onClickAttrNode.nodeValue += " " + code;
            else
                onClickAttrNode.nodeValue = code;
        } else {
            // create and register new onclick event handler
            var onClickAttrNode = document.createAttribute("onclick");
            onClickAttrNode.nodeValue = code;
            element.setAttributeNode(onClickAttrNode);
        }
    } else
        console.error("Cannot add on" + type + " event listener with element \"" + elementId + "\".\nNeither addEventListener() nor attachEvent() nor getAttributeNode() are supported by the browser.");
}


//
// Registers all created event handlers with their respective HTML elements.
//
window.EventHandlers.prototype.RegisterAll = function ()
{
    for (var elementId in this.eventHandlers) {
        var element = document.getElementById(elementId);
        if (element)
            for (var type in this.eventHandlers[elementId]) {
                this.Register(elementId, type, this.eventHandlers[elementId][type].call);
            }
        else
            console.error("Cannot register event handler with element \"" + elementId + "\". No element with the given ID found.");
    }
}


//
// Adds the given commands to the code to execute when the event handler of
// the given type is invoked for the element with the given id.
//
window.EventHandlers.prototype.Add = function ( elementId, type, commands, registerDelayed )
{
    if (typeof registerDelayed == "undefined")
        registerDelayed = false;

    // check if the element with the given ID exists
    var element = document.getElementById(elementId);
    if (!element) {
        console.error("Cannot add event handler for element \"" + elementId + "\". No element with the given ID found.");
        return;
    }

    // check if the given type is supported for the type of the element
    if (!this.CheckType(type, element.nodeName)) {
        console.error("Cannot add event handler for element \"" + elementId + "\". Unknown/unsupported type: \"" + type + "\" for HTML element type \"" + element.nodeName + "\"");
        return;
    }

    // create the list of event handlers by type if it doesn't exist yet
    if (!this.eventHandlers[elementId])
        this.eventHandlers[elementId] = new Array();

    // create the event handler of the given type if it doesn't exist yet
    if (!this.eventHandlers[elementId][type]) {
        // save the given code as the code to execute when the event handler of the given type is invoked for the given element
        this.eventHandlers[elementId][type] = {
            code:
                commands,
            call:
                function (event) {
                    eventHandlers.Invoke(elementId, type);
                }
        }

        if (!registerDelayed)
            this.Register(elementId, type, this.eventHandlers[elementId][type].call);
    } else {
        // add the given commands to the event handler's code
        this.eventHandlers[elementId][type].code += "\n" + commands;
    }
}


//
// Returns the number of event handlers managed by this class.
//
window.EventHandlers.prototype.Count = function ()
{
    return Count(this.eventHandlers);
}


//
// Executes the code associated with the event of the given type for the element with the given id.
//
window.EventHandlers.prototype.Invoke = function ( elementId, type )
{
//        console.info("EventManager_Invoke has been called for element \"" + elementId + "\", type: on" + type + ", code:\n    " + this.eventHandlers[elementId][type].code.replace(/\n/g, '\n    '));
    eval(this.eventHandlers[elementId][type].code);
}


// define event handler types
window.EventHandlers.Type = {
    LOAD      : "load",
    UNLOAD    : "unload",
    ABORT     : "abort",
    ERROR     : "error",
    SELECT    : "select",
    CHANGE    : "change",
    SUBMIT    : "submit",
    RESET     : "reset",
    FOCUS     : "focus",
    BLUR      : "blur",
    RESIZE    : "resize",
    SCROLL    : "scroll",
    CLICK     : "click",
    DBLCLICK  : "dblclick",
    MOUSEOVER : "mouseover",
    MOUSEMOVE : "mousemove",
    MOUSEOUT  : "mouseout",
    MOUSEDOWN : "mousedown",
    MOUSEUP   : "mouseup",
    KEYDOWN   : "keydown",
    KEYPRESS  : "keypress",
    KEYUP     : "keyup"
}
// define event handler types
window.EventHandlers.ValidHtmlElements = {
    LOAD      : ["FRAMESET", "BODY", "OBJECT"],
    UNLOAD    : ["FRAMESET", "BODY", "OBJECT"],
    ABORT     : ["FRAMESET", "BODY", "OBJECT", "IMG"],
    ERROR     : ["FRAMESET", "BODY", "OBJECT", "IMG"],
    SELECT    : ["INPUT", "TEXTAREA"],
    CHANGE    : ["INPUT", "SELECT", "TEXTAREA"],
    SUBMIT    : ["FORM"],
    RESET     : ["FORM"],
    FOCUS     : ["A", "AREA", "BUTTON", "INPUT", "LABEL", "SELECT", "TEXTAREA"],
    BLUR      : ["A", "AREA", "BUTTON", "INPUT", "LABEL", "SELECT", "TEXTAREA"],
    RESIZE    : ["BODY"],
    SCROLL    : ["BODY"],
    CLICK     : "*",
    DBLCLICK  : "*",
    MOUSEOVER : "*",
    MOUSEMOVE : "*",
    MOUSEOUT  : "*",
    MOUSEDOWN : "*",
    MOUSEUP   : "*",
    KEYDOWN   : "*",
    KEYPRESS  : "*",
    KEYUP     : "*"
}


// the one and only instance of the EventHandlers class
window.eventHandlers = new EventHandlers();
