// Copyright (c) 2006 Central Desktop Inc. 



/************** START dom.utils.js ***************/


/**
 * @author     Philip Snyder <philip.r.snyder@gmail.com>
 * @copyright  Copyright &copy; 2005-2009, Philip Snyder
 */

/**
 * dom.utils function namespace
 *
 *
 * @access public
 * @since  v1.1
 */
if (typeof dom == 'undefined') var dom = new Object;
if (typeof dom.utils == 'undefined') dom.utils = new Object;



/**
 * Returns the first child node matching nodeName (tagName)
 */
dom.getNext = function(node, nodeName) {
    for (var i=0; i<node.childNodes.length; i++) {
        var tNode = node.childNodes[i];
        if (tNode.nodeType==1 && tNode.nodeName.toLowerCase() == nodeName.toLowerCase()) return tNode;
    }
    return false;
}
//Element.getNext = function(nodeName) { dom.getNext(this, nodeName); }

dom.utils.stripIds = function(node) {
    var stack = new Array;
    stack[stack.length] = node;
    while (stack.length > 0) {
        var n = stack.shift();
        if (node.nodeType == Node.ELEMENT_NODE) {
            if (n.id) {
                n.removeAttribute('id');
            }
            if (n.hasChildNodes()) {
                var children = n.childNodes;
                for (var i=0; i<children.length; i++) {
                    stack.push(children[i]);
                }
            }
        }
    }
    return node;
}


dom.utils.getMouseCoords = function(ev) {
    if (ev.pageX || ev.pageY) {
        return {x:ev.pageX, y:ev.pageY};
    }
    return {
        x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
        y:ev.clientY + document.body.scrollTop    - document.body.clientTop
    };
}

dom.utils.getMouseOffset = function(target, ev) {
    ev = ev || window.event;
    var docPos    = dom.utils.getPosition(target);
    var mousePos    = dom.utils.mouseCoords(ev);
    return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}


dom.utils.scrollTo = function(targetElem) {
    var tTop = dom.utils.getElementTop(targetElem);
    window.scrollTo(0,tTop);
}




/**
 * Browser detection function namespace
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
dom.utils.browser = new Object;

/**
 * RegEx definitions for browser detections based on property tested
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
dom.utils.browser.regexes = {
    overflowX: new Array(/Firefox\/1\.0/),
    overflowY: new Array(/Firefox\/1\.0/)
};

/**
 * Determines if the browser supports CSS overflowX property correctly
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
dom.utils.browser.supportsOverflowX = function() {
    for (var i=0; i<dom.utils.browser.regexes.overflowX.length; i++) {
        var regex = dom.utils.browser.regexes.overflowX[i];
        if (navigator.userAgent.match(regex)) {
            return false;
        }
    }
    return true;
}

/**
 * Determines if the browser supports CSS overflowY property correctly
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
dom.utils.browser.supportsOverflowY = function() {
    for (var i=0; i<dom.utils.browser.regexes.overflowY.length; i++) {
        var regex = dom.utils.browser.regexes.overflowY[i];
        if (navigator.userAgent.match(regex)) {
            return false;
        }
    }
    return true;
}

/**
 * Determines if the browser supports the Document Object Model
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
dom.utils.browser.supportsDom = function() {
    return (document.getElementById) ? true : false;
}

/**
 * Determines if the browser is Internet Explorer
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
dom.utils.browser.isIE = function() {
    return (document.all && navigator.appName.indexOf('Microsoft Internet Explorer') > -1) ? true : false;
}

/**
 * Determines if the browser is Safari
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
dom.utils.browser.isSafari = function() {
    return (navigator.userAgent.toLowerCase().indexOf('safari') > -1) ? true : false;
}







/**
 * Fixes pseudo-leaks in Internet Explorer.
 *
 * Use this method anytime you need to remove an element
 * since it will do it in a memory clean manner for both
 * Internet Explorer and Firefox.
 *
 * @access public
 * @since  v1.4.8.1.2
 * @param  DomNode   elem
 * @return void
 */
dom.utils.removeElement = function(elem) {
    if (dom.utils.browser.isIE()) {
        var garbageBin = document.getElementById('IELeakGarbageBin');
        if (!garbageBin) {
            garbageBin = document.createElement('DIV');
            garbageBin.id = 'IELeakGarbageBin';
            garbageBin.style.display = 'none';
            document.body.appendChild(garbageBin);
        }
        // move the element to the garbage bin
        garbageBin.appendChild(elem);
        garbageBin.innerHTML = '';
    } else {
        elem.parentNode.removeChild(elem);
    }
}

/**
 * Use this function to get the complete width of the window content
 * useful for covering the entire page with a layer.
 *
 * @access public
 * @since  v1.2
 * @return integer
 */
dom.utils.getPageWidth = function() {
    var w = 0;
    if (window.innerWidth && window.scrollMaxX) { // Firefox
        w = window.innerWidth + window.scrollMaxX;
    } else if (document.body.scrollWidth > document.body.offsetWidth) { // All but Explorer Mac
        w = document.body.scrollWidth;
    } else { // Works in Explorer 6 strict, Mozilla (not FF), and Safari
        w = document.body.offsetWidth;
    }
    return w;
}

/**
 * Use this function to get the complete height of the window content
 * useful for covering the entire page with a layer.
 *
 * @access public
 * @since  v1.2
 * @return integer
 */
dom.utils.getPageHeight = function() {
    var h = 0;
    if (window.innerHeight && window.scrollMaxY) { // Firefox
        h = window.innerHeight + window.scrollMaxY;
    } else if (document.body.scrollHeight > document.body.offsetHeight) { // All but Explorer Mac
        h = document.body.scrollHeight;
    } else { // works in Exporer 6 strict, Mozilla (not FF) and Safari
        h = document.body.offsetHeight;
    }
    return h;
}


/**
 * Returns the window width in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Window    win    Window object (optional)
 * @return integer
 */
dom.utils.getWindowWidth   = function(win) {
    win = (win) ? win : window;
    if (win.document.compatMode == 'CSS1Compat') {
        return parseInt(win.document.body.parentNode.clientWidth);
    } else if (dom.utils.browser.isIE()) {
        return parseInt(win.document.body.clientWidth);
    } else {
        return parseInt(win.innerWidth);
    }
}


/**
 * Returns the window height in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Window    win    Window object (optional)
 * @return integer
 */
dom.utils.getWindowHeight  = function(win) {
    win = (win) ? win : window;
    if (win.document.compatMode == 'CSS1Compat') {
        return parseInt(win.document.body.parentNode.clientHeight);
    } else if (dom.utils.browser.isIE()) {
        return parseInt(win.document.body.clientHeight);
    } else {
        return parseInt(win.innerHeight);
    }
}


/**
 * Returns the window's scrolled position on the x-axis in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Window    win    Window object (optional)
 * @return integer
 */
dom.utils.getWindowScrollX = function(win) {
    win = (win) ? win : window;
    if (document.compatMode == 'CSS1Compat' && win.document.body.parentNode.scrollLeft) return parseInt(win.document.body.parentNode.scrollLeft);
    else if (dom.utils.browser.isIE())       return parseInt(win.document.body.scrollLeft);
    else                                     return parseInt(win.scrollX);
}


/**
 * Returns the window's scrolled position on the y-axis in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Window    win    Window object (optional)
 * @return integer
 */
dom.utils.getWindowScrollY = function(win) {
    win = (win) ? win : window;
    if (document.compatMode == 'CSS1Compat' && win.document.body.parentNode.scrollTop) return parseInt(win.document.body.parentNode.scrollTop);
    else if (dom.utils.browser.isIE())       return parseInt(win.document.body.scrollTop);
    else                                     return parseInt(win.scrollY);
}



/**
 * Returns the element width in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return integer
 */
dom.utils.getElementWidth  = function(elem) {
	var eStyle, prop, width;
    var w = 0;
    if (elem.tagName == 'IMG') {
        w = parseInt(elem.width);
    } else if (document.compatMode == 'CSS1Compat') {
        w = parseInt(elem.offsetWidth);
    } else if (document.compatMode == 'BackCompat') {
        eStyle = dom.utils.getCurrentStyle(elem);
        if (elem.offsetWidth) {
            w = parseInt(elem.offsetWidth);
        } else {
            w = parseInt(eStyle.width);
        }
        var bLeft  = parseInt(eStyle.borderLeft);
        var bRight = parseInt(eStyle.borderRight);
        var pLeft  = parseInt(eStyle.paddingLeft);
        var pRight = parseInt(eStyle.paddingRight);
        w += !isNaN(bLeft)  ? parseInt(bLeft)  : 0;
        w += !isNaN(bRight) ? parseInt(bRight) : 0;
        w += !isNaN(pLeft)  ? parseInt(pLeft)  : 0;
        w += !isNaN(pRight) ? parseInt(pRight) : 0;
    } else if (dom.utils.browser.isSafari()) {
        w = parseInt(elem.offsetWidth);
    }
    return w;
}


/**
 * Returns the element height in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return integer
 */
dom.utils.getElementHeight = function(elem) {
    var h = 0;
    var eStyle, height;
    if (elem.tagName && elem.tagName == 'IMG') {
        h = parseInt(elem.height);
    } else if (document.compatMode == 'CSS1Compat') {
        h = parseInt(elem.offsetHeight);
    } else if (document.compatMode == 'BackCompat') {
        eStyle  = dom.utils.getCurrentStyle(elem);
        if (elem.offsetHeight) {
            h = parseInt(elem.offsetHeight);
        } else {
            if (!eStyle) return false;
            h = parseInt(eStyle.height);
        }
        var bTop    = parseInt(eStyle.borderTop);
        var bBottom = parseInt(eStyle.borderBottom);
        var pTop    = parseInt(eStyle.paddingTop);
        var pBottom = parseInt(eStyle.paddingBottom);
        if (!dom.utils.browser.isIE()) {
            h += !isNaN(bTop)    ? parseInt(bTop)    : 0;
            h += !isNaN(bBottom) ? parseInt(bBottom) : 0;
            h += !isNaN(pTop)    ? parseInt(pTop)    : 0;
            h += !isNaN(pBottom) ? parseInt(pBottom) : 0;
        } else {
            h -= !isNaN(bTop) ? parseInt(bTop) : 0;
            h -= !isNaN(bBottom) ? parseInt(bBottom) : 0;
        }
    } else if (dom.utils.browser.isSafari()) {
        h = parseInt(elem.offsetHeight);
    }
    return h;
}

dom.utils.getDimensions = function(elem) {
    var dim    = {};
    dim.height = dom.utils.getElementHeight(elem);
    dim.width  = dom.utils.getElementWidth(elem);
    dim.left   = dom.utils.getElementLeft(elem);
    dim.top    = dom.utils.getElementTop(elem);
    return dim;
}

/**
 * Returns the element's left position in pixels (integer form)
 *
 * @todo   add error handling code -- find out what falls into catch code block
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return integer
 */
dom.utils.getElementLeft   = function(elem) {
    var left = 0;
    try {
        if (elem.offsetParent) {
            while (elem.offsetParent) {
                left += parseInt(elem.offsetLeft);
                elem  = elem.offsetParent;
            }
        } else if (elem.x) {
            left += parseInt(elem.x);
        }
        return left;
    } catch (e) {
        /**
	 * Add catch code for this function -- if anything does fall in here that is
         */
        return 0;
    }
}


/**
 * Returns the element's top position in pixels (integer form)
 *
 * @todo   add error handling code -- find out what falls into catch code block
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return integer
 */
dom.utils.getElementTop    = function(elem) {
    try {
        var top = 0;
        if (elem.offsetParent) {
            while (elem.offsetParent) {
                top += parseInt(elem.offsetTop);
                elem = elem.offsetParent;
            }
        } else if (elem.y) {
            top += parseInt(elem.y);
        }
        return top;
    } catch (e) {
        /**
	 * Add catch code for this function -- if anything does fall in here that is
         */
        return 0;
    }
}







/**
 * Centers an element inside its window.
 *
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return void
 */
dom.utils.center = function(elem) {
    var wWidth  = parseInt(dom.utils.getWindowWidth());
    var wHeight = parseInt(dom.utils.getWindowHeight());
    var eWidth  = parseInt(dom.utils.getElementWidth(elem));
    var eHeight = parseInt(dom.utils.getElementHeight(elem));
    var xScroll = parseInt(dom.utils.getWindowScrollX());
    var yScroll = parseInt(dom.utils.getWindowScrollY());
    //console.log('wHeight: '+wHeight+', eHeight: '+eHeight+', yScroll: '+yScroll);
    //console.log('wHeight: '+wHeight+', eHeight: '+eHeight+', yScroll: '+yScroll);
    
    var left = parseInt(wWidth / 2) - parseInt(eWidth / 2) + xScroll;
    var top  = parseInt(wHeight / 2) - parseInt(eHeight / 2) + yScroll;
    //console.log('setting center (x,y): '+left+', '+top);
    elem.style.left = left+'px';
    elem.style.top  = top+'px';
}







/**
 * Returns the element's current style object
 *
 * @access public
 * @since  v1.1
 * @param  Element   elem   Element object
 * @return Style
 */
dom.utils.getCurrentStyle  = function(elem) {
    if (elem && elem.currentStyle) {
        return elem.currentStyle;
    } else if (document.defaultView && document.defaultView.getComputedStyle) {
        return document.defaultView.getComputedStyle(elem, '');
    }
}

/**
 * Copies the current style applied on element 1 to element 2.
 * 
 * @access public
 * @since  v1.8
 * @param  Element    elem1
 * @param  Element    elem2
 * @return void
 */
dom.utils.duplicateStyle = function(elem1, elem2) {
    var style1 = dom.utils.getCurrentStyle(elem1);
    //var str = 'style1: '+style1+"<br/>\n";
    for (prop in style1) {
        try {
            //elem2.style[prop] = style1[prop];
            eval('elem2.style.'+prop+' = style1.'+prop);
            //var span = document.createElement('span');
            //span.innerHTML = 'set style1.'+prop+': '+style1[prop]+"<br/>\n";
            //document.getElementsByTagName('body')[0].appendChild(span);
        } catch(e) {
            //var span = document.createElement('span');
            //span.innerHTML = 'failed setting style1.'+prop+': '+style1[prop]+"<br/>\n";
            //document.getElementsByTagName('body')[0].appendChild(span);
        }
    }
};


/**
 * Returns the element's zIndex attribute (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Element   elem   Element object
 * @return integer
 */
dom.utils.getZIndex = function(elem, recurse) {
    recurse = recurse || false;
    var eStyle = dom.utils.getCurrentStyle(elem);
    var zIdx   = 0;
    if ((eStyle.zIndex && isNaN(eStyle.zIndex)) || recurse) {
        if (elem.offsetParent) {
            while (elem.offsetParent) {
                zIdx   = (parseInt(elem.style.zIndex) > zIdx) ? parseInt(elem.style.zIndex) : zIdx;
                eStyle = dom.utils.getCurrentStyle(elem);
                elem   = elem.offsetParent;
            }
        }
    } else {
        zIdx = parseInt(eStyle.zIndex);
    }
    return zIdx;
}








/**
 * Returns a reference to the document's body tag
 *
 * @access public
 * @since  v1.1
 * @return Element
 */
dom.utils.getBody = function() {
    return document.getElementsByTagName('body')[0];
}



/************** END dom.utils.js ***************/




