
/* --- classes/DefinitionPopup.js --- */
/**
 * $Id: DefinitionPopup.js 38066 2007-05-04 16:38:33Z sagi $
 * $Author: sagi $
 * $Revision: 38066 $
 * $Name$
 * $Date: 2007-05-04 09:38:33 -0700 (Fri, 04 May 2007) $
 *
 * @jsRequire DomUtils
 * @jsRequire classes.InterfaceObject
 * @jsRequire classes.EventManager
 * @jsRequire interfaces.DropShadowInterface
 * @jsRequire interfaces.CalloutInterface
 * @jsRequire interfaces.DelayedPopupInterface
 * @jsRequire interfaces.AnchoredInterface
 * @jsRequire interfaces.RoundedCornersInterface
 *
 *
 *
 *
 * @version    $Revision: 38066 $
 * @author     Philip Snyder <philip@pricegrabber.com>
 * @copyright  Copyright &copy; 2006 2007, Philip Snyder
 * @see        classes.InterfaceObject
 * @see        interfaces.DropShadowInterface
 * @see        interfaces.CalloutInterface
 * @see        interfaces.DelayedPopupInterface
 * @see        interfaces.AnchoredInterface
 * @see        interfaces.RoundedCornersInterface
 */

/**
 * DefinitionPopup Constructor / Definition
 *
 * This is NOT intended to be instantiated directly. Instead, use the
 * singleton accessor methods DefinitionPopup.getInstance(),
 * DefinitionPopup.show(), DefinitionPopup.hide() and DefinitionPopup.toggle().
 *
 * @access public
 * @since  v1.1
 * @param  DOMElement       anchor
 * @return DefinitionPopup
 */
function DefinitionPopup(anchor) {
    this.elemId            = null;
    // Callout interface implementation
    this.calloutId         = null;
    this.calloutPadding    = 0;
    // Drop shadow interface implementation
    /*this.dropShadowId      = null;
    this.color             = null;
    this.xOffset           = null;
    this.yOffset           = null;
    this.blur              = { iRadius: null, iSigma: null };
    this.opacity           = null;
    this.xShrink           = null;
    this.yShrink           = null;
    this.shadowStyle       = null;
    this.images            = new Array;
    this.setBlur           = DropShadowInterface_SetBlur;*/
    // Delayed popup interface implementation
    this.timer             = null;
    this.visible           = false;
    this.delay             = null;
    this.linked            = new Array;
    this.cancelTimer       = DelayedPopupInterface_CancelTimer;
    this.hide              = DelayedPopupInterface_Hide;
    this.toggle            = PopupInterface_Toggle;
    // Anchored interface implementation
    this.anchorId          = anchor || null;
    this.disableScroll     = true;
    this.getAnchorX        = AnchoredInterface_GetAnchorX;
    this.getAnchorY        = AnchoredInterface_GetAnchorY;
    this.getAnchorZ        = AnchoredInterface_GetAnchorZ;
    this.getAnchorWidth    = AnchoredInterface_GetAnchorWidth;
    this.getAnchorHeight   = AnchoredInterface_GetAnchorHeight;
    this.getAnchorPosition = AnchoredInterface_GetAnchorPosition;
    this.getElemWidth      = AnchoredInterface_GetElemWidth;
    this.getElemHeight     = AnchoredInterface_GetElemHeight;
    this.setAnchor         = AnchoredInterface_SetAnchor;
    // Rounded corners interface implementation
    this.cornerStyle       = null;
    this.cornersDrawn      = false;
    // Drop shadow interface && Callout interface joint implementation
    this.erase             = DefinitionPopup_Erase;
    this.draw              = DefinitionPopup_Draw;
    this.init              = DefinitionPopup_Init;
    // Drop shadow interface && Delayed popup interface joint implementation
    this.show              = DefinitionPopup_Show;
    // Drop shadow interface && Anchored interface joint implementation
    this.alignElement      = DefinitionPopup_AlignElement;

    //this.implement(DropShadowInterface);
    this.implement(CalloutInterface);
    this.implement(DelayedPopupInterface);
    this.implement(AnchoredInterface);
    this.implement(RoundedCornersInterface);
    
    this.setElement        = DefinitionPopup_SetElement;
    this.setDefinition     = DefinitionPopup_SetDefinition;
    this.setTerm           = DefinitionPopup_SetTerm;
    this.setTermColor      = DefinitionPopup_SetTermColor;

    this.id                = 'DefinitionPopup';
    this.style             = 'Default';
    this.delay             = 500;
    this.elemId            = this.id;
    this.defId             = this.elemId+'_def';
    this.termId            = this.elemId+'_term';
   
    this.init();
} // End DefinitionPopup

// Setup DefinitionPopup prototype chain
DefinitionPopup.prototype             = new InterfaceObject;
DefinitionPopup.prototype.constructor = DefinitionPopup;
DefinitionPopup.superclass            = InterfaceObject.prototype;









/****** BEGIN EDIT SECTION ******/

/**
 * Style definitions for DefinitionPopup widget.
 *
 * These style settings can be overridden by a simple variable set call.
 * Note that if you set the backgroundColor to anything other than #ffffff
 * you will most likely want to create some rounded corner images and define
 * them too.
 * 
 * Example:
 *   <?php
 *   if (!$pricegrabber_site)
 *       echo "    DefinitionPopup.styles.Default.term.color = '".$color."';\n";
 *   ?>
 */
DefinitionPopup.styles = {
    Default: {
        term: {
            font: {
                family:  'Arial, Helvetica, sans-serif',
                size:    '13px',
                weight:  'bold'
            },
            //color:       '#589c1c'
            color:       '#0099FF'
        },
        font: {
            family:      'Arial, Helvetica, sans-serif',
            size:        '13px',
            weight:      'normal'
        },
        backgroundColor: '#ffffff',
        color:           '#656565'
    }
} // End DefinitionPopup.styles

/****** END EDIT SECTION ******/


















/**
 * Sets the DOMElement that the DefinitionPopup works with.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetElement(elem) {
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_SetContent() called.');
    this.elemId = elem.id;
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_SetContent() finished.');
}

/**
 * Initializes the DefinitionPopup in preparation for drawing.
 *
 * Call this method before any draw methods as it handles initialization of
 * any implemented interfaces as well.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_Init() {
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_Init() called.');
    var elem = document.getElementById(this.elemId);
    if (!elem) {
        elem = document.createElement('div');
        document.getElementsByTagName('body')[0].appendChild(elem);
        elem.id = this.elemId;
    }

    var term = document.getElementById(this.termId);
    if (!term) {
        term = document.createElement('div');
        elem.appendChild(term);
        term.id = this.termId;
    }

    var def = document.getElementById(this.defId);
    if (!def) {
        def = document.createElement('div');
        elem.appendChild(def);
        def.id = this.defId;
    }

    elem.style.backgroundColor = DefinitionPopup.styles[this.style].backgroundColor;
    term.style.color           = DefinitionPopup.styles[this.style].term.color;
    term.style.paddingBottom   = '5px';
    term.style.fontFamily      = DefinitionPopup.styles[this.style].term.font.family;
    term.style.fontSize        = DefinitionPopup.styles[this.style].term.font.size;
    term.style.fontWeight      = DefinitionPopup.styles[this.style].term.font.weight;
    def.style.color            = DefinitionPopup.styles[this.style].color;
    def.style.fontFamily       = DefinitionPopup.styles[this.style].font.family;
    def.style.fontSize         = DefinitionPopup.styles[this.style].font.size;
    def.style.fontWeight       = DefinitionPopup.styles[this.style].font.weight;
    
    this.calloutPadding = 20;
    this.cornerStyle = 'Default';
    RoundedCornersInterface_Init.call(this);
    this.shadowStyle = 'Default';
    //DropShadowInterface_Init.call(this);
    //if (typeof(writeDebug) == 'function') writeDebug('DefinitionPopup_Init() finished.');
} // End DefinitionPopup_Init

/**
 * Erases the definition popup by removing the dom elements created in DefinitionPopup_Draw.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_Erase() {
    CalloutInterface_Erase.call(this);
    //DropShadowInterface_Erase.call(this);
    RoundedCornersInterface_Erase.call(this);
    this.linked = new Array;
} // End DefinitionPopup_Erase

/**
 * Draws the definition popup by creating the necessary dom elements and attaching them to the document accordingly.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_Draw() {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_Draw() called.', '#ffffff', '#0000ff');
    var elem = document.getElementById(this.elemId);
    if (!elem) throw new Error('Unable to find element: '+this.elemId);

    var term = document.getElementById(this.termId);
    if (!term) throw new Error('Unable to find element: '+this.termId);

    var def = document.getElementById(this.defId);
    if (!def) throw new Error('Unable to find element: '+this.defId);

    this.linked = new Array;
    bHeight = 2;
    elem.style.border = '1px solid '+DefinitionPopup.styles[this.style].backgroundColor;
    elem.style.backgroundColor = DefinitionPopup.styles[this.style].backgroundColor;
    elem.style.color = DefinitionPopup.styles[this.style].color;
    RoundedCornersInterface_Draw.call(this);
    CalloutInterface_Draw.call(this);
    //DropShadowInterface_Draw.call(this);
    window.addEvent(elem, 'mouseover', this.cancelTimer, this, true);
    window.addEvent(elem, 'mouseout',  this.hide,        this, true);
    elem.style.border = 'none';
    elem.style.backgroundColor = 'transparent';

    //this.linked.push(this.dropShadowId);
    this.linked.push(this.calloutId);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_Draw() finished.', '#ffffff', '#0000ff');
} // End DefinitionPopup_Draw

/**
 * Shows the definition popup on the screen.
 *
 * @access public
 * @since  v1.1
 * @return boolean
 */
function DefinitionPopup_Show() {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_Show() called.', '#ffffff', '#0000ff');
    this.cancelTimer();
    var wasVisible = this.visible;
    if (this.visible) {
        PopupInterface_Hide.call(this);
        this.erase();
    }
    this.draw();

    var anchor     = document.getElementById(this.anchorId);
    if (!anchor)     throw new Error('Unable to find anchor element: '+this.anchorId);

    var elem       = document.getElementById(this.elemId);
    if (!elem)       throw new Error('Unable to find element: '+this.elemId);

    //var dropShadow = document.getElementById(this.dropShadowId);
    //if (!elem)       throw new Error('Unable to find drop shadow element: '+this.dropShadowId);

    var callout    = document.getElementById(this.calloutId);
    if (!callout)    throw new Error('Unable to find callout element: '+this.calloutId);


    // Get the z-index of our anchor element
    var zIndex = parseInt(DomUtils.getZIndex(anchor));
    // If it doesn't have one make it 1000
    if (zIndex == 0) {
        zIndex = 1000;
        anchor.style.zIndex = zIndex;
    }
    //dropShadow.style.zIndex = zIndex+1;
    callout.style.zIndex    = zIndex+2;
    elem.style.zIndex       = zIndex+3;
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'anchor zIndex: '+zIndex) );
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'drop shadow zIndex: '+dropShadow.style.zIndex) );
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'callout zIndex: '+callout.style.zIndex) );
    //window.messageQueue.add( new Message('ItineraryPopup_Show', 'elem zIndex: '+elem.style.zIndex) );
    //this.alignElement(this.getAnchorPosition());
    this.alignElement();
    if (wasVisible) PopupInterface_Show.call(this);
    else            DelayedPopupInterface_Show.call(this);
    return true;
} // End DefinitionPopup_Show

/**
 * Aligns the definition popup by calling implemented interfaces' AlignElement functions.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_AlignElement() {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_AlignElement() called.', '#ffffff', '#0000ff');
    AnchoredInterface_AlignElement.call(this)
    CalloutInterface_AlignElement.call(this);
    //DropShadowInterface_AlignElement.call(this);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_AlignElement() finished.', '#ffffff', '#0000ff');
} // End DefinitionPopup_AlignElement

/**
 * Sets the definition in the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetDefinition(definition) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_SetDefinition() called.', '#ff0000', '#ffffff');
    var defElem = document.getElementById(this.defId);
    if (!defElem) throw new Error('Unable to find definition element: '+this.defId);
    while (defElem.hasChildNodes()) DomUtils.removeElement(defElem.firstChild);
    var txtDef = document.createTextNode(definition);
    defElem.appendChild(txtDef);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_SetDefinition() finished.', '#ff0000', '#ffffff');
}

/**
 * Sets the term in the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetTerm(term) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_SetTerm() called.', '#ff0000', '#ffffff');
    var termElem = document.getElementById(this.termId);
    if (!termElem) throw new Error('Unable to find term element: '+this.termId);
    while (termElem.hasChildNodes()) DomUtils.removeElement(termElem.firstChild);
    var txtTerm = document.createTextNode(term);
    termElem.appendChild(txtTerm);
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_SetTerm() finished.', '#ff0000', '#ffffff');
}

/**
 * Sets the term color of the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
function DefinitionPopup_SetTermColor(color) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup_SetTermColor() called.', '#ff0000', '#ffffff');
    var term = document.getElementById(this.termId);
    if (!term) throw new Error('Unable to find term element: '+this.termId);
    term.style.color = color;
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup_SetTermColor() finished.', '#ff0000', '#ffffff');
}








/****** SINGLETON ACCESSORS SECTION ******/

/**
 * Singleton instance variable.
 *
 * @access public
 * @since  v1.1
 * @var    instance   DefinitionPopup
 */
DefinitionPopup.instance = null;

/**
 * Singleton accessor for retrieving the definition popup instance.
 *
 * @access public
 * @since  v1.1
 * @return DefinitionPopup
 */
DefinitionPopup.getInstance = function() {
    if (!DefinitionPopup.instance) DefinitionPopup.instance = new DefinitionPopup();
    return DefinitionPopup.instance;
} // End DefinitionPopup.getInstance

/**
 * Singleton accessor for initializing the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
//DefinitionPopup.initInstance = function() {
//    if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup.init() called.', '#ff0000', '#ffff00');
//    DefinitionPopup.instance = new DefinitionPopup();
//    if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup.init() finished.', '#ff0000', '#ffff00');
//} // End DefinitionPopup.init

/**
 * Singleton accessor for showing the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
DefinitionPopup.show = function(anchor, term, def) {
    //if (typeof(writeDebug) == 'function') writeDebug('>> DefinitionPopup.show() called.', '#ff0000', '#ffff00');
    DefinitionPopup.getInstance().setAnchor(anchor);
    DefinitionPopup.getInstance().setDefinition(def);
    DefinitionPopup.getInstance().setTerm(term);
    DefinitionPopup_Show.call(DefinitionPopup.getInstance());
    //if (typeof(writeDebug) == 'function') writeDebug('<< DefinitionPopup.show() finished.', '#ff0000', '#ffff00');
} // End DefinitionPopup.show

/**
 * Singleton accessor for hiding the definition popup.
 *
 * @access public
 * @since  v1.1
 * @return void
 */
DefinitionPopup.hide = function() {
    DelayedPopupInterface_Hide.call(DefinitionPopup.getInstance());
} // End DefinitionPopup.hide

/**
 * Singleton accessor for toggling the definition popup.
 *
 * @access public
 * @since  v1.1
 * @param  DOMElement  anchor
 * @param  string      def
 * @return void
 */
DefinitionPopup.toggle = function(anchor, term, def) {
    if (DefinitionPopup.getInstance().visible) DefinitionPopup.hide();
    else                                       DefinitionPopup.show(anchor, term, def);
}


/* --- tech_specs.js --- */
//var COLLAPSE = ' Collapse All Sections';
//var EXPAND   = ' Expand All Sections';


/**
 *
 *
 *
 *
 */
function toggleAllSections(elem) {
    var text, display, imgSrc;
    var txtElem = elem.firstChild.nextSibling;
    var imgElem = elem.firstChild;
    switch (txtElem.firstChild.nodeValue.toLowerCase()) {
        case COLLAPSE.toLowerCase():
            display = 'none';
            text    = EXPAND;
            imgSrc  = plus.src;
            break;
        case EXPAND.toLowerCase():
        default:
            display = '';
            text    = COLLAPSE;
            imgSrc  = minus.src;
            break;
    }
    imgElem.src = imgSrc;
    txtElem.removeChild(txtElem.firstChild);
    var txtNode = document.createTextNode(text);
    txtElem.appendChild(txtNode);
    var tbodys = document.getElementsByTagName('tbody');
    var splitPoint, img, length;
    for (var i=0; i<tbodys.length; i++) {
        if ((/^section/).test(tbodys[i].id)) {
            tbodys[i].style.display = display;
            splitPoint = tbodys[i].id.indexOf('_') + 1;
            length = tbodys[i].id.length - splitPoint;
            sectionId = tbodys[i].id.substr(splitPoint, length);
            img = document.getElementById('toggle_'+sectionId);
            if (img) img.src = imgSrc;
        }
    }
}


/**
 *
 *
 *
 *
 */
function toggle(section) {
    var elem = document.getElementById('section_'+section);
    if (elem) {
        elem.style.display = (elem.style.display != '') ? '' : 'none';
    }
    var img  = document.getElementById('toggle_'+section);
    if (img && img.src == plus.src) {
        img.src = minus.src;
    } else if (img) {
        img.src = plus.src;
    }
}
var minus = new Image(9,9);
var plus  = new Image(9,9);
minus.src = 'http://ai.pricegrabber.com/images/compare/minus_9x9.gif';
plus.src  = 'http://ai.pricegrabber.com/images/compare/plus_9x9.gif';

/* --- DomUtils.js --- */
/**
 * $Id: DomUtils.js 45931 2007-11-27 00:37:43Z kchiu $
 * $Author: kchiu $
 * $Revision: 45931 $
 * $Name$
 * $Date: 2007-11-26 16:37:43 -0800 (Mon, 26 Nov 2007) $
 *
 * @jsRequire DomUtils
 * @jsRequire interfaces.Interface
 *
 *
 * @version    $Revision: 45931 $
 * @author     Philip Snyder <philip@pricegrabber.com>
 * @copyright  Copyright &copy; 2006, Philip Snyder, PriceGrabber.com
 * @see        interfaces.Interface
 */

/**
 * DomUtils function namespace
 *
 *
 * @access public
 * @since  v1.1
 */
var DomUtils = new Object;


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

/**
 * RegEx definitions for browser detections based on property tested
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
DomUtils.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
 */
DomUtils.browser.supportsOverflowX = function() {
    for (var i=0; i<DomUtils.browser.regexes.overflowX.length; i++) {
        var regex = DomUtils.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
 */
DomUtils.browser.supportsOverflowY = function() {
    for (var i=0; i<DomUtils.browser.regexes.overflowY.length; i++) {
        var regex = DomUtils.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
 */
DomUtils.browser.supportsDom = function() {
    return (document.getElementById) ? true : false;
}

/**
 * Determines if the browser is Internet Explorer
 *
 * @access public
 * @since  v1.4.8.1.2.4
 */
DomUtils.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
 */
DomUtils.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
 */
DomUtils.removeElement = function(elem) {
    if (DomUtils.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);
    }
}




/**
 * Returns the window width in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Window    win    Window object (optional)
 * @return integer
 */
DomUtils.getWindowWidth   = function(win) {
    win = (win) ? win : window;
    if (document.compatMode == 'CSS1Compat') return parseInt(win.document.body.parentNode.clientWidth);
    else if (DomUtils.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
 */
DomUtils.getWindowHeight  = function(win) {
    win = (win) ? win : window;
    if (document.compatMode == 'CSS1Compat') return parseInt(win.document.body.parentNode.clientHeight);
    else if (DomUtils.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
 */
DomUtils.getWindowScrollX = function(win) {
    win = (win) ? win : window;
    if (document.compatMode == 'CSS1Compat') return parseInt(win.document.body.parentNode.scrollLeft);
    else if (DomUtils.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
 */
DomUtils.getWindowScrollY = function(win) {
    win = (win) ? win : window;
    if (document.compatMode == 'CSS1Compat') return parseInt(win.document.body.parentNode.scrollTop);
    else if (DomUtils.browser.isIE())        return parseInt(win.document.body.scrollTop);
    else                                     return parseInt(win.scrollY);
}


///**
// * Returns the element's width after css clipping
// *
// * @access public
// * @since  v1.1
// * @deprecated       Unnecessary -- I think. Keep the code just in case
// * @param  Element   elem  Element to get the clip width
// * @return integer
// */
//DomUtils.getElementClipWidth = function(elem) {
//    var currStyle = DomUtils.getCurrentStyle(elem);
//    var pre = document.createElement('pre');
//    var str = "current style props:\n";
//    for (var prop in currStyle) {
//        str += prop+": "+currStyle[prop]+"\n";
//    }
//    pre.appendChild(document.createTextNode(str));
//    document.body.appendChild(pre);
//}


/**
 * Returns the element width in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return integer
 */
DomUtils.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 = DomUtils.getCurrentStyle(elem);
        width  = parseInt(eStyle.width);
        if (DomUtils.browser.isIE()) width = elem.offsetWidth;
        var bLeft  = parseInt(eStyle.borderLeft);
        var bRight = parseInt(eStyle.borderRight);
        var pLeft  = parseInt(eStyle.paddingLeft);
        var pRight = parseInt(eStyle.paddingRight);
        w  = parseInt(width);
        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 (DomUtils.browser.isSafari()) {
        if (typeof(writeDebug) == 'function') writeDebug('browser is safari...');
        width = elem.offsetWidth;
        w = parseInt(width);
    }
    return w;
}


/**
 * Returns the element height in pixels (integer form)
 *
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return integer
 */
DomUtils.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  = DomUtils.getCurrentStyle(elem);
        height  = parseInt(eStyle.height);
        if (DomUtils.browser.isIE()) height = elem.offsetHeight;
        var bTop    = parseInt(eStyle.borderTop);
        var bBottom = parseInt(eStyle.borderBottom);
        var pTop    = parseInt(eStyle.paddingTop);
        var pBottom = parseInt(eStyle.paddingBottom);
        h  = parseInt(height);
        if (!DomUtils.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 (DomUtils.browser.isSafari()) {
        height = elem.offsetHeight;
        h = parseInt(height);
    }
    return h;
}


/**
 * 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
 */
DomUtils.getElementLeft   = function DomUtils_GetElementLeft(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) {
        /**
         */
        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
 */
DomUtils.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) {
        return 0;
    }
}







/**
 * Centers an element inside its window.
 *
 * @access public
 * @since  v1.1
 * @param  Element    elem    Element object
 * @return void
 */
DomUtils.center = function(elem) {
    var wWidth  = parseInt(DomUtils.getWindowWidth());
    var wHeight = parseInt(DomUtils.getWindowHeight());
    var eWidth  = parseInt(DomUtils.getElementWidth(elem));
    var eHeight = parseInt(DomUtils.getElementHeight(elem));
    var xScroll = parseInt(DomUtils.getWindowScrollX());
    var yScroll = parseInt(DomUtils.getWindowScrollY());
    
    var left = parseInt(wWidth / 2) - parseInt(eWidth / 2) + xScroll;
    var top  = parseInt(wHeight / 2) - parseInt(eHeight / 2) + yScroll;
    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
 */
DomUtils.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
 */
DomUtils.duplicateStyle = function(elem1, elem2) {
    var style1 = DomUtils.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
 */
DomUtils.getZIndex = function(elem) {
    var eStyle = DomUtils.getCurrentStyle(elem);
    var zIdx   = 0;
    if (eStyle.zIndex && isNaN(eStyle.zIndex)) {
        if (elem.offsetParent) {
            while (elem.offsetParent) {
                zIdx   = (parseInt(eStyle.zIndex) > zIdx) ? parseInt(eStyle.zIndex) : zIdx;
                eStyle = DomUtils.getCurrentStyle(elem);
                elem   = elem.offsetParent;
            }
        }
    } else {
        zIdx = parseInt(eStyle.zIndex);
    }
    return zIdx;
}




///**
// * alerts an image's ready state if not complete
// *
// * @access public
// * @deprecated       I highly doubt this is used anywhere?
// * @since  v1.1
// * @param  Window    win    Window object (optional)
// * @return integer
// */
//DomUtils.checkImage = function() {
//    if (this.readyState != 'complete') {
//        alert(this.src+"\n"+this.readyState);
//    }
//}




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





/**
 * Returns the window height in pixels (integer form)
 *
 * This should probably be deprecated / removed in favor
 * of net.RequestQueue
 *
 * @access public
 * @deprecated       Use net.RequestQueue instead
 * @since  v1.1
 * @return integer
 */
DomUtils.XmlHttp = function() {
    var request = null;
    try {
        ActiveXObject.prototype.jsonRequest = null;
        request = new ActiveXObject('Msxml2.XMLHTTP');
    } catch (e) {
        try {
            ActiveXObject.prototype.jsonRequest = null;
            request = new ActiveXObject('Microsoft.XMLHTTP');
        } catch (e) {
            try {
                XMLHttpRequest.prototype.jsonRequest = null;
                request = new XMLHttpRequest();
            } catch (e) {
                //request = new IframeHttpRequest();
                request = null;
            }
        }
    }
    return request;
}




















/**
 * Adds method function to Function objects
 *
 * @access public
 * @since  v1.1
 * @param  string    name   Name of the method to create
 * @param  Function  func   Function reference to assign to the method
 * @return Function
 */
Function.prototype.method = function(name, func) {
    this.prototype[name] = func;
    return this;
}

/**
 * Returns true if param is not a javascript object
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isAlien(a) {
   return isObject(a) && typeof a.constructor != 'function';
}

/**
 * Returns true if the param is an array
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isArray(a) {
    return isObject(a) && a.constructor == Array;
}

/**
 * Returns true if the param is a boolean data type
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean 
 */
function isBoolean(a) {
    return typeof a == 'boolean';
}

/**
 * Returns true if the param is empty (contains no value)
 *
 * @access public
 * @since  v1.1
 * @param  mixed     o      test this param
 * @return boolean
 */
function isEmpty(o) {
    var i, v;
    if (isObject(o)) {
        for (i in o) {
            v = o[i];
            if (isUndefined(v) && isFunction(v)) {
                return false;
            }
        }
    }
    return true;
}

/**
 * Returns true if the param is a float
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isFloat(a) {
    return typeof a == 'number' && parseFloat(a) == a;
}

/**
 * Returns true if the param is a function
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isFunction(a) {
    return typeof a == 'function';
}

/**
 * Returns true if the param is an integer
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isInteger(a) {
    return typeof a == 'number' && parseInt(a) == a;
}

/**
 * Returns true if the param is null
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isNull(a) {
    return typeof a == 'object' && !a;
}

/**
 * Returns true if the param is a number
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isNumber(a) {
    return typeof a == 'number' && isFinite(a);
}

/**
 * Returns true if the param is an object
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isObject(a) {
    return (a && typeof a == 'object') || isFunction(a);
}

/**
 * Returns true if the param is a string
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isString(a) {
    return typeof a == 'string';
}

/**
 * Returns true if the param is undefined
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function isUndefined(a) {
    return typeof a == 'undefined';
}

/**
 * Fix PNG images for IE
 *
 * @access public
 * @since  v1.1
 * @param  mixed     a      test this param
 * @return boolean
 */
function fixPNG_IE (image) {
	//Only fix PNGs for IE
	if(DomUtils.browser.isIE()) { 
		image.outerHTML = '<div style="width:' + image.width + '; height:' + image.height + '; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + image.src + '\', sizingMethod=\'scale\');"></div>';
	}
}



































/** BEGIN getElementsBySelector CODE ******************************************/

/* document.getElementsBySelector(selector)
   - returns an array of element objects from the current document
     matching the CSS selector. Selectors can contain element names, 
     class names and ids and can be nested. For example:
     
       elements = document.getElementsBySelect('div#main p a.external')
     
     Will return an array of all 'a' elements with 'external' in their 
     class attribute that are contained inside 'p' elements that are 
     contained inside the 'div' element which has id="main"

   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
   See http://www.w3.org/TR/css3-selectors/#attribute-selectors

   Version 0.4 - Simon Willison, March 25th 2003
   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
   -- Opera 7 fails 
*/

function getAllChildren(e) {
  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
  return e.all ? e.all : e.getElementsByTagName('*');
}

document.getElementsBySelector = function(selector) {
  // Attempt to fail gracefully in lesser browsers
  if (!document.getElementsByTagName) {
    return new Array();
  }
  // Split selector in to tokens
  var tokens = selector.split(' ');
  var currentContext = new Array(document);
  for (var i = 0; i < tokens.length; i++) {
    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
    if (token.indexOf('#') > -1) {
      // Token is an ID selector
      var bits = token.split('#');
      var tagName = bits[0];
      var id = bits[1];
      var element = document.getElementById(id);
      if (tagName && element.nodeName.toLowerCase() != tagName) {
        // tag with that ID not found, return false
        return new Array();
      }
      // Set currentContext to contain just this element
      currentContext = new Array(element);
      continue; // Skip to next token
    }
    if (token.indexOf('.') > -1) {
      // Token contains a class selector
      var bits = token.split('.');
      var tagName = bits[0];
      var className = bits[1];
      if (!tagName) {
        tagName = '*';
      }
      // Get elements matching tag, filter them for class selector
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // Code to deal with attribute selectors
    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
      var tagName = RegExp.$1;
      var attrName = RegExp.$2;
      var attrOperator = RegExp.$3;
      var attrValue = RegExp.$4;
      if (!tagName) {
        tagName = '*';
      }
      // Grab all of the tagName elements within current context
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      var checkFunction; // This function will be used to filter the elements
      switch (attrOperator) {
        case '=': // Equality
          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
          break;
        case '~': // Match one of space seperated words 
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
          break;
        case '|': // Match start with value followed by optional hyphen
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
          break;
        case '^': // Match starts with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
          break;
        case '$': // Match ends with value - fails with "Warning" in Opera 7
          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
          break;
        case '*': // Match ends with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
          break;
        default :
          // Just test for existence of attribute
          checkFunction = function(e) { return e.getAttribute(attrName); };
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (checkFunction(found[k])) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
      continue; // Skip to next token
    }
    // If we get here, token is JUST an element (not a class or ID selector)
    tagName = token;
    var found = new Array;
    var foundCount = 0;
    for (var h = 0; h < currentContext.length; h++) {
      var elements = currentContext[h].getElementsByTagName(tagName);
      for (var j = 0; j < elements.length; j++) {
        found[foundCount++] = elements[j];
      }
    }
    currentContext = found;
  }
  return currentContext;
}

/* That revolting regular expression explained 
/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
  \---/  \---/\-------------/    \-------/
    |      |         |               |
    |      |         |           The value
    |      |    ~,|,^,$,* or =
    |   Attribute 
   Tag
*/
/** END getElementsBySelector CODE ********************************************/

// Alias old DomUtils.getElementsBySelector to this same function
// in order to maintain compatibility if anyone was using the old one
DomUtils.getElementsBySelector = document.getElementsBySelector;




/* --- classes/EventManager.js --- */
/**
 *
 *
 *
 * @package     PriceGrabber
 * @subpackage  Utils
 * @category    JavaScript
 *
 * @author      Philip Snyder <philip@pricegrabber.com>
 * @copyright   Copyright &copy; 2005 2006 2007, Philip Snyder, PriceGrabber.com
 * @version     v0.0.1a
 *
 */

/**
 * Class is an event manager that handles attaching events and
 * maintaining function/variable scope in a cross-browser manner.
 *
 * Note: Do not define your handler as an anonymous function as this
 * will cause rampant memory leaks in Internet Explorer.
 *
 * Basic example:
 *
 *    <script language="JavaScript" src="js/classes/EventManager.js" type="text/javascript"></script>
 *    <script language="JavaScript">
 *    function Document_KeyDown_Handler(e) {
 *        e = (e) ? e : ((window.event) ? window.event : null);
 *        if (e) alert(e.keyCode);
 *    }
 *    window.addEvent(document, 'keydown', Document_KeyDown_Handler, document, true);
 *    </script>
 *
 * @since     v0.0.1a
 * @return    EventManager
 */


function EventManager() {

    window.onload = null;
    window.onunload = null;
//    this.addEvent    = EventManager_AddEvent;
//    this.removeEvent = EventManager_RemoveEvent;
//    this.addOnLoad   = EventManager_AddOnLoad;
//    this.addOnUnload = EventManager_AddOnUnload;
//    this.addOnResize = EventManager_AddOnResize;
    
    
    
    this.alterEventObject = function(e) { };
    
    
	var registry      = {};
	var targetIdCount = 0;

	function registryKey(id, type, fn) {
		return id+'#'+type+'#'+fn;
	}

	function isInRegistry(key) {
		return registry[key] != null;
	}

	function invoke(key, evt) {
		if (!isInRegistry(key)) return null;
		if (window.eventManager) {
    		var _evt = window.eventManager.alterEventObject(evt);
    		if (typeof(_evt) == 'object') evt = _evt;
    		var handler = registry[key];
    		var scope   = handler.scope;
    		scope.__EventManager_Listener__ = handler.listener;
    		scope.__EventManager_Listener__(evt);
    		scope.__EventManager_Listener__ = null;
    		return true;
		} else {
		    return false;
		}
	}

	function targetId(target) {
		if (target == document)      return "__EventManager_ID_document";
		if (target == window)        return "__EventManager_ID_window";
		if (target+'' == xmlhttp+'') return "__EventManager_ID_xmlhttp";
		try {
    		var id = target.getAttribute('id') || target.uniqueID;
    		if (id == null) {
    			id = "__EventManager_ID_"+(targetIdCount++);
    			target.setAttribute('id', id);
    		}
		} catch (e) {
//		    throw new Error('target: "'+target+'" vs xmlhttp: "'+xmlhttp+'"');
		}
		return id;
	}

	this.isEventRegistered = function(target, type, listener) {
    		var key = registryKey(targetId(target), type, listener);
		return isInRegistry(key);
	}


    this.addEvent = function(target, type, listener, scope, capture) {
    	var key, handler;
    	key   = registryKey(targetId(target), type, listener);
    	scope = scope || target;
    	if (isInRegistry(key)) window.removeEvent(target, type, listener);
    	handler = { listener: listener, scope: scope, capture: capture, invoker: function(evt) { invoke(key, evt); } };
    	registry[key] = handler;
    	if (target.addEventListener) target.addEventListener(type, handler.invoker, capture);
    	else if (target.attachEvent) target.attachEvent('on'+type, handler.invoker);
    	else                         return false;
    	if (typeof(window.addOnUnload) == 'function') window.addOnUnload( function() { /*alert('calling window.removeEvent.');*/ window.removeEvent(target, type, listener); target = type = listener = null; } );
    	scope = null;
    	return true;
    }

    this.removeEvent = function(target, type, listener) {
        var key, invoker, capture;
        key = registryKey(targetId(target), type, listener);
        if (!isInRegistry(key)) return false;
        invoker       = registry[key].invoker;
        capture       = registry[key].capture;
        registry[key] = null;
        if (target.removeEventListener) target.removeEventListener(type, invoker, capture);
        else if (target.detachEvent)    target.detachEvent("on" + type, invoker);
        else                            return false;
        return true;
    }


//    this.handleOnload = function() {
//        for (var i=0; i<window.eventManager.onload.length; i++) {
//            window.eventManager.onload[i]();
//        }
//    }
    
//    this.addOnLoad = function(func) {
//        if (window.onload != this.handleOnload) {
//            window.eventManager.onload[window.eventManager.onload.length] = window.onload;
//            window.onload = this.handleOnload;
//        }
//        window.eventManager.onload[window.eventManager.onload.length] = func;
////        if (typeof(window.onload) != 'function') window.onload = func;
////        else {
////            var oldLoad = window.onload;
////            window.onload = function() {
////                oldLoad();
////                func();
////            }
////        }
//    }
    
//    this.addOnUnload = function(func) {
//        if (typeof(window.onunload) != 'function') window.onunload = func;
//        else {
//            var oldUnload = window.onunload;
//            window.onunload = function() {
//                alert('running '+oldUnload);
//                oldUnload();
//                alert('running '+func);
//                func();
//            }
//        }
//    }
    
    this.addOnResize = function(func) {
        if (typeof(window.onresize) != 'function') window.onresize = func;
        else {
            var oldResize = window.onresize;
            window.onresize = function() {
                oldResize();
                func();
            }
        }
    }
    
    return this;
}

EventManager.prototype             = new Object;
EventManager.prototype.constructor = EventManager;
EventManager.superclass            = Object.prototype;

window.eventManager = new EventManager();
window.EventManager = window.eventManager;

function EventManager_CleanWindow() {
    window.onafterprint   = null;
    window.onbeforeprint  = null;
    window.onbeforeunload = null;
    window.onblur         = null;
    window.ondragdrop     = null;
    window.onerror        = null;
    window.onfocus        = null;
    window.onhelp         = null;
    window.onload         = null;
    window.onmove         = null;
    window.onresize       = null;
    window.onscroll       = null;
    window.onunload       = null;
}

EventManager.instance = null;
EventManager.getInstance = function() {
    if (!EventManager.instance) EventManager.instance = new EventManager();
    return EventManager.instance;
}

/**
 * Methods opened up to the window object:
 *
 *   addEvent
 *   removeEvent
 *   addOnload
 *   addOnUnload
 *   addOnResize
 *
 */

window.addEvent = function(target, type, listener, scope, capture) {
    if (window.eventManager) window.eventManager.addEvent(target, type, listener, scope, capture);
    else return false;
}

window.removeEvent = function(target, type, listener) {
    if (window.eventManager) window.eventManager.removeEvent(target, type, listener);
    else return false;
}

window.isEventRegistered = function(target, type, listener) {	
    if (window.eventManager) return window.eventManager.isEventRegistered(target, type, listener);
    else return false;
}





/**
 * Handles for multiple onLoad functions.
 */
window.loadQueue = new Array();
// Alias the names so it makes sense for everyone
window.addOnLoad = window.addOnload = function Window_AddOnLoad(func) {
    if (!(window.onload instanceof Function)) {
        if (window.onload) {
            var oldOnload = window.onload;
            window.loadQueue.push(function() { oldOnload });
        }
        window.onload = Window_OnLoadQueue;
    } else if (window.onload !== Window_OnLoadQueue) {
        loadQueue.push(window.onload);
        window.onload = Window_OnLoadQueue;
    }
    var sz = window.loadQueue.length;
    window.loadQueue[sz] = func;
}
function Window_OnLoadQueue() {
    for (var i=0; i<window.loadQueue.length; i++) {
        var loadFunc = window.loadQueue[i];
        loadFunc();
    }
}
window.onload = Window_OnLoadQueue;








/**
 * Handles for multiple onUnload functions.
 */
window.unloadQueue = new Array();
function Window_OnUnloadQueue() {
    for (var i=0; i<window.unloadQueue.length; i++) {
        var unloadFunc = window.unloadQueue[i];
        unloadFunc();
    }
    /**
     * Google Maps API Version 2 introduced a javascript
     * closure cleanup function... call it if its defined.
     */ 
    if (typeof(GUnload) == 'function') GUnload();
    // Cleanup event manager memory space
    window.onload       = null;
    window.onunload     = null;
    window.onresize     = null;
    window.eventManager = null;
    window.EventManager = null;
}
// Alias the names so it make sense for everyone
window.addOnunload = window.addOnUnLoad = window.addOnUnload = function Window_AddOnUnload(func) {
    if (!(window.onunload instanceof Function)) {
        if (window.onunload) {
            var oldUnload = window.onunload;
            window.unloadQueue.push(function() { oldUnload });
        }
        window.onunload = Window_OnUnloadQueue;
    } else if (window.onunload !== Window_OnUnloadQueue) {
        window.unloadQueue.push(window.onunload);
        window.onunload = Window_OnUnloadQueue;
    }
    window.unloadQueue.push(func);
}
window.onunload = Window_OnUnloadQueue;










window.addOnResize = function(func) {
    if (window.eventManager) window.eventManager.addOnResize(func);
    else return false;
}



if (typeof window.addOnUnload == 'function') window.addOnUnload(EventManager_CleanWindow);









/**
 * This kinda sucks that I have to instantiate an XMLHttpRequest
 * in order to come up with a valid id for them in the event manager.
 */
var xmlhttp = null;
try {
    xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
    try {
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
    } catch (e) {
        try {
            xmlhttp = new XMLHttpRequest();
        } catch (e) {
            //this.request = new IframeHttpRequest();
            xmlhttp = null;
        }
    }
}
