// --------------------------------------------------------------------------------
// ow_util.js
// Matthew Hogg 15-Nov-2004
// Contains various useful functions, used for functionality of front-end apps.
// Updated Feb 19, 2008 to modernize javascript
// --------------------------------------------------------------------------------
// create the OneWeb object
var OneWeb = {};
// --- Functions and variables. ---
// Create a util namespace
OneWeb.Util = {
//    _owu:OneWeb.Util,
    "_loadAfterInitQueue": [],
    "_pollForDOMCounter": 0,
    "_pollForDOMInterval": null,
    // --------------------------------------------------------------------------------
    // addEvent()
    "addEvent": function (element, type, handler, useCapture) {
        /// <summary>Attach an event handler to an element.</summary>
        /// <param name="element">element to assign event handler to [object]</param>
        /// <param name="type">event to handle (i.e. "load", "click") [string]</param>
        /// <param name="handler">function which will handle the event [function]</param>
        /// <param name="useCapture"> use Event capturing model? [boolean]</param>
        /// <remarks>Based on a version of addEvent/removeEvent created by Dean Edwards (http://dean.edwards.name/weblog/2005/10/add-event/)
        /// and Tino Zijdel (http://therealcrisp.xs4all.nl/upload/addEvent_dean.html)</remarks>
        /// <returns>void</returns>
        if (element.addEventListener) {
            element.addEventListener(type, handler, useCapture);
        } else {
            // assign each event handler a unique ID
            if (!handler.$$guid) handler.$$guid = (typeof(OneWeb.Util.addEvent.guid)=="undefined") ? OneWeb.Util.addEvent.guid = 1 : ++OneWeb.Util.addEvent.guid;
            // create a hash table of event types for the element
            if (!element.events) element.events = {};
            // create a hash table of event handlers for each element/event pair
            var handlers = element.events[type];
            if (!handlers) {
                handlers = element.events[type] = {};
                // store the existing event handler (if there is one)
                if (element["on" + type]) {
                    handlers[0] = element["on" + type];
                }
            }
            // store the event handler in the hash table
            handlers[handler.$$guid] = handler;
            // assign a global event handler to do all the work
            element["on" + type] = OneWeb.Util._handleEvent;
        }
    },
    // --------------------------------------------------------------------------------
    // removeEvent()
    "removeEvent": function (element, type, handler, useCapture) {
        /// <summary>Attach an event handler to an element.</summary>
        /// <param name="element">element to remove event handler from [object]</param>
        /// <param name="type">event to handle (i.e. "load", "click") [string]</param>
        /// <param name="handler">function which handled the event [function]</param>
        /// <param name="useCapture"> use Event capturing model? [boolean]</param>
        /// <remarks>Based on a version of addEvent/removeEvent created by Dean Edwards (http://dean.edwards.name/weblog/2005/10/add-event/)
        /// and Tino Zijdel (http://therealcrisp.xs4all.nl/upload/addEvent_dean.html)</remarks>
        /// <returns>void</returns>
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, useCapture);
        } else {
            // delete the event handler from the hash table
            if (element.events && element.events[type] && handler.$$guid) {
                delete element.events[type][handler.$$guid];
            }
        }
    },
    // --------------------------------------------------------------------------------
    // _handleEvent()
    "_handleEvent": function (event) {
        /// <summary>Used internally to handle events in a standard fasion in non-standard browsers (IE).</summary>
        var returnValue = true;
        // grab the event object (IE uses a global event object)
        event = event || OneWeb.Util._fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
        // get a reference to the hash table of event handlers
        var handlers = this.events[event.type];
        // execute each event handler
        for (var i in handlers) {
            if (!Object.prototype[i]) {
                this.$$handleEvent = handlers[i];
                if (this.$$handleEvent(event) === false) {
                    returnValue = false;
                    break;
                }
            }
        }
        // detach last event handler from the element
        if (this.$$handleEvent)
            this.$$handleEvent = null;
        return returnValue;
    },
    "_fixEvent": function (event) {
        /// <summary>Used internally to add W3C standard event methods to IE event objectss.</summary>
        event.preventDefault = function () { this.returnValue = false; };
        event.stopPropagation = function () { this.cancelBubble = true; };
        return event;
    },
    // --------------------------------------------------------------------------------
    // appendLoadEvent()
    "appendLoadEvent": function(f) {
        /// <summary>Append a function to be executed when the onload event fires.</summary>
        /// <param name="f">function to be appended [function]</param>
        /// <returns>void</returns>
        OneWeb.Util.addEvent(window, "load", f);
//        var oldonload = window.onload;
//      
//        if (typeof window.onload != "function") {
//            window.onload = f;
//        } else {
//            window.onload = function() {
//                oldonload();
//                f();
//            }
//        }
    },
    // --------------------------------------------------------------------------------
    // appendUnloadEvent()
    "appendUnloadEvent": function(f) {
        /// <summary>Append a function to be executed when the onunload event fires.</summary>
        /// <param name="f">function to be appended [function]</param>
        /// <returns>void</returns>
        OneWeb.Util.addEvent(window, "unload", f);
//        var oldonunload = window.onunload;
//        if (typeof window.onunload != "function") {
//            window.onunload = f;
//        } else {
//            window.onunload = function() {
//                oldonunload();
//                f();
//            }
//        }
    },
    
    // --------------------------------------------------------------------------------
    // appendInitEvent()
    "appendInitEvent": function(f) {
        /// <summary>Appends a function to be executed when the DOM if fully initialised.  This method
        ///    simply adds the function pointer to the queue of other initializers.</summary>
        /// <param name="f">function to be appended [function]</param>
        /// <returns>void</returns>
        OneWeb.Util.addEvent(window, "load", f);
    /*    IE is having a hard time with hard-refreshes not running these scripts
        OneWeb.Util._loadAfterInitQueue.push(f);
        if (!OneWeb.Util._pollForDOMInterval)
            OneWeb.Util._runInitMethods();
        */
    },
    
    // --------------------------------------------------------------------------------
    // _isDOMInitialized()
    "_isDOMInitialized": function() {
        /// <summary>Checks to see if the DOM is initialized (full DOM hierarchy created).</summary>
        /// <returns>boolean</returns>
        return (typeof document.getElementsByTagName != "undefined" 
                && (document.getElementsByTagName("body")[0] != null || document.body != null));
    },
    // --------------------------------------------------------------------------------
    // _pollForDOM()
    "_pollForDOM": function() {
        /// <summary>Polls the DOM for full initialization (full DOM hierarchy created).</summary>
        /// <returns>void</returns>
        OneWeb.Util._pollForDOMCounter++;
        if (OneWeb.Util._isDOMInitialized()) {
            OneWeb.Util._runInitMethods();
            window.clearInterval(OneWeb.Util._pollForDOMInterval);
            OneWeb.Util._pollForDOMInterval = null;
        } else if (OneWeb.Util._pollForDOMCounter == 10) { 
            // reset the interval to 250ms from 50 ms
            window.clearInterval(OneWeb.Util._pollForDOMInterval);
            OneWeb.Util._pollForDOMInterval = window.setInterval(OneWeb.Util._isDOMInitialized, 250);
        } else if (OneWeb.Util._pollForDOMCounter >= 60) { 
            // reset the interval to 1 sec
            window.clearInterval(OneWeb.Util._pollForDOMInterval); 
            OneWeb.Util._pollForDOMInterval = window.setInterval(OneWeb.Util._isDOMInitialized, 1000);
        }
    },
    // --------------------------------------------------------------------------------
    // _runInitMethods()
    "_runInitMethods": function() {
        /// <summary>Runs the initialization methods.</summary>
        /// <returns>void</returns>
        for (var i = 0; i < OneWeb.Util._loadAfterInitQueue.length; i++) {
            try {
                OneWeb.Util._loadAfterInitQueue[i]();
            } catch(ex) {
                var fn = OneWeb.Util._loadAfterInitQueue[i] + "";
                fn = fn.substring(fn.indexOf(" ") + 1, fn.indexOf("("));
                alert("ERROR!\nThe function " + fn + "() was found in the DOM queue but could not be executed.\n" + ex.description);
            }
        }
        OneWeb.Util._loadAfterInitQueue.length = 0;
    },
    // --------------------------------------------------------------------------------
    // stopEventProp()
    "stopEventProp": function (e) {
        /// <summary>Prevent triggered events from propogating to parent elements.
        ///    <param name="e">triggered event [object]</param>
        /// <returns>void</returns>
        if (!e) var e = window.event;
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
        return true;
    },
    // --------------------------------------------------------------------------------
    // preventDefault()
    "preventDefault": function (e) {
        /// <summary>Prevent triggered events from executing their default action.</summary>
        ///    <param name="e">triggered event [object]</param>
        /// <returns>void</returns>
        if (!e) var e = window.event;
        if (e.preventDefault) { e.preventDefault(); } else { e.returnValue = false; }
    },
            
    // --------------------------------------------------------------------------------
    // addSubmitEvent()
    "addSubmitEvent": function(elm, fn) {
        /// <summary>Attach an osubmit event handler.</summary>
        /// <param name="elm">form element to assign event handler to [object]</param>
        /// <param name="fn">function which will handle the event [function]</param>
        /// <returns>void</returns>
        var _fn = function(e) { var r = fn(e); if (r===false) e.preventDefault(); return r; }
        OneWeb.Util.addEvent(elm, "submit", _fn);
/*        var oldsubmit = elm.onsubmit;
      
        if (typeof elm.onsubmit != "function") {
            elm.onsubmit = fn;
        } else {
            elm.onsubmit = function() {
                return oldsubmit() ? fn() : false;
            }
        } */
    },
    // --------------------------------------------------------------------------------
    // detachEvents()
    "detachEvents": function (elm) {
        /// <summary>Detaches all event handlers from an element and its children.</summary>
        /// <param name="elm">element to detach event handlers from [object]</param>
        /// <returns>void</returns>
        if (!elm)
            return;
            
        var a = elm.attributes, i, l, n;
        if (a) {
            l = a.length;
            for (i = 0; i < l; i += 1) {
                n = a[i].name;
                if (typeof elm[n] === "function") {
                    elm[n] = null;
                }
            }
        }
        a = elm.childNodes;
        if (a) {
            l = a.length;
            for (i = 0; i < l; i += 1) {
                OneWeb.Util.detachEvents(elm.childNodes[i]);
            }
        }
    },

    // --------------------------------------------------------------------------------
    // getElementsByClassName()
    "getElementsByClassName": function(cls, tag) {
        /// <summary>Find all document elements with the specified CSS class attribute.</summary>
        ///    <param name="cls">class name to be searched for [string]</param>
        ///    <param name="tag">search for specific tags with givn class, or "*" for all [string]</param>
        /// <returns>all elements with the specified class [array]</returns>
        /// --------------------------------------------------------------------------------
        var arr = [];
        var j = 0;
        var i;
        var elm = document.getElementsByTagName(tag);
        
        var re = new RegExp("(^|\\s)" + cls + "(\\s|$)");
        for (i = 0; i < elm.length; i++) {
            if (re.test(elm[i].className)) {
                arr[j] = elm[i];
                j++;
            }
        }
        return arr;
    },
    
    // --------------------------------------------------------------------------------
    // getTotalOffset()
    "getTotalOffset": function (elm, off) {
        /// <summary>Compute the total offset of an element from the top-left corner of the screen.</summary>
        /// <param name="elm">element to calculate the offset for [object]</param>
        /// <param name="off">type of offset to calculate (i.e. "offsetLeft", "offsetTop") [string]</param>
        /// <returns>total calculated offset for specified element [integer]</returns>
        var totalOffset = 0;
        var item = eval("elm");
        
        do {
            totalOffset += eval("item." + off);
            item = eval("item.offsetParent");
        } while (item != null);
        return totalOffset;
    },
    // getElementStyle()
    "getElementStyle": function (elm, prop) {
        /// <summary>Get current value of a CSS style property for a specified element.</summary>
        ///    <param name="elm">element to find a style for [object]</param>
        ///    <param name="prop">name of property to find value for (i.e. "margin-top") [string]</param>
        /// <returns>current value of specified property [string]</returns>
        if (window.getComputedStyle) {
            return window.getComputedStyle(elm, null).getPropertyValue(prop);
        } else if (elm.currentStyle) {
            var ieProp = "";
            for (var i = 0; i < prop.length; i++) {
                if (prop.charAt(i) == "-") {
                    i++;
                    ieProp += prop.charAt(i).toUpperCase();
                } else {
                    ieProp += prop.charAt(i);
                }
            }
            return eval("elm.currentStyle." + ieProp);
        }
    },
    // --------------------------------------------------------------------------------
    // runInitializers()
    "runInitializers": function() {
        /// <summary>Run the initialization functions, or schedule them for running.</summary>
        /// <returns>void</returns>
        if (OneWeb.Util._isDOMInitialized()) 
            OneWeb.Util._runInitMethods() 
        else
            OneWeb.Util._pollForDOMInterval = window.setInterval(OneWeb.Util._pollForDOM, 50);
    },
    
    "_getEngineVersion": function () {
        var engine = { "name":null, "version":null, "major":0, "minor":0, "revision":0, "build":0, "prerelease":""};
        var ua = navigator.userAgent.toLowerCase();
        var engRegex = null;
        if (ua.match(/rv\:[^)]+\).*gecko\/\d{8}/)!=null) {
            // Gecko
            engine.name = "Gecko"
            engRegex = /rv\:([^)]+)\)/;
        } else if (ua.match(/msie [\d\.\w]+;.*windows/)!=null) {
            engine.name = "Trident";
            engRegex = /msie ([\d\.\w]+);/;
        } else if (ua.match(/applewebkit\/[\d\.\w]+ /)!=null) {
            engine.name = "WebKit";
            engRegex = /applewebkit\/([\d\.\w]+) /;
        } else if (ua.match(/opera[\/ ][\d\.\w]+/)!=null) {
            engine.name = "Opera";
            engRegex = /opera[\/ ]([\d\.\w]+)/;
        }
        if (engRegex != null) {
            var version = engRegex.exec(ua);
            if (version != null) {
                engine.version = version[1];
                engine.versionParts = engine.version.split(".");
                for (var i = 0; i < engine.versionParts.length; i++) {
                    if (engine.versionParts[i] == null) 
                        engine.versionParts[i] = "";
                    var part = parseInt(engine.versionParts[i]);
                    if (isNaN(part))
                        part = 0;
                    switch(i) {
                        case 0: engine.major = part; break;
                        case 1: engine.minor = part; break;
                        case 2: engine.revision = part; break;
                        case 3: engine.build = part; break;
                    }
                    // check for pre-release signature
                    if (i==engine.versionParts.length-1 && engine.versionParts[i].length > 0 && (engine.versionParts[i] != part.toString() || part == 0))
                        engine.prerelease = engine.versionParts[i].substr(part.toString().length);
                }
                engine.toString = function() { return this.name + ":" + this.version; }
            }
        }
        return engine;
    }
};
//shims
var ow_f_AppendInitEvent = OneWeb.Util.appendInitEvent;
var ow_f_AppendLoadEvent = OneWeb.Util.appendLoadEvent;
var ow_f_AppendUnloadEvent = OneWeb.Util.appendUnloadEvent;
var ow_f_AddEvent = OneWeb.Util.addEvent;
var ow_f_RemoveEvent = OneWeb.Util.removeEvent;
var ow_f_GetElementsByClassName = OneWeb.Util.getElementsByClassName;
var ow_f_GetTotalOffset = OneWeb.Util.getTotalOffset;
var ow_f_GetElementStyle = OneWeb.Util.getElementStyle;
var ow_f_StopEventProp = OneWeb.Util.stopEventProp;
var ow_f_PreventDefault = OneWeb.Util.preventDefault;

// default initialization functions
// --------------------------------------------------------------------------------
// searchOnEnter()
OneWeb._searchOnEnter = function(e) {
    /// <summary>Click the corresponding search button when [ENTER] is pressed.</summary>
    /// <param name="e">event object</param>
    /// <returns>void</returns>
    var code;
    if (!e) var e = window.event;
    if (e.keyCode) code = e.keyCode;
    else if (e.which) code = e.which;
    if (code == 13) {
        var elm = null;
        if (e.target) elm = e.target;
        else elm = e.srcElement;
        var btn = document.getElementById((elm.id).replace("ow_txt", "ow_btn"));
        if (btn) {
            btn.click();
            if (e.preventDefault) e.preventDefault(); else e.returnValue = false;
        } else {
            var img = document.getElementById((elm.id).replace("ow_txt", "ow_img"));
            if (img) {
                img.click();
                if (e.preventDefault) e.preventDefault(); else e.returnValue = false;
            }
        }
    }
}
// --------------------------------------------------------------------------------
// initSearchBox()
OneWeb._initSearchBox = function() {
    /// <summary>Find all search textfields and wire up the [ENTER] key to submit the form properly.</summary>
    /// <returns>void</returns>
    var txt;
    var inp = OneWeb.Util.getElementsByClassName("ow_sbox", "input");
    for (var i = 0; i < inp.length; i++) {
        if (inp[i].id.indexOf("ow_txtSearch") != -1) {
                OneWeb.Util.addEvent(inp[i], "keypress", OneWeb._searchOnEnter, false);
        }
    }
}
// --------------------------------------------------------------------------------
// _initAutoComplete()
OneWeb._initAutoComplete = function () {
    /// <summary>Find all hidden input fields and disable the autocomplete, which tends to 
    /// screw up event validation by maintaining stale values in ajax scenarios.</summary>
    /// <returns>void</returns>
    var inputs = document.getElementsByTagName("INPUT");
    for (var i = 0; i < inputs.length; i++) {
        if (inputs[i].getAttribute("type") == "HIDDEN")
            inputs[i].setAttribute("autocomplete", "off");
    }
}
// --------------------------------------------------------------------------------
// Initialize()
/// <summary>Initializes the OneWeb javascript</summary>
/// <returns>void</returns>
OneWeb.initialize = function() {
    OneWeb.Util.engine = OneWeb.Util._getEngineVersion();
    OneWeb.Util.appendInitEvent(OneWeb._initSearchBox);
    OneWeb.Util.runInitializers();
    
    // This little snippet fixes the problem that the onload attribute on the body-element will overwrite
    // previous attached events on the window object for the onload event
    if (!window.addEventListener) {
        document.onreadystatechange = function() {
            if (window.onload && window.onload != OneWeb.Util._handleEvent)    {
                OneWeb.Util.addEvent(window, 'load', window.onload);
                window.onload = OneWeb.Util._handleEvent;
            }
        }
    }
}
// --------------------------------------------------------------------------------
// immediate calls
OneWeb.initialize();
