/*global DARTY, window , document, navigator, self, setTimeout, clearInterval, setInterval */
DARTY = DARTY || {};
DARTY.util = DARTY.util || {};
// <dependencies checking>
(function(){// Depends on Init.js, Number.js
    var from = "DARTY.util.Dom";
    var libs = ["DARTY.util.Init","DARTY.util.Number","DARTY.util.Array","DARTY.util.String"];    
	if (DARTY && DARTY.util && DARTY.util.required) {    
        DARTY.util.required(libs, from);
    }
    else {
       if(DARTY && DARTY.DEBUG) {	
        window.alert("Missing library : DARTY.util.Init in " + from);
       } 
    }
})();
// </dependencies checking>
DARTY.util.Dom = function(){
    // definition of  dom variables for internet explorer
    document.ELEMENT_NODE = 1;
    document.TEXT_NODE = 3;
    document.DOCUMENT_NODE = 9;
    document.COMMENT_NODE = 8;
    document.DOCUMENT_FRAGMENT_NODE = 11;
    document.ATTRIBUTE_NODE = 2;
    
    /////////////////////////////////////////////////////////////////
    //--------------- definition of private variables ---------------
    ////////////////////////////////////////////////////////////////
    
    // function variables
    var onload;
    var isOldBrowser;
    var walkTheDom;
	var remove;
	var empty;
	var before;
	var checkElem;
	var append;
	var getParents;
    var id;
    var getElementsByClassName;
	var addClassName;
	var removeClassName;
	var hasClassName;
    var getStyle;
    var pageHeight;
    var pageWidth;
    var windowHeight;
    var windowWidth;
    var setOpacity;
    var hide;
    var show;
    var fadeIn;
    var getWidth;
    var getHeight;
    var scrollY;
    var scrollX;
    var setY;
    var setX;
    var stopBubble;
    var stopDefault;
	var getElementsByAttribute;
	var getElementsByAttributeObjectArg;
	var text;
	var BrowserDetect;
	var isIE;
	var addEvent;
    var removeEvent;
    var handleEvent;
    var fixEvent;
	var domReady;
	var isDOMReady;
	var isDisplayed;
	var all;
	var pageX;
	var pageY;
	var forceRerendering;
	var getEventWrapper;
	//--
	getEventWrapper = function(event) {
	   var _event = event || window.event;
	   var o = {
	     e: event,
	     event: _event,
	     target: _event.target || _event.srcElement,
	     srcElement: _event.target || _event.srcElement, // alias 
	     stopDefault: function() { stopDefault(this.e) },
	     preventDefault: function() { stopDefault(this.e) },
	     stopBubble: function() { stopBubble(this.e); },
	     cancelBubble: function() { stopBubble(this.e); }, // alias
	     getId: function() { return  (this.target)?this.target.id:null; },
	     getClassName: function() { return  (this.target)?this.target.className:null;  },
	     getValue: function() { return  (this.target)?this.target.value:null;  },
	     toString: function() {
	       var str = [ 
	          "return from getEventWrapper",
	          "===========================",
	          "event : " + this.event,
	          "target : " + this.target,
	          "id : " + this.getId(),
	          "className : " +  this.getClassName()
	       ].join("\n");
	       return str;
	     }
	   };
	   //--
	   return o;
	};
	//--
	forceRerendering = function(element){
       if(element) {
	     var n = document.createTextNode(' ');    
	     element.appendChild(n); 
	     n.parentNode.removeChild(n);    
	   }
     return element;    
   };
	//--
	isDisplayed = function(elem){ // get the visual inheritance of 'display:none'
	    var hasDisplayNoneParent;
	    var parentsDisplayed;
	    //--
	    hasDisplayNoneParent = function(_elem){
	        var o = {
	            elem: _elem,
	            func: function(arg){
	                return (getStyle(arg, "display") === 'none');
	            }
	        };
	        parentsDisplayed = getParents(o);
	        //--				
	        return (parentsDisplayed && parentsDisplayed.length >= 1);
	    };
	    //--
	    var retVal = (getStyle(elem, "display") !== 'none') && !hasDisplayNoneParent(elem);
	    return retVal;
	};
	////---------------------------   
    remove = function(elem){// Remove a single Node from the DOM
        if (elem && elem.parentNode) 
            elem.parentNode.removeChild(elem);
    };
    
    // Remove all of an Element's children from the DOM
    empty = function(elem){
        while (elem.firstChild) 
            remove(elem.firstChild);
    };
	
    //--------------------------------------------------------------------------------------------------------------
    // addEvent/removeEventwritten by Dean Edwards, 2005 
    // with input from Tino Zijdel 
    // http://dean.edwards.name/weblog/2005/10/add-event/ 
    //--------------------------------------------------------------------------------------------------------------
    addEvent = function(element, type, handler){
        // assign each event handler a unique ID 
        if (!handler.$$guid) {
            handler.$$guid = 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 hashtable 
        handlers[handler.$$guid] = handler;
        // assign a global event handler to do all the work 
        element["on" + type] = handleEvent;
    };
    // a counter used to create unique IDs 
    addEvent.guid = 1;
    removeEvent = function(element, type, handler){
        // delete the event handler from the hashtable 
        if (element.events && element.events[type]) {
            delete element.events[type][handler.$$guid];
        }
    };
    handleEvent = function(event){
        var returnValue = true;
        // grab the event object (IE uses a global event object) 
        event = event || fixEvent(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) {
            this.$$handleEvent = handlers[i];
            if (this.$$handleEvent(event) === false) {
                returnValue = false;
            }
        }
        return returnValue;
    };
    //Add some "missing" methods to IE's event object 
    fixEvent = function(event){
        // add W3C standard event methods 
        event.preventDefault = fixEvent.preventDefault;
        event.stopPropagation = fixEvent.stopPropagation;
        return event;
    };
    fixEvent.preventDefault = function(){
        this.returnValue = false;
    };
    fixEvent.stopPropagation = function(){
        this.cancelBubble = true;
    };
	// -- 
    //--------------------------------------------------------------------------------------------------------------
    // execute when the dom is ready
	// from John Resig with custom modifications (extraF)
    //--------------------------------------------------------------------------------------------------------------
    domReady = function(f){		
        
        var extraF = function(){
            f();
			
			// iframe cross-browser onload processing  
            var parentIframes;   
            if(DARTY.VARS.SAME_APPLICATION) {    
	            if (window.parent) {
	                parentIframes = window.parent.document.getElementsByTagName('iframe');
	                if (parentIframes && parentIframes.length >= 1) {                
	                    for (var i = 0, length = parentIframes.length; i < length; i++) {
	                        if (parentIframes[i].onready && typeof parentIframes[i].onready === 'function') {
	                            parentIframes[i].onready();                            
	                        }
	                    }
	                }
	            }
            }
        };        
		
        // If the DOM is already loaded, execute the function right away
        if (domReady.done) {
            return extraF();
        }
        
        // If we've already added a function
        if (domReady.timer) {
            // Add it to the list of functions to execute
            domReady.ready.push(extraF);
        }
        else {
            // Attach an event for when the page finishes  loading,
            // just in case it finishes first. Uses addEvent.
            addEvent(window, "load", isDOMReady);
            
            // Initialize the array of functions to execute
            domReady.ready = [extraF];
            
            //  Check to see if the DOM is ready as quickly as possible
            domReady.timer = setInterval(isDOMReady, 13);
        }	
    };	
    
    //--------------------------------------------------------------------------------------------------------------
    // Checks to see if the DOM is ready for navigation
	// from John Resig 
    //--------------------------------------------------------------------------------------------------------------
    isDOMReady = function(){
        // If we already figured out that the page is ready, ignore
        if (domReady.done) {
            return false;
        }
        
        // Check to see if a number of functions and elements are
        // able to be accessed
        if (document && document.getElementsByTagName &&
        document.getElementById &&
        document.body) {
        
            // If they're ready, we can stop checking
            clearInterval(domReady.timer);
            domReady.timer = null;
            
            // Execute all the functions that were waiting
            for (var i = 0, llength = domReady.ready.length ; i < llength; i++) {
				domReady.ready[i]();
			}
            
            // Remember that we're now done
            domReady.ready = null;
            domReady.done = true;
        }
    };
	// --
	isIE = function(){
        var bd = BrowserDetect;
        return bd.browser === 'Explorer';
    };
    //--------------------------------------------------------------------------------------------------------------
    // A Generic Function for Stopping Event Bubbling 
    //--------------------------------------------------------------------------------------------------------------
    stopBubble = function(e){
        if (e && e.stopPropagation) {
            e.stopPropagation();
        }
        else {
            window.event.cancelBubble = true;
        }
    };
    
    //--------------------------------------------------------------------------------------------------------------
    // A Generic Function for Preventing the Default Browser Action from Occurring 
    //--------------------------------------------------------------------------------------------------------------
    stopDefault = function(e){
        //Prevent the default browser action(W3C) 
        if (e && e.preventDefault) {
            e.preventDefault();
        }
        //A shortcut for stoping the browser action in IE 
        else {
           if(window.event) {
              window.event.returnValue = false;
            }
        }
        return false;
    };
    
    //-------------------------------------------------------------
    // assigning body.onload using already defined onload 
    //-------------------------------------------------------------
    onload = domReady;
	/*function(func){
        var wo = window.onload;
        window.onload = function(){
        
            if (wo && typeof wo === 'function') {
                wo();
            }
            
            if (func && typeof func === 'function') {
                func();
            }
        };
        return this;
    };
    */
	
    isOldBrowser = function(){ // ie6 etc...
        if (typeof document.body.style.maxHeight !== "undefined") {
            return false;
        }
        else {
            return true;
        }
    };    
    
    all = function (node) {
    	return node.all || node.getElementsByTagName("*");
    }
    
    walkTheDom = function(node, func){
        var elements = all(node);
        var current; // Declaration outside for performance        
        for (var i=0,llength = elements.length ; i<llength; i++){
			current = elements[i];
			func(current);
		}
    };
    
    //-------------------------------------------------------------
    // A wrapper for retrieving a dom element with a specific id
    //-------------------------------------------------------------
    id = function(ident){
        return document.getElementById(ident);
    };
    
    //-------------------------------------------------------------
    // finding all elements with the className
    //-------------------------------------------------------------
    getElementsByClassName = function(className,elem){
        var results = [];
        var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
        walkTheDom(  elem || document.body, function(node){
            var a, i;
            if(testClass.test(node.className)) {
            	results.push(node);
            }
        });
        return results;
    };
	
	
	//-------------------------------------------------------------
    // an element has a className ?
	// o : { element: [element], className: [className] }
    //-------------------------------------------------------------
	hasClassName = function(o) {		
		if (o && o.className && o.element) {		   	
			var testClass = new RegExp("(^|\\s)" + o.className + "(\\s|$)");
			return testClass.test(o.element.className);
		}	
		return false;
	};
	
	//-------------------------------------------------------------
    // adding a className to an element
    //-------------------------------------------------------------
    addClassName = function(o /* { className: String | Arry of Strings, element : reference of an element node }*/){
        var arrClasses;
		var classNotExist = true;
        if (o && o.className && o.element) {
            if (typeof o.className === 'string') {
                o.className = o.className.trim();
                arrClasses = o.className.split(' ').select(function(item){ //-- TODO : utiliser des expressions reguliere plutot qu'un split
                    return item && typeof item === 'string';
                });
                classNotExist = o.element.className && o.element.className.indexOf(o.className) === -1 || !o.element.className;
                if (arrClasses.length === 1 && classNotExist) {
                    if (!o.element.className) {
                        o.element.className = '';
                    }
                    o.element.className += ' ' + arrClasses[0];
                }
                
                if (arrClasses.length > 1) {
                    addClassName({
                        className: arrClasses,
                        element: o.element
                    });
                }
            }
            
            if (Array.is_array(o.className)) {
                o.className.each(function(item){
                    addClassName({
                        className: item,
                        element: o.element
                    });
                });
            }
        }
    };
	
	//-------------------------------------------------------------
    // removing a className from an element
    //-------------------------------------------------------------
	removeClassName = function(o /* { className: String | Arry of Strings, element : reference of an element node }*/){
        var arrClasses;
		var classNotExist = true;
        if (o && o.className && o.element) {
            if (typeof o.className === 'string') {
                o.className = o.className.trim();
                arrClasses = o.className.split(' ').select(function(item){
                    return item && typeof item === 'string';
                });
                classNotExist = o.element.className && o.element.className.indexOf(o.className) === -1 || !o.element.className;
                
                if (arrClasses.length === 1 && !classNotExist) {                    
                  o.element.className = o.element.className.replace(arrClasses[0],'');
                }
                
                if (arrClasses.length > 1) {
                    removeClassName({
                        className: arrClasses,
                        element: o.element
                    });
                }
            }
            
            if (Array.is_array(o.className)) {
                o.className.each(function(item){
                    removeClassName({
                        className: item,
                        element: o.element
                    });
                });
            }
        }
    };
    // Define a getElementsByAttribute function. It
    // takes an attribute name string and an optional
    // matching value. It calls walkTheDom, passing it a
    // function that looks for an attribute name in the
    // node. The matching nodes are accumulated in a
    // results array.
    getElementsByAttribute = function(att, value){
        var o = { 
                  attName: att,
                  value: value
                };
        return getElementsByAttributeObjectArg(o);
    };
	
	getElementsByAttributeObjectArg = function(o) { /* o = {element: [element], attName: '', value: ''} */
		var results = [];
		if (o && o.attName) {
		    if (o.attName === 'for') {
		        // If the attribute is FOR, just look in the LABEL elements.
		        var elements = document.getElementsByTagName("LABEL");
		        var element_length = elements.length;
		        for (var i = 0; i < element_length; i++) {
		            var element = elements[i];
		            var elementValue = element.htmlFor || element.getAttribute("for");
		            if (o.value === undefined || elementValue === o.value) {
		                results.push(element);
		            }
		        }
		    }
		    else {
		        walkTheDom(o.element || document.body, function(node){
		            var actual = function(){
		                var result;
		                try {
		                    result = node.nodeType === 1 && node.getAttribute(o.attName);
		                } 
		                catch (e) {
		                    // nothing
		                }
		                return result;
		            }();
		            
		            if (typeof actual === 'string' && (actual === o.value || typeof o.value !== 'string')) {
		                results.push(node);
		            }
		        });
		    }
		}
	    return results;
	};
	
	// Getting all parents validating func
	// o : {elem:[dom element], num: [integer], func:[function]}
	getParents = function(o) {
		var elem;
		var num;		
		var func;
		
		if (o) {
			elem = o.elem;
			num = o.num;
			func = o.func;
		}
		
		var arrResult = [];
		var result = elem;
		var incr = 0;
        while ( elem && (!num || num && incr < num) ) {
			elem = elem.parentNode;
            if (elem && elem.nodeType === document.ELEMENT_NODE && (!func || func && typeof func === 'function' && func(elem))) {
               result = elem;
			   arrResult.push(elem);
			   incr += 1;
            }
        }
		return arrResult;
	};
	
    //----------------------------------------------------------------------------------------
    // A Method for Finding the Actual Computed Value of a CSS Style Property on an Element 
    //----------------------------------------------------------------------------------------
    // Get a style property (name) of a specific element (elem)
    getStyle = function(elem, name){
        // If the property exists in style[], then it's been set recently (and is current)
        if (elem.style[name]) {
            return elem.style[name];
        }
        
        // Otherwise, try to use IE's method
        if (elem.currentStyle) {
            return elem.currentStyle[name];
        }

		// Or the W3C's method, if it exists
        if (document.defaultView && document.defaultView.getComputedStyle) {
            // It uses the traditional 'text-align' style of rule writing, instead of textAlign
            name = name.replace(/([A-Z])/g, "-$1");
            name = name.toLowerCase();
            
            // Get the style object and get the value of the property (if it exists)
            var s = document.defaultView.getComputedStyle(elem, "");
            return s && s.getPropertyValue(name);
        }

        // Otherwise, we're using some other browser : no style.
        return null;
    };
    
    //--------------------------------------------------------------------------------------------------------------
    // A Generic Function for Retreiving the Text Contents of an Element 
    //--------------------------------------------------------------------------------------------------------------
    text = function (e){
        var t = "";
		if (e) {
			// If an element was passed, get its children, 
			// otherwise assume it's an array 
			e = e.childNodes || e;
			// Look throughall child nodes 
			for (var j = 0; j < e.length; j +=1 ) {
				// If it's not an element, append its text value 
				// Otherwise, recurse through all the element's children 
				t += e[j].nodeType !== 1 ? e[j].nodeValue : text(e[j].childNodes);
			}
		}
        // Return the matched text 
        return t;
    };
    
    // Find the X (Horizontal, Left) position of an element
	pageX = function (elem){
	    // See if we're at the root element, or not
	    return elem.offsetParent ?    // If we can still go up, add the current offset and recurse upwards
	    elem.offsetLeft + pageX(elem.offsetParent) :    // Otherwise, just get the current offset
	    elem.offsetLeft;
	};
	
	// Find the Y (Vertical, Top) position of an element
	pageY = function (elem){
	    // See if we're at the root element, or not
	    return elem.offsetParent ?    // If we can still go up, add the current offset and recurse upwards
	    elem.offsetTop + pageY(elem.offsetParent) :    // Otherwise, just get the current offset
	    elem.offsetTop;
	};    
	
    // Returns the height of the web page
    // (could change if new content is added to the page)
    pageHeight = function(){
        return document.body.scrollHeight;
    };
    
    // Returns the width of the web page
    pageWidth = function(){
        return document.body.scrollWidth;
    };
    
    // Find the height of the viewport
    windowHeight = function(){
        // A shortcut, in case we're using Internet Explorer 6 in Strict Mode
        var de = document.documentElement;
        // If the innerHeight of the browser is available, use that
        return self.innerHeight ||
        // Otherwise, try to get the height off of the root node
        (de && de.clientHeight) ||
        // Finally, try to get the height off of the body element
        document.body.clientHeight;
    };
    
    // Find the width of the viewport
    windowWidth = function(){
        // A shortcut, in case we're using Internet Explorer 6 in Strict Mode
        var de = document.documentElement;
        // If the innerWidth of the browser is available, use that
        return self.innerWidth ||
        // Otherwise, try to get the width off of the root node
        (de && de.clientWidth) ||
        // Finally, try to get the width off of the body element
        document.body.clientWidth;
    };
    
    // Get the actual height (using the computed CSS) of an element
    getHeight = function(elem){
        // Gets the computed CSS value and parses out a usable number
        return parseInt(getStyle(elem, 'height'), 10) ? parseInt(getStyle(elem, 'height'), 10) : elem.clientHeight;
    };
    
    // Get the actual width (using the computed CSS) of an element
    getWidth = function(elem){
        // Gets the computed CSS value and parses out a usable number
        return parseInt(getStyle(elem, 'width'), 10) ? parseInt(getStyle(elem, 'width'), 10) : elem.clientWidth;
    };
    
    // A function for determining how far horizontally the browser is scrolled
    scrollX = function(){
        // A shortcut, in case we're using Internet Explorer 6 in Strict Mode
        var de = document.documentElement;
        // If the pageXOffset of the browser is available, use that
        return self.pageXOffset ||
        // Otherwise, try to get the scroll left off of the root node
        (de && de.scrollLeft) ||
        // Finally, try to get the scroll left off of the body element
        document.body.scrollLeft;
    };
    
    // A function for determining how far vertically the browser is scrolled
    scrollY = function(){
        // A shortcut, in case we're using Internet Explorer 6 in Strict Mode
        var de = document.documentElement;
        // If the pageYOffset of the browser is available, use that
        return self.pageYOffset ||
        // Otherwise, try to get the scroll top off of the root node
        (de && de.scrollTop) ||
        // Finally, try to get the scroll top off of the body element
        document.body.scrollTop;
    };
    
    // A function for setting the horizontal position of an element
    setX = function(elem, pos){
        // Set the 'left' CSS property, using pixel units
        elem.style.left = pos + "px";
		return this;
    };
    
    // A function for setting the vertical position of an element
    setY = function(elem, pos){
        // Set the 'top' CSS property, using pixel units
        elem.style.top = pos + "px";
		return this;
    };
    
    //--------------------------------------------------------------------------------------------------------------
    // A Function for Adjusting the Opacity Level of an Element
    //--------------------------------------------------------------------------------------------------------------
    // Set an opacity level for an element
    // (where level is a number 0-100)
    setOpacity = function(elem, level){
        // If filters exist, then this is IE, so set the Alpha filter
        if (elem.filters /* elem.style.filter === '' || elem.style.filter !== '' && elem.style.filter */ ) { // hasOwnProperty('filter') doesn't work here
     		elem.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=' + level + ')';
        }
        // Otherwise use the W3C opacity property
        else {
            elem.style.opacity = level / 100;
        }
		return this;
    };
    
    // A Method for hiding (using display) an element
    hide = function(elem){
        // Find out what it's current display state is
        var curDisplay = getStyle(elem, 'display');
        
        //  Remember its display state for later
        if (curDisplay !== 'none') {
            elem.$oldDisplay = curDisplay;
        }
        
        // Set the display to none (hiding the element)
        elem.style.display = 'none';
		
		return this;
    };
    
    
    // A function for showing (using display) an element
    show = function(elem){
        // Set the display property back to what it use to be, or use
        // 'block', if no previous display had been saved
        elem.style.display = elem.$oldDisplay || 'block';
		return this;
    };
    
    //--------------------------------------------------------------------------------------------------------------
    // A Function for Slowly Revealing a Hidden Element by Increasing Its Opacity Over a
    // Matter of One Second
    //--------------------------------------------------------------------------------------------------------------
    fadeIn = function(elem, ops, ope){
        var opstart = function(){ // opacity start
            if (ops && DARTY.util.Number.isNumber(ops) && ops <= 100 && ops >= 0) {
                return ops;
            }
            else {
                return 0;
            }
        }();
        
        var opend = function(){ // opacity end
            if (ope && DARTY.util.Number.isNumber(ope) && ope <= 100 && ope >= 0 && opstart < ope) {
                return ope;
            }
            else {
                return 100;
            }
        }();
		
		var delta = (opend - opstart)/20;
        
        // Start the opacity at  0
        setOpacity(elem, opstart);
        
        // Show the element (but you can see it, since the opacity is 0)
        show(elem);
        
        // We're going to do a 20 'frame' animation that takes
        // place over one second		
        for (var i = opstart; i <= opend; i += delta) {
            // A closure to make sure that we have the right 'i'
            (function(pos){
                // Set the timeout to occur at the specified time in the future
                setTimeout(function(){
                    // Set the new opacity of the element
                    setOpacity(elem, pos);
                }, (pos + 1) * delta);
            })(i);
        }
		return this;
    };
	
    //--------------------------------------------------------------------------------------------------------------
    // A Helper Function for the before and append() Functions
    //--------------------------------------------------------------------------------------------------------------
    checkElem = function(a){
        var r = [];
        // Force the argument into an array, if it isn't already
        if (a.constructor !== Array) {
            a = [a];
        }
        
        for (var i = 0; i < a.length; i +=1) {
            // If there's a String
            if (a[i].constructor === String) {
                // Create a temporary element to house the HTML
                var div = document.createElement("div");
                
                // Inject the HTML, to convert it into a DOM structure
                div.innerHTML = a[i];
                
                // Extract the DOM structure back out of the temp DIV
                for (var j = 0; j < div.childNodes.length; j+=1) {
                    r[r.length] = div.childNodes[j];
                }
            }
            else 
                if (a[i].length) { // If it's an array
                    // Assume that it's an array of DOM Nodes
                    for (var k = 0; k < a[i].length; k+=1) {
                        r[r.length] = a[i][k];
                    }
                }
                else { // Otherwise, assume it's a DOM Node
                    r[r.length] = a[i];
                }
        }
        return r;
    };
	
    //--------------------------------------------------------------------------------------------------------------
    // A Function for Inserting an Element Before Another Element
    //--------------------------------------------------------------------------------------------------------------
    before = function(parent, beforeElem, elem){
        // Check to see if no parent node was provided
        if (elem === null) {
            elem = beforeElem;
            beforeElem = parent;
            parent = beforeElem.parentNode;
        }
        
        // Get the new array of elements
        var elems = checkElem(elem);
        
        // Move through the array backwards,
        // because we're prepending elements
        for (var i = elems.length - 1; i >= 0; i-=1) {
            parent.insertBefore(elems[i], beforeElem);
        }
    };    
	
    //--------------------------------------------------------------------------------------------------------------
    // A Function for Appending an Element As a Child of Another Element
    //--------------------------------------------------------------------------------------------------------------
    append = function(parent, elem){
        // Get the array of elements
        var elems = checkElem(elem);
        
        // Append them all to the element
        for (var i = 0; i <= elems.length; i+=1) {
            parent.appendChild(elems[i]);
        }
    };    
    
    ///////////////////////////////////////////////////////////////////////////////////// 
    //  Browser Detection from quirksMode : http://www.quirksmode.org/js/detect.html
    //  Usage:  
    //     * Browser name: BrowserDetect.browser
    //     * Browser version: BrowserDetect.version
    //     * OS name: BrowserDetect.OS
    ///////////////////////////////////////////////////////////////////////////////////
    BrowserDetect = ({
        init: function(){
            this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
            this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version";
            this.OS = this.searchString(this.dataOS) || "an unknown OS";
            return this; // local customisation
        },
        searchString: function(data){
            for (var i = 0; i < data.length; i += 1) {
                var dataString = data[i].string;
                var dataProp = data[i].prop;
                this.versionSearchString = data[i].versionSearch || data[i].identity;
                if (dataString) {
                    if (dataString.indexOf(data[i].subString) !== -1) {
                        return data[i].identity;
                    }
                }
                else 
                    if (dataProp) {
                        return data[i].identity;
                    }
            }
        },
        searchVersion: function(dataString){
            var index = dataString.indexOf(this.versionSearchString);
            if (index === -1) {
                return;
            }
            return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
        },
        dataBrowser: [{
            string: navigator.userAgent,
            subString: "OmniWeb",
            versionSearch: "OmniWeb/",
            identity: "OmniWeb"
        }, {
            string: navigator.vendor,
            subString: "Apple",
            identity: "Safari"
        }, {
            prop: window.opera,
            identity: "Opera"
        }, {
            string: navigator.vendor,
            subString: "iCab",
            identity: "iCab"
        }, {
            string: navigator.vendor,
            subString: "KDE",
            identity: "Konqueror"
        }, {
            string: navigator.userAgent,
            subString: "Firefox",
            identity: "Firefox"
        }, {
            string: navigator.vendor,
            subString: "Camino",
            identity: "Camino"
        }, { // for newer Netscapes (6+)
            string: navigator.userAgent,
            subString: "Netscape",
            identity: "Netscape"
        }, {
            string: navigator.userAgent,
            subString: "MSIE",
            identity: "Explorer",
            versionSearch: "MSIE"
        }, {
            string: navigator.userAgent,
            subString: "Gecko",
            identity: "Mozilla",
            versionSearch: "rv"
        }, { // for older Netscapes (4-)
            string: navigator.userAgent,
            subString: "Mozilla",
            identity: "Netscape",
            versionSearch: "Mozilla"
        }],
        dataOS: [{
            string: navigator.platform,
            subString: "Win",
            identity: "Windows"
        }, {
            string: navigator.platform,
            subString: "Mac",
            identity: "Mac"
        }, {
            string: navigator.platform,
            subString: "Linux",
            identity: "Linux"
        }]
    }).init();
    
    ///////////////////////////////////////////////
    // ------------- public properties & methods     
    //////////////////////////////////////////////
    
    return {
		hasClassName: hasClassName,
        onload: onload,
        addEvent: addEvent,
        removeEvent: removeEvent,
		remove: remove,
		empty: empty,
        id: id,
        before: before,
        append: append,
        walkTheDom: walkTheDom,
        getElementsByClassName: getElementsByClassName,
		addClassName: addClassName,
		removeClassName: removeClassName,
        getElementsByAttribute: getElementsByAttribute,
        getElementsByAttributeObjectArg: getElementsByAttributeObjectArg,
        getParents: getParents,
        getStyle: getStyle,
        text: text,
        pageHeight: pageHeight,
        pageWidth: pageWidth,
        windowHeight: windowHeight,
        windowWidth: windowWidth,
        setOpacity: setOpacity,
        hide: hide,
        show: show,
        fadeIn: fadeIn,
		isIE: isIE,
        isOldBrowser: isOldBrowser,
        BrowserDetect: BrowserDetect,
        getHeight: getHeight,
        getWidth: getWidth,
        scrollY: scrollY,
        scrollX: scrollX,
        setY: setY,
        setX: setX,
        pageX: pageX,
        pageY: pageY,
        stopBubble: stopBubble,
        stopDefault: stopDefault,
        isDisplayed: isDisplayed,
        forceRerendering: forceRerendering,
        getEventWrapper: getEventWrapper
    };
}();

