// $Header: /web/src/rsearch/web/js/common.js,v 1.67 2008-05-07 07:19:26 ahope Exp $
/*--------------------------------------------------------------------------
A shared library of javascript code to be used throughout the site
--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------
Generic helper functions
--------------------------------------------------------------------------*/

// Putting this here rather than in RUI.BrowserSniffer.initialize() as an
// optimization measure. Styles are changing too long after the page renders
// at the moment, possibly causing confusion for users.
(function () {
    //CSS Browser Selector v0.2.5
    //Documentation: http://rafael.adm.br/css_browser_selector
    //License:       http://creativecommons.org/licenses/by/2.5/
    //Author:        Rafael Lima (http://rafael.adm.br)
    //Contributors:  http://rafael.adm.br/css_browser_selector#contributors

    //method is
    //desc   searches for a substring within userAgent string
    //param  [req] t [String]
    function is(t) {
        return ua.indexOf(t) !== -1;
    }

    var ua = navigator.userAgent.toLowerCase();
    var h = document.getElementsByTagName('html')[0];

    // Browser/platform information
    var b = (!(/opera|webtv/i.test(ua)) && /msie (\d)/.test(ua)) ?
            ('ie ie' + RegExp.$1) :
            is('gecko/')          ? 'gecko'                   :
            is('opera/9')         ? 'opera opera9'            :
            /opera (\d)/.test(ua) ? 'opera opera' + RegExp.$1 :
            is('konqueror')       ? 'konqueror'               :
            is('applewebkit/')    ? 'webkit safari'           :
            is('mozilla/')        ? 'gecko'                   : '';
    var os = (is('x11') || is('linux')) ? ' linux' :
            is('mac')                   ? ' mac'   :
            is('win')                   ? ' win'   : '';

    // Compile list of class names to be added to the root html element
    var c = b + os + ' js';

    // Apply the classes
    h.className += h.className ? ' ' + c : c;
})();

// rich media onload handler
// TODO: Refactor this into the RUI namespace
function WindowOnload(f, arg) {
    var f_prev;

    if (inFrame()) {
        f_prev = parent.window.onload;
        window.parent.onload = function () {
            if (f_prev) {
                f_prev(arg);
            }
            f(arg);
        };
    }

    var prev = window.onload;
    window.onload = function () {
        if (prev) {
            prev(arg);
        }
        f(arg);
    };
}

// open popup
// TODO: Refactor this into the RUI namespace
function openwin(page, W, H) {
    window.open(
        page,
        '',
        'menubar=no,toolbar=no,status=no,width=' + W + ',height=' + H +
            ',resizable=no'
    );
}

// generate a random alpha id
// TODO: Refactor this into the RUI namespace
function randomAlphaId() {
    var chars = 'abcdefghiklmnopqrstuvwxyz';
    var string_length = 10;
    var randomstring = '';
    var rnum;

    for (var i = 0; i < string_length; i++) {
        rnum = Math.floor(Math.random() * chars.length);
        randomstring += chars.substring(rnum, rnum + 1);
    }

    return randomstring;
}

// land estate map rollovers
// TODO: Refactor this into the RUI namespace
function classChangeIn(id) {
    document.getElementById(id).className = 'show';
    document.getElementById('dot').className = 'hide';
}

// TODO: Refactor this into the RUI namespace
function classChangeOut(id) {
    document.getElementById(id).className = 'hide';
    document.getElementById('dot').className = 'show';
}

// get the width of the current window
// TODO: Refactor this into the RUI namespace
function getWindowWidth() {
    var width = 0;
    if (typeof(window.outerWidth) === 'number') {
        width = window.outerWidth;
    }
    else if (document.documentElement && document.documentElement.clientWidth) {
        width = document.documentElement.clientWidth;
    }
    else if (document.body && document.body.clientWidth) {
        width = document.body.clientWidth;
    }
    return width;
}

//var myFrame;
// TODO: Refactor this into the RUI namespace
function setFrameId(id) {
    document.myFrame = id;
}

//method [static] createAdHTML
//desc   Writes an Accipiter ad tag to the page.
//note   This method is deprecated in favour of RUI.Ad.writeAdHTML.
function createAdHTML(tag, width, height, id) {
    var options = {
        height: height,
        width : width,
        id    : id
    };

    RUI.Ad.writeAdHTML(tag, options);
}

/*
    Validate user input for contact agent form
    param [req] search    dom reference to form element
*/
// TODO: Refactor this into the RUI namespace
function CheckDisplaySingleFormEntry(search) {
    if (
        search.Name.value === '' ||
        search.Email.value === ''
    ) {
        alert('You need to enter a Name and Email Address');
        return false;
    }

    return true;
}


/* Rich Media Control Functions */

var delayMouseOverMS = 750; // milliseconds

var  requiredMajorVersion, requiredMinorVersion, requiredRevision;

if (!requiredMajorVersion) {
    requiredMajorVersion = 7;
}

if (!requiredMinorVersion) {
    requiredMinorVersion = 0;
}

if (!requiredRevision) {
    requiredRevision = 0;
}

var jsVersion = 1.0;

// TODO: Refactor this into the RUI namespace
function hidePluginNote(pid) {
    var targ = inFrame() ? window.parent.document : document;
    targ.getElementById(pid).style.visibility = 'hidden';
}

// Visual basic helper required to detect Flash Player ActiveX control version
// information.
var detect_vb_tag = '<scr' + 'ipt language="VB'
    + 'Script" type="text/vbscript">\n'
    + 'Function VBGetSwfVer(i)\n'
    + ' on error resume next\n'
    + ' Dim swControl, swVersion\n'
    + ' swVersion = 0\n'
    + ' set swControl ='
    + ' CreateObject("ShockwaveFlash.ShockwaveFlash." + CStr(i))\n'
    + ' if (IsObject(swControl)) then\n'
    + '  swVersion = swControl.GetVariable("$version")\n'
    + ' end if\n'
    + ' VBGetSwfVer = swVersion\n'
    + 'End Function\n'
    + ' </script>\n';

document.write(detect_vb_tag);

var isIE    = (navigator.appVersion.indexOf('MSIE') !== -1);
var isWin   = (navigator.appVersion.toLowerCase().indexOf('win') !== -1);
var isOpera = (navigator.userAgent.indexOf('Opera') !== -1);
jsVersion = 1.1;
// TODO: Refactor this into the RUI namespace
function JSGetSwfVer(i) {
    var swVer2, flashDescription;

    // NS/Opera version >= 3 check for Flash plugin in plugin array
    if (navigator.plugins !== null && navigator.plugins.length > 0) {
        if (
            navigator.plugins['Shockwave Flash 2.0']
            || navigator.plugins['Shockwave Flash']
        ) {
            swVer2 = navigator.plugins['Shockwave Flash 2.0'] ? ' 2.0' : '';
            flashDescription = navigator.plugins[
                'Shockwave Flash' + swVer2
            ].description;
            descArray = flashDescription.split(' ');
            tempArrayMajor = descArray[2].split('.');
            versionMajor = tempArrayMajor[0];
            versionMinor = tempArrayMajor[1];
            if (descArray[3] !== '') {
                tempArrayMinor = descArray[3].split('r');
            }
            else {
                tempArrayMinor = descArray[4].split('r');
            }
            versionRevision = tempArrayMinor[1] > 0 ? tempArrayMinor[1] : 0;
            flashVer = versionMajor + '.' + versionMinor + '.'
                + versionRevision;
        }
        else {
            flashVer = -1;
        }
    }
    else {
        flashVer = -1;
    }

    return flashVer;
}

// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that
// version or greater is available.
// TODO: Refactor this into the RUI namespace
function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) {
    var reqVer = parseFloat(reqMajorVer + '.' + reqRevision);

    var versionStr;

    // loop backwards through the versions until we find the newest version
    for (i = 25; i > 0; i--) {
        if (isIE && isWin && !isOpera) {
            versionStr = VBGetSwfVer(i);
        }
        else {
            versionStr = JSGetSwfVer(i);
        }

        if (versionStr === -1 ) {
            return false;
        }
        else if (versionStr !== 0) {
            if (isIE && isWin && !isOpera) {
                tempArray    = versionStr.split(' ');
                tempString   = tempArray[1];
                versionArray = tempString.split(',');
            }
            else {
                versionArray = versionStr.split('.');
            }

            versionMajor    = versionArray[0];
            versionMinor    = versionArray[1];
            versionRevision = versionArray[2];

            // 7.0r24 == 7.24
            versionString   = versionMajor + '.' + versionRevision;

            versionNum      = parseFloat(versionString);

            // is the major.revision >= requested major.revision AND the minor
            // version >= requested minor.
            if ((versionMajor > reqMajorVer) && (versionNum >= reqVer)) {
                return true;
            }
            else {
                return (versionNum >= reqVer && versionMinor >= reqMinorVer);
            }
        }
    }
}

// TODO: Refactor this into the RUI namespace
// TODO: Refactor to use SWFObject
function returnFlashTag(
    div_id,
    swf_id,
    movieTag,
    movieHeight,
    movieWidth,
    FlashVars,
    staticImg,
    staticLink,
    showMeImmediately,
    trig_img_id
) {
    var hasRequestedVersion = DetectFlashVer(
        requiredMajorVersion,
        requiredMinorVersion,
        requiredRevision
    );
    var isIE = (navigator.appVersion.indexOf('MSIE') !== -1);

    var allow_fscommand, fsTags, oeTags, rma_alternateContent, openNewWin;
    if (
        window.parent.location.search.toString().indexOf('noflash=true') !== -1
    ) {
        hasRequestedVersion = false;
    }

    if (hasRequestedVersion) {
        allow_fscommand = true;

        if (allow_fscommand) {
            // Handle all the FSCommand messages in a Flash movie.
            fsTags = '<scr' + 'ipt type=\"text/javas' + 'cript\">\n'
                + 'var isInternetExplorer ='
                + ' navigator.appName.indexOf("Microsoft") !== -1;\n'
                + 'function ' + swf_id + '_DoFSCommand(command, args) {\n'
                + 'var ' + swf_id + '_sresObj = isInternetExplorer ?'
                + ' document.all.' + swf_id + ' : document.' + swf_id + ';\n'
                + 'eval (command);\n'
                + '}\n'
                + '</script>\n';

            // Hook for Internet Explorer.
            if (
                navigator.appName
                && navigator.appName.indexOf('Microsoft') !== -1
                && navigator.userAgent.indexOf('Windows') !== -1
                && navigator.userAgent.indexOf('Windows 3.1') === -1
            ) {
                fsTags += '<scr' + 'ipt type=\"text/javas'
                    + 'cript\" event=\"FSCommand(command,args)\" for=\"'
                    + swf_id + '\" >\n'
                    + 'eval (command);\n'
                    + '</script>\n';
            }
        }
        else {
            fsTags = '';
        }

        oeTags = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" '
            + 'width="' + movieWidth + '" height="' + movieHeight + '" id="'
            + swf_id + '" ' + 'codebase="http://download.macromedia.com/pub/'
            + 'shockwave/cabs/flash/swflash.cab">'
            + '<param name="movie" value="' + movieTag
            + '" /><param name="FlashVars" value="' + FlashVars + '" />'
            + '<param name="quality" value="high" />'
            + '<param name="bgcolor" value="#FFFFFF" />'
            + ' <param name="wmode" value="transparent" />'
            + '<param name="allowScriptAccess" value="always" />'
            + '<param name="swLiveConnect" value="true" />'
            + '<embed src="' + movieTag + '" quality="high" bgcolor="#FFFFFF" '
            + 'width="' + movieWidth + '" height="' + movieHeight + '" name="'
            + swf_id + '" align="middle"  id="' + swf_id + '" '
            + 'play="true" loop="false" FlashVars="' + FlashVars
            + '" quality="high" wmode="transparent" '
            + 'allowScriptAccess="always" swLiveConnect="true"'
            + ' type="application/x-shockwave-flash"'
            + ' pluginspage="http://www.macromedia.com/go/getflashplayer">'
            + '<\/embed>'
            + '<\/object>';
        output = oeTags + fsTags;
        return output;
    }
    else {
        if (showMeImmediately) {
            if (staticImg) {
                rma_alternateContent = '<a href="' + staticLink
                    + '" target="_blank"><img src="' + staticImg
                    + '" border="0" id="staticImg" /></a>';
            }
            else {
                rma_alternateContent = '<div style="border:1px solid #ccc;'
                    + 'background:#fff;text-align:center;padding:10px;'
                    + 'font-weight:bold;color:#333;" id="pn_' + swf_id + '">'
                    + 'This rich media content requires the'
                    + ' Macromedia Flash Player. '
                    + '<a href=http://www.macromedia.com/go/getflash/>'
                    + 'Get Flash</a> | <a href="javascript:void(0);"'
                    + ' onclick="expad_hideMe(\'' + div_id + '\')">'
                    + 'close</a></div>';
            }
        }
        else {
            // this isn't an all flash version - the static gif needs a link
            // applied to it.
            trig_img_id = document.getElementById(trig_img_id);
            if (isIE) {
                trig_img_id.onmousedown = function () {
                    openNewWin = window.open(
                        staticLink,
                        'RealEstate.com.au',
                        'status=1,toolbar=1,scrollbars=1,location=1,resizable=1'
                    );
                    openNewWin.focus();
                };
            }
            else {
                trig_img_id.addEventListener('mousedown', function () {
                    var openNewWin = window.open(
                        staticLink,
                        'RealEstate.com.au',
                        'status=1,toolbar=1,scrollbars=1,location=1,resizable=1'
                    );
                    openNewWin.focus();
                }, false);
                rma_alternateContent = '<!-- NOFLASHCONTENT -->';
            }

            output = rma_alternateContent;  // insert non-flash content
        }

        return output;
    }

    if (isIE) {
        document.onmousedown = routeClickDivDelay;
    }
    else {
        document.addEventListener('mousedown', routeClickDivDelay, false);
    }

    var showOnlyOneAd = true;
}

// TODO: Refactor this into the RUI namespace
function getElementLeft(eElement) {
    if (!eElement && this) {
        // identify the element as the method owner
        eElement = this;
    }

    var nLeftPos = eElement.offsetLeft; // initialize var to store calculations
    // identify first offset parent element
    var eParElement = eElement.offsetParent;

    // move up through element hierarchy
    while (eParElement !== null) {
        // appending left offset of each parent
        nLeftPos += eParElement.offsetLeft;
         // until no more offset parents exist
        eParElement = eParElement.offsetParent;
    }

    // return the number calculated
    return nLeftPos;
}

// TODO: Refactor this into the RUI namespace
function getElementTop(eElement) {
    if (!eElement && this) {
        eElement = this;
    }

    var nTopPos = eElement.offsetTop;
    var eParElement = eElement.offsetParent;

    while (eParElement !== null) {
        nTopPos += eParElement.offsetTop;
        eParElement = eParElement.offsetParent;
    }

    return nTopPos;
}



// TODO: Refactor this into the RUI namespace
function returnPositionArray(
    trig_img_id,
    myFrame,
    movieHeight,
    movieWidth,
    rm_alignment
) {
    var xalign = rm_alignment[0];
    var yalign = rm_alignment[1];

    if (rm_alignment[2]) {
        whereDraw_rl = rm_alignment[2];
    }
    else {
        whereDraw_rl = 'left';
    }

    if (rm_alignment[3]) {
        whereDraw_tb = rm_alignment[3];
    }
    else {
        whereDraw_tb = 'bottom';
    }

    if (trig_img_id) {
        if (!myFrame) {
            targElement    = window.parent.document.getElementById(myFrame);
            t_framePosTop  = getElementTop(targElement);
            t_framePosLeft = getElementLeft(targElement);
        }
        else {
            t_framePosTop  = 0;
            t_framePosLeft = 0;
        }

        t_adPosTop = getElementTop(trig_img_id);

        // LEFT: find the position of this frame and this element inside the
        // frame.
        t_adPosLeft = getElementLeft(trig_img_id);
        if (whereDraw_rl === 'right') {
            t_rmPosLeft = (t_framePosLeft - 0) + (t_adPosLeft - 0);
        }

        if (whereDraw_rl === 'left') {
            t_rmPosLeft = (t_framePosLeft - 0) + (t_adPosLeft - 0)
                - (movieWidth - 0);
        }

        if (whereDraw_tb === 'top') {
            t_rmPosTop = (t_framePosTop - 0) + (t_adPosTop - 0)
                - (movieHeight - 0);
        }

        if (whereDraw_tb === 'bottom') {
            t_rmPosTop = (t_framePosTop - 0);
        }

        if (yalign === 'bottom') {
            t_rmPosTop = (t_framePosTop - 0) + (t_adPosTop - 0);
        }

        if (xalign === 'right') {
            t_rmPosLeft += trig_img_id.width;
        }

        if (yalign === 'bottom') {
            t_rmPosTop += trig_img_id.height;
        }
    }
    else {
        // there was no trig_img_id so this means we're drawing it from the top
        // left of the screen.
        t_rmPosLeft = 0;
        t_rmPosTop = 0;
    }

    t_divWidth = movieWidth;
    t_divHeight = movieHeight;

    return [t_rmPosTop, t_rmPosLeft, t_divWidth, t_divHeight];
}

// TODO: Refactor this into the RUI namespace
function noFlash(flashtags) {
    if (flashtags) {
        return !(flashtags.match(/embed/));
    }

    return true;
}

// TODO: Refactor this into the RUI namespace
function createAdDiv(
    flashTags,
    div_id,
    swf_id,
    myFrame,
    trig_img_id,
    movieHeight,
    movieWidth,
    rm_alignment,
    typeInteraction,
    showMeImmediately
) {
    var nft = noFlash(flashTags);

    var nftTargWidth;

    if (nft) {
        nftTargWidth = trig_img_id.width;
        movieWidth = nftTargWidth;
    }

    var position_array = returnPositionArray(
        trig_img_id,
        myFrame,
        movieHeight,
        movieWidth,
        rm_alignment
    );

    var rmPosTop  = position_array[0];
    var rmPosLeft = position_array[1];
    var divWidth  = position_array[2];
    var divHeight = position_array[3];

    if (!myFrame) {
        // create dynamically div tag
        dv = window.parent.document.createElement('div');
    }
    else {
        dv = document.createElement('div');
    }

    dv.setAttribute('id', div_id); //give it an id
    dv.className        = 'top'; // set the style classname
    dv.style.position   = 'absolute';
    dv.style.left       = rmPosLeft + 'px';
    dv.iOver = dv.dOver = false;
    dv.style.top        = rmPosTop + 'px';

    if (showMeImmediately) {
        dv.style.overflow = 'hidden';
        dv.showMeImmediately = true;
    }
    else {
        dv.showMeImmediately = false;
    }

    // set the final width once it has been activated
    dv.finalWidth = divWidth + 'px';

    dv.style.height = divHeight + 'px';
    dv.noFlash = false;

    if (nft) {
        dv.style.width = nftTargWidth;
    }
    else {
        if (showMeImmediately) {
            // set to 0 initally - this will allow us to load the inner flash
            // file when the page loads.
            dv.style.width = dv.finalWidth;
        }
        else {
            dv.style.width = '0px';
        }
    }

    dv.style.zIndex = 100;

    if (!showMeImmediately) {
        dv.style.visibility = 'hidden';
    }

    dv.swf     = swf_id;
    dv.myFrame = myFrame;
    dv.onHold  = false;

    //set the html content inside the div tag
    dv.typeInteraction = typeInteraction;

    dv.innerHTML = '<div class="flash_child" id="' + dv.id + '"_child">'
        + flashTags + '</div>';

    if (flashTags !== '<!-- NOFLASHCONTENT -->') {
        if (isIE) {
            dv.onmousedown = setAdDivClick;
        }
        else {
            dv.addEventListener('mousedown', setAdDivClick, false);
        }

        if (dv.typeInteraction === 'mouseOver') {
            setRulesOnMouseover(dv);
        }
    }
    else {
        dv.noFlash = true;
    }

    if (showMeImmediately) {
        window.parent.document.getElementById(myFrame).style.height = '1px';
    }

    window.parent.document.getElementById('rm_container').appendChild(dv);
}

// TODO: Refactor this into the RUI namespace
function getBrowserWindowWidth() {
    var winW;

    if (isIE) {
        winW = window.parent.document.body.offsetWidth;
    }
    else {
        winW = window.parent.innerWidth;
    }

    return winW;
}

//var myFrame;
// TODO: Refactor this into the RUI namespace
function returnMyFrame() {
    var dls = document.location.toString();
    var searchFor = 'acc_random=';

    if (dls.indexOf(searchFor) !== -1) {
        st  = dls.indexOf(searchFor) + searchFor.length;
        dli = dls.substring(st);
        if (dli.indexOf('/') !== -1 ) {
            en = dli.indexOf('/');
            return 'iframe' + dli.substring(0,en);
        }
        else {
            return 'iframe' + dli;
        }
    }
}

// TODO: Refactor this into the RUI namespace
function resizeDiv(div_id, newWidth, newHeight) {
    var d, l, cw;

    if (inFrame()) {
        d = window.parent.document.getElementById(div_id);
    }
    else {
        d = document.getElementById(div_id);
    }

    var childDiv = window.parent.document.getElementById(div_id + '_child');

    if (newWidth) {
        l  = d.style.left;
        w  = d.finalWidth;
        cw = d.style.width;

        if (!d.retWidth) {
            d.retWidth = w;
            d.retLeft = l;
            childDiv.retMargin = childDiv.style.marginLeft;
        }

        l  = l.substr(0, l.length - 2); // get the number
        w  = w.substr(0, w.length - 2);
        cw = cw.substr(0, cw.length - 2);
        newWidth = newWidth - 0;
        l = l - 0; // make sure its a number
        w = w - 0;

        if (cw === newWidth) {
            return;
        }

        if (newWidth < w) {
            //contracting
            ad                        = w - newWidth;
            d.style.width             = newWidth + 'px';
            d.style.left              = (l + ad) + 'px';
            childDiv.style.marginLeft = '-' + ad + 'px';
            d.closeWidth              = newWidth;
            register_ad(d, 0);
        }
        else {
            ad = w - newWidth;

            if (cw !== newWidth) {
                d.style.width = d.retWidth;
            }

            d.style.left              = d.retLeft;
            childDiv.style.marginLeft = childDiv.retMargin;
            register_ad(d, 1);
        }
    }

    if (newHeight) {
        hh = d.style.height;
        dh = hh.substr(0, hh.length - 2) - 0;

        if (dhi === newHeight) {
            return;
        }

        if (dh > newHeight) {
            //contracting
            d.closeHeight = newHeight;
            register_ad(d, 0);
        }
        else {
            register_ad(d, 1);
        }

        d.style.height = newHeight + 'px';
    }

    newHeight = null;
    newWidth = null;
}

// deprecated but still in use
// TODO: Refactor this into the RUI namespace
function MovObj(
    rm_alignment,
    trig_img_id,
    FlashVars,
    movieTag,
    movieWidth,
    movieHeight,
    typeInteraction,
    showMeImmediately
) {
    var random = Math.round(Math.random() * 10000000000);
    var div_id, swf_id;
    this.swf_id          = 'swf_' + random;
    this.div_id          = 'div_' + this.swf_id;
    this.rm_alignment    = rm_alignment;
    this.trig_img_id     = trig_img_id;
    this.FlashVars       = FlashVars;
    this.movieTag        = movieTag;
    this.movieWidth      = movieWidth;
    this.movieHeight     = movieHeight;
    this.typeInteraction = typeInteraction;
    if (showMeImmediately) {
        this.showMeImmediately = showMeImmediately;
    }
}

// TODO: Refactor this into the RUI namespace
function getRichMediaAd(argObj) {
    var random;

    if (inFrame()) {
        argObj.myFrame = returnMyFrame();
    }
    else {
        argObj.myFrame = false;
    }

    if (!argObj.swf_id) {
        random = Math.round(Math.random() * 10000000000);
        argObj.swf_id = 'swf_' + random;
        argObj.div_id = 'div_' + argObj.swf_id;
    }

    argObj.FlashVars += '&staticImg=' + argObj.staticImg + '&staticLink='
        + argObj.staticLink + '&typeInteraction=' + argObj.typeInteraction
        + '&useDomain=' + document.domain;

    if (argObj.showMeImmediately) {
        argObj.FlashVars += '&showMeImmediately=true';
    }

    argObj.FlashVars += '&closeHandler=expad_hideMe("' + argObj.div_id + '");'
        + '&registerHandler=auto_register_ad("' + argObj.div_id + '", 1);'
        + '&adControlsURL=/im/flash/ad_controller.swf&live=true&div_id='
        + argObj.div_id + '&movieWidth=' + argObj.movieWidth
        + '&movieHeight=' + argObj.movieHeight + '&movieid=' + argObj.swf_id
        + '&delayMouseOverMS=' + delayMouseOverMS + '&';

    var flashTags = returnFlashTag(
        argObj.div_id,
        argObj.swf_id,
        argObj.movieTag,
        argObj.movieHeight,
        argObj.movieWidth,
        argObj.FlashVars,
        argObj.staticImg,
        argObj.staticLink,
        argObj.showMeImmediately,
        argObj.trig_img_id
    );

    if (document.getElementById(argObj.trig_img_id)) {
        // we are aligning this to an element in the frame
        trig_img_id = document.getElementById(argObj.trig_img_id);
    }
    else {
        trig_img_id = window.parent.document.getElementById(argObj.trig_img_id);
    }

    createAdDiv(
        flashTags,
        argObj.div_id,
        argObj.swf_id,
        argObj.myFrame,
        trig_img_id,
        argObj.movieHeight,
        argObj.movieWidth,
        argObj.rm_alignment,
        argObj.typeInteraction,
        argObj.showMeImmediately
    );

    if (inFrame()) {
        argObj.div_elem = window.parent.document.getElementById(argObj.div_id);
    }
    else {
        argObj.div_elem = document.getElementById(argObj.div_id);
    }
}

// TODO: Refactor this into the RUI namespace
function createRichMediaAd(argObj) {
    WindowOnload(initOads);
    WindowOnload(getRichMediaAd,argObj);
}

// --------------------------------------------------------------------
// Functions to control data flow and page actions
// --------------------------------------------------------------------
//


// TODO: Refactor this into the RUI namespace
function setRulesOnMouseover(div_id) {
    if (isIE) {
        div_id.onmouseout = function (evt) {
            div_id.dOver = false;
            div_id.iOver = false;
            expad_mouseOut(div_id.id);
        };
    }
    else {
        div_id.addEventListener('mouseout', function (evt) {
            div_id.dOver = false;
            div_id.iOver = false;
            expad_mouseOut(div_id.id);
        }, true);
    }

    if (isIE) {
        div_id.onmouseover = function () {
            div_id.dOver = true;
        };
    }
    else {
        div_id.addEventListener('mouseover', function () {
            div_id.dOver = true;
        }, true);
    }
}

// called after the delay to see if user is still hovering over the target
// TODO: Refactor this into the RUI namespace
function expad_showMe_mouseOverTest(div_id, fromMouseOver) {
    var targObj     = (inFrame()) ? window.parent.document : window.document;
    var targObjElem = targObj.getElementById(div_id);
    if (targObjElem.showMeImmediately) {
        if (targObjElem.dOver === 1) {
            expad_showMe_SWF(targObjElem, 1);
        }
    }
    else {
        if (targObjElem.iOver === 1) {
            expad_showMe(targObjElem, 1);
        }
    }
}

// TODO: Refactor this into the RUI namespace
function expad_showMe_SWF(div_id, fromMouseOver) {
    setFlashVariables(div_id, div_id.swf, 'requestReload=true');
}

// TODO: Refactor this into the RUI namespace
function expad_showMe(div_id,fromMouseOver) {
    controlGates(0, div_id.id);
    setAdDivClick();

    var oads = returnOpenedAdArray();

    if (oads[0] === div_id) {
        return;
    }

    div_id.style.display    = 'block';
    div_id.style.visibility = 'visible';
    div_id.style.width      = div_id.finalWidth;

    if (div_id.hasDisplayed === 1 && !div_id.showMeImmediately) {
        setFlashVariables(div_id, div_id.swf, 'requestReload=true');
    }

    div_id.hasDisplayed = 1;
    register_ad(div_id, 1);
}

// setOnHold -  called from flash, takes a true/false paramenter in addition to
// the div_id. used to determine if user is using a form
// TODO: Refactor this into the RUI namespace
function setOnHold(div_id,onoff) {
    var targObj = (inFrame()) ? window.parent.document : window.document;

    targObj.getElementById(div_id).onHold = onoff;
}

// controlGates - used to prevent infinite mouseOut loops
// TODO: Refactor this into the RUI namespace
function controlGates(offon, div_id) {
    var targObj = (inFrame()) ? window.parent.document : window.document;

    div_id = targObj.getElementById(div_id);

    if (offon === 0) {
        div_id.setBrakes = true;
        setTimeout('controlGates(1, "' + div_id.id + '")', 50);
    }
    else {
        div_id.setBrakes = false;
    }
}

// TODO: Refactor this into the RUI namespace
function expad_mouseOver(dv, ref) {
    if (dv && dv.noFlash) {
        return;
    }

    if (ref === 1) { // over the image
        if (dv.id) {
            div_id = dv.id;
        }
        else {
            div_id = dv;
        }

        if (dv.showMeImmediately) {
            dv.dOver = true;
        }
        else {
            dv.iOver = true;
        }

        setTimeout(
            'expad_showMe_mouseOverTest("' + div_id + '", 1)', delayMouseOverMS
        );
    }
}

// TODO: Refactor this into the RUI namespace
function expad_mouseOutImg(div_id) {
    if (div_id) {
        div_id.iOver = false;
    }

    setTimeout('expad_mouseOut("' + div_id.id + '",1)', 50);
}

// TODO: Refactor this into the RUI namespace
function expad_mouseOut(div_id, ref) {
    var targObj = (inFrame()) ? window.parent.document : window.document;
    var targ    = targObj.getElementById(div_id);
    var oads    = returnOpenedAdArray(); // check to make sure it's open

    if (targ.noFlash || oads.length < 1) {
        return;
    }

    if (ref === 1) {
        targ.iOver = false;
    }
    else {
        targ.dOver = false;
    }

    if ((targ.dOver === null) || (targ.dOver || targ.iOver)) {
        return;
    }

    var ok = false;

    for (i = 0; i < oads.length; i++) {
        if (oads[i] === targ) {
            ok = true;
            break;
        }
    }

    if (targ.onHold || targ.setBrakes || !ok) {
        return;
    }
    else {
        routeCloser(targ);
    }
}

// TODO: Refactor this into the RUI namespace
function expad_hideMe(div_id) {
    if (typeof div_id === 'string') {
        if (inFrame()) {
            div_id = window.parent.document.getElementById(div_id);
        }
        else {
            div_id = document.getElementById(div_id);
        }
    }

    if (div_id.setBrakes) {
        return;
    }

    div_id.iOver = div_id.dOver = false;
    div_id.style.visibility = 'hidden';
    div_id.style.display = 'none';
    register_ad(div_id, 0);
}

// TODO: Refactor this into the RUI namespace
function inFrame() {
    return (self !== top);
}

// TODO: Refactor this into the RUI namespace
function setAdDivClick(arg) {
    // tells the system that an ad was just clicked (to prevent the
    // document.onclick from hiding the ad div).
    var targ = inFrame() ? window.parent.document : document;
    targ.ad_div_clicked = (arg !== 1);
}

// TODO: Refactor this into the RUI namespace
function routeClickDivDelay() {
    setTimeout(routeClickDiv, 100);
}

// TODO: Refactor this into the RUI namespace
function routeClickDiv() {
    var oads = returnOpenedAdArray();

    var div_id, targ;

    if (oads) {
        if (oads.length > 0) {
            div_id = oads[0];
        }

        targ = inFrame() ? window.parent.document : document;

        if (!targ.ad_div_clicked && oads.length > 0) {
            if (div_id) {
                routeCloser(div_id);
            }
        }

        setAdDivClick(1);
    }
}


// TODO: Refactor this into the RUI namespace
function initOads() {
    if (inFrame()) {
        window.parent.document.getElementById('rm_container').opened_ads = [];
    }
    else {
        document.getElementById('rm_container').opened_ads = [];
    }
}

// TODO: Refactor this into the RUI namespace
function returnOpenedAdArray()  {
    var o;
    if (inFrame() && window.parent.document.getElementById('rm_container')) {
        o = window.parent.document.getElementById('rm_container').opened_ads;
    }
    else if (document.getElementById('rm_container')) {
        o = document.getElementById('rm_container').opened_ads;
    }
    return o;
}

// TODO: Refactor this into the RUI namespace
function routeCloser(div_id) {
    if (div_id.showMeImmediately) {
        if (!div_id.closeWidth) {
            div_id.closeWidth = null;
        }

        if (!div_id.closeHeight) {
            div_id.closeHeight = null;
        }
    }

    setFlashVariables(div_id, div_id.swf, 'requestReset=true');
}

// TODO: Refactor this into the RUI namespace
function manageSelects(n) {
    // collect all of the <select>s as an array
    var targ = inFrame() ? window.parent.document : document;
    var s    = targ.getElementsByTagName('select');
    // loop through the array
    for (var i = 0; i < s.length; i++) {
        s[i].style.visibility = (n === 0) ? 'hidden' : 'visible';
    }
}

// TODO: Refactor this into the RUI namespace
function auto_register_ad(div_id, add) {
    // called from flash - can't have the object, just the string ref
    var targ = inFrame() ? window.parent.document : document;
    var a    = targ.getElementById(div_id);

    register_ad(a, add);
}

// TODO: Refactor this into the RUI namespace
function register_ad(div_id, add) {
    var is_registered = false;
    var oads = returnOpenedAdArray();

    if (add === 1) {
        // check to see if it is already in there
        for (i = 0; i < oads.length; i++) {
            if (oads[i] === div_id) {
                is_registered = true;
            }
            else {
                if (showOnlyOneAd) {
                    routeCloser(oads[i]);
                }
            }
        }

        if (!is_registered) {
            oads[oads.length] = div_id;
        }
    }
    else {
        setOnHold(div_id.id, false);
        temp_arr = [];
        t = 0;

        for (i = 0; i < oads.length; i++) {
            if (oads[i] !== div_id) {
                temp_arr[t] = oads[i];
                t++;
            }
        }

        oads.length = 0;
        oads = temp_arr;
    }

    if (oads.length > 0) {
        manageSelects(0); // hide them
    }
    else {
        manageSelects(1);
    }
}

// TODO: Refactor this into the RUI namespace
function setFlashVariables(div_id, movieid, flashquery) {
    var targ = inFrame() ? window.parent.document : document;

    var i, values, chunk, divcontainer, divholder, divinfo;

    if (isIE) {
        chunk = flashquery.split('&');
        for (i in chunk) {
            values = chunk[i].split('=');
            targ[movieid].SetVariable(values[0], values[1]);
        }
    }
    else {
        divcontainer = 'flash_setvariables_' + movieid;

        if (!targ.getElementById(divcontainer)) {
            divholder    = targ.createElement('div');
            divholder.id = divcontainer;
            targ.body.appendChild(divholder);
        }

        targ.getElementById(divcontainer).innerHTML = '';
        divinfo = '<embed src="/im/flash/gateway.swf" FlashVars="lc=' + movieid
            + '&fq=' + escape(flashquery) + '" width="0" height="0"'
            + ' type="application/x-shockwave-flash"></embed>';
        targ.getElementById(divcontainer).innerHTML = divinfo;
    }
}

/*--------------------------------------------------------------------------
Guaranteed Top Spot Animation
*** Requires moo.fx library below ***
--------------------------------------------------------------------------*/

var GTSElements;
var GTSElementEffects = [];
var GTSDelay = 5000; // time each ad is shown (milliseconds)
var GTSFadeDuration = 350; // duration of fade effect (milliseconds)

// TODO: Refactor to use RUI.Slideshow
function initGTSAnimation() {
    var i, completeCycleTime;

    if (document.getElementById('guaranteedTopSpotLeader')) {
        // process all GTS divs on page
        GTSElements = document.getElementsByClassName('guaranteedTopSpot');
        for (i = 0; i < GTSElements.length; i++) {
            GTSElementEffects[i] = new fx.Opacity(GTSElements[i], {
                duration: GTSFadeDuration
            });
            // hide everything
            GTSElements[i].style.display = 'block';
            GTSElementEffects[i].hide();
            // schedule timing of events
            completeCycleTime = GTSElements.length * GTSDelay;
            setTimeout(
                'GTSElementEffects[' + i + '].toggle()',
                (i * GTSDelay) + GTSFadeDuration
            ); // show
            if (GTSElements.length > 1) {
                setTimeout(
                    'GTSElementEffects[' + i + '].toggle()',
                    ((i + 1) * GTSDelay)
                ); // hide
                setTimeout(
                    'GTSExecLoop("GTSElementEffects[' + i + '].toggle()", '
                        + completeCycleTime + ')',
                    (i * GTSDelay) + GTSFadeDuration
                ); // show
                setTimeout(
                    'GTSExecLoop("GTSElementEffects[' + i + '].toggle()", '
                        + completeCycleTime + ')',
                    ((i + 1) * GTSDelay)
                ); // hide
            }
        }
    }
}

function GTSExecLoop(executionString, interval) {
    eval(executionString);
    setTimeout(
        "GTSExecLoop('" + executionString + "', " + interval + ")",
        interval
    );
}

/*--------------------------------------------------------------------------
Prototype JavaScript framework
(c) 2005 Sam Stephenson <sam@conio.net>
Prototype is freely distributable under the terms of an MIT-style license.
For details, see the Prototype web site: http://prototype.conio.net/
*** Required by the moo.fx library below ***
--------------------------------------------------------------------------*/

// TODO: Upgrade this to the latest Prototype.

var Class = {
    create: function () {
        return function () {
            this.initialize.apply(this, arguments);
        };
    }
};

Object.extend = function (destination, source) {
    for (property in source) {
        destination[property] = source[property];
    }

    return destination;
};

Object.extend(Object, {
    //method [static] clone
    //desc   Clones an object.
    //param  [req] object [Object]
    //return [Object] clone
    clone: function (object) {
        return Object.extend({}, object);
    }
});

Function.prototype.bind = function (object) {
    var __method = this;
    return function () {
        return __method.apply(object, arguments);
    };
};

Function.prototype.bindAsEventListener = function (object) {
    var __method = this, args = $A(arguments);

    object = args.shift();

    return function (event) {
        return __method.apply(
            object,
            [( event || window.event)].concat(args).concat($A(arguments))
        );
    };
};

function $() {
    var elements = [];

    var element;

    for (var i = 0; i < arguments.length; i++) {
        element = arguments[i];
        if (typeof element === 'string') {
            element = document.getElementById(element);
        }

        if (arguments.length === 1) {
            return element;
        }

        elements.push(element);
    }

    return elements;
}

//-------------------------

document.getElementsByClassName = function (className) {
    var children = document.getElementsByTagName('*') || document.all;
    var elements = [];

    var child, classNames, j;

    for (var i = 0; i < children.length; i++) {
        child = children[i];
        classNames = child.className.split(' ');

        for (j = 0; j < classNames.length; j++) {
            if (classNames[j] === className) {
                elements.push(child);
                break;
            }
        }
    }

    return elements;
};

var Element = window.Element || {};

Object.extend(Element, {
    remove: function (element) {
        element = $(element);
        element.parentNode.removeChild(element);
    },

    hasClassName: function (element, className) {
        element = $(element);

        if (!element) {
            return false;
        }

        var a = element.className.split(' ');

        for (var i = 0; i < a.length; i++) {
            if (a[i] === className) {
                return true;
            }
        }

        return false;
    },

    addClassName: function (element, className) {
        element = $(element);
        Element.removeClassName(element, className);
        element.className += ' ' + className;
    },

    removeClassName: function (element, className) {
        element = $(element);

        if (!element) {
            return;
        }

        var newClassName = '';
        var a = element.className.split(' ');

        for (var i = 0; i < a.length; i++) {
            if (a[i] !== className) {
                if (i > 0) {
                    newClassName += ' ';
                }

                newClassName += a[i];
            }
        }

        element.className = newClassName;
    },

    // removes whitespace-only text node children
    cleanWhitespace: function (element) {
        element = $(element);

        var node;

        for (var i = 0; i < element.childNodes.length; i++) {
            node = element.childNodes[i];

            if (node.nodeType === 3 && !/\S/.test(node.nodeValue)) {
                Element.remove(node);
            }
        }
    }
});

//--- generic handlers

function addEvent( obj, type, fn ) {
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        EventCache.add(obj, type, fn);
    }
    else if (obj.attachEvent) {
        obj['e' + type + fn] = fn;
        obj[type + fn] = function () {
            obj['e' + type + fn](window.event);
        };
        obj.attachEvent('on' + type, obj[type + fn]);
        EventCache.add(obj, type, fn);
    }
    else {
        obj['on' + type] = obj['e' + type + fn];
    }
}

var EventCache = function () {
    var listEvents = [];

    return {
        listEvents: listEvents,
        add: function (node, sEventName, fHandler) {
            listEvents.push(arguments);
        },
        flush: function () {
            var i, item;

            for (i = listEvents.length - 1; i >= 0; i = i - 1) {
                item = listEvents[i];

                if (item[0].removeEventListener) {
                    item[0].removeEventListener(item[1], item[2], item[3]);
                }

                if (item[1].substring(0, 2) !== 'on') {
                    item[1] = 'on' + item[1];
                }

                if (item[0].detachEvent) {
                    item[0].detachEvent(item[1], item[2]);
                }

                item[0][item[1]] = null;
            }
        }
    };
}();

addEvent(window, 'unload', EventCache.flush);

Array.from = function (iterable) {
    var results = [];

    var i;

    if (!iterable) {
        return [];
    }

    if (iterable.toArray) {
        return iterable.toArray();
    }
    else {
        for (i = 0; i < iterable.length; i++) {
            results.push(iterable[i]);
        }

        return results;
    }
};

var $A = Array.from;

var Event = window.Event || {};

Object.extend(Event, {
    KEY_BACKSPACE: 8,
    KEY_TAB:       9,
    KEY_RETURN:   13,
    KEY_ESC:      27,
    KEY_LEFT:     37,
    KEY_UP:       38,
    KEY_RIGHT:    39,
    KEY_DOWN:     40,
    KEY_DELETE:   46,
    KEY_HOME:     36,
    KEY_END:      35,
    KEY_PAGEUP:   33,
    KEY_PAGEDOWN: 34,

    element: function (event) {
        return event.target || event.srcElement;
    },

    isLeftClick: function (event) {
        return (((event.which) && (event.which === 1)) ||
            ((event.button) && (event.button === 1)));
    },

    pointerX: function (event) {
        return event.pageX || (event.clientX +
            (document.documentElement.scrollLeft || document.body.scrollLeft));
    },

    pointerY: function (event) {
        return event.pageY || (event.clientY +
            (document.documentElement.scrollTop || document.body.scrollTop));
    },

    stop: function (event) {
        if (event.preventDefault) {
            event.preventDefault();
            event.stopPropagation();
        }
        else {
            event.returnValue = false;
            event.cancelBubble = true;
        }
    },

    // find the first node with the given tagName, starting from the
    // node the event was triggered on; traverses the DOM upwards
    findElement: function (event, tagName) {
        var element = Event.element(event);

        while (
            element.parentNode && (!element.tagName ||
            (element.tagName.toUpperCase() !== tagName.toUpperCase()))
        ) {
            element = element.parentNode;
        }

        return element;
    },

    observers: false,

    _observeAndCache: function (element, name, observer, useCapture) {
        if (!this.observers) {
            this.observers = [];
        }

        if (element.addEventListener) {
            this.observers.push([element, name, observer, useCapture]);
            element.addEventListener(name, observer, useCapture);
        }
        else if (element.attachEvent) {
            this.observers.push([element, name, observer, useCapture]);
            element.attachEvent('on' + name, observer);
        }
    },

    unloadCache: function () {
        if (!Event.observers) {
            return;
        }

        for (var i = 0; i < Event.observers.length; i++) {
            Event.stopObserving.apply(this, Event.observers[i]);
            Event.observers[i][0] = null;
        }

        Event.observers = false;
    },

    observe: function (element, name, observer, useCapture) {
        element = $(element);
        useCapture = useCapture || false;

        if (
            name === 'keypress' &&
            (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
            || element.attachEvent)
        ) {
            name = 'keydown';
        }

        Event._observeAndCache(element, name, observer, useCapture);
    },

    stopObserving: function (element, name, observer, useCapture) {
        element = $(element);
        useCapture = useCapture || false;

        if (
            name === 'keypress' &&
            (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
            || element.detachEvent)
        ) {
            name = 'keydown';
        }

        if (element.removeEventListener) {
            element.removeEventListener(name, observer, useCapture);
        }
        else if (element.detachEvent) {
            try {
                element.detachEvent('on' + name, observer);
            }
            catch (e) {}
        }
    }
});

/* prevent memory leaks in IE */
if (navigator.appVersion.match(/\bMSIE\b/)) {
    Event.observe(window, 'unload', Event.unloadCache, false);
}

/*--------------------------------------------------------------------------
moo.fx, simple animated effects library
by Valerio Proietti (http://mad4milk.net) MIT-style LICENSE.
for more info (http://moofx.mad4milk.net).
10/24/2005
v(1.0.2)
*** Requires the Prototype library above ***
--------------------------------------------------------------------------*/

// TODO: Replace this with Scriptaculous effects
//base
var fx = {};
fx.Base = function () {};
fx.Base.prototype = {
    setOptions: function (options) {
        this.options = {
            duration: 500,
            onComplete: ''
        };

        Object.extend(this.options, options || {});
    },

    go: function () {
        this.duration  = this.options.duration;
        this.startTime = (new Date()).getTime();
        this.timer     = setInterval(this.step.bind(this), 13);
    },

    step: function () {
        var time = (new Date()).getTime();
        var Tpos = (time - this.startTime) / (this.duration);
        if (time >= this.duration + this.startTime) {
            this.now = this.to;
            clearInterval(this.timer);
            this.timer = null;
            if (this.options.onComplete) {
                setTimeout(this.options.onComplete.bind(this), 10);
            }
        }
        else {
            this.now = ((-Math.cos(Tpos * Math.PI) / 2) + 0.5)
                * (this.to - this.from) + this.from;
            // this time-position, sinoidal transition thing is from
            // script.aculo.us.
        }
        this.increase();
    },

    custom: function (from, to) {
        if (this.timer) {
            return;
        }

        this.from = from;
        this.to   = to;
        this.go();
    },

    hide: function () {
        this.now = 0;
        this.increase();
    },

    clearTimer: function () {
        clearInterval(this.timer);
        this.timer = null;
    }
};

//fader
fx.Opacity = Class.create();
fx.Opacity.prototype = Object.extend(new fx.Base(), {
    initialize: function (el, options) {
        this.el  = $(el);
        this.now = 1;
        this.increase();
        this.setOptions(options);
    },

    increase: function () {
        if (this.now === 1) {
            this.now = 0.9999;
        }

        if (this.now > 0 && this.el.style.visibility === 'hidden') {
            this.el.style.visibility = 'visible';
        }

        if (this.now === 0) {
            this.el.style.visibility = 'hidden';
        }

        if (window.ActiveXObject) {
            this.el.style.filter = 'alpha(opacity=' + this.now * 100 + ')';
        }

        this.el.style.opacity = this.now;
    },

    toggle: function () {
        if (this.now > 0) {
            this.custom(1, 0);
        }
        else {
            this.custom(0, 1);
        }
    }
});

//desc   The REA User Interface namespace.
var RUI = window.RUI || {};

//desc   Abstraction layer for Prototype.
(function () {
    var targets = [
        '$',
        '$$',
        '$A',
        '$F',
        '$H',
        '$R',
        '$w',
        'Ajax',
        'Array',
        'Class',
        'Date',
        'Element',
        'Enumerable',
        'Event',
        'Form',
        'Function',
        'Hash',
        'Insertion',
        'Number',
        'Object',
        'ObjectRange',
        'PeriodicalExecuter',
        'Position',
        'String',
        'Template',
        'TimedObserver',
        'Try'
    ];

    var target;

    for (var i = 0; i < targets.length; i++) {
        target = targets[i];
        RUI[target] = window[target];
    }

    RUI.DOM = {
        getElementsByClassName: document.getElementsByClassName
    };

    RUI.ViewPort = document.viewport;
})();

//method [static] RUI.initialize
//desc   Initializes behaviours.
RUI.initialize = function (options) {
    RUI.GroupNavigation.initialize();
    RUI.initializeSite();
};

//method [static] RUI.initializeSite
//desc   Initializes site-specific behaviours.
//note   This may be overloaded.
RUI.initializeSite = function () {};

//desc   Controls the Group Navigation dropdown menu.
//note   This is self-contained and must not rely on external
//       code so that it can be distributed to all REA Group sites
//       without any dependencies.
RUI.GroupNavigation = {
    //method [static] initialize
    //desc   Initializes the group navigation dropdown behaviours.
    initialize: function () {
        // Id's of the html elements used in the dropdown
        var ID = {
            CONTAINER: 'groupNavBgCurve',   // CHANGE THIS?
            GROUP_NAV: 'groupNav',          // Group Nav
            DROPDOWN : 'groupNavCountries', // Dropdown menu UD
            TRIGGER  : 'groupNavTrigger'    // Trigger anchor ID
        };

        // Classes used to display the flippy triangle on the dropdown heading
        var CLASS = {
            EXPANDED  : 'expanded',  // Expanding navigation
            CONTRACTED: 'contracted' // Contract navigation
        };

        // Arbitrarily large base value for setting z-indices on the shim,
        // the dropdown and the containing element for both
        var Z_INDEX = {
            BASE_VALUE: 999
        };

        // Elements required by the createShim function
        var container = RUI.$(ID.CONTAINER);
        var trigger   = RUI.$(ID.TRIGGER);
        var groupnav  = RUI.$(ID.GROUP_NAV);
        var dropdown  = RUI.$(ID.DROPDOWN);

        var oldOnclick;

        // Check to make sure we've got all the elements we need,
        // in case the group navigation is removed from specific pages
        if (
            !container ||
            !trigger   ||
            !groupnav  ||
            !dropdown
        ) {
            return false;
        }

        //TODO:  Refactor this function to be usable by any DOM element, and to
        //       work around the current requirement to place that element at
        //       the end of the page's source code in order to work around the
        //       stacking order problem of the windowed controls it's attempting
        //       to overlay.
        //       Cf: http://weblogs.asp.net/bleroy/archive/2005/08/09/
        //           how-to-put-a-div-over-a-select-in-ie.aspx
        //
        //method [static] createShim
        //desc   Creates an invisible iframe to handle the shim effect in IE.
        //       This is used to cover Select Box, ActiveX object, Iframes etc.
        //param  [HTMLElement] element.
        //note   Only create shim if the browser is IE Version >= 5.5 && < 7.
        function createShim() {

            // Browser version for applying proprietary style filter properties
            var ieVersion = parseFloat(navigator.appVersion.split('MSIE')[1]);

            // To prevent windowed controls from appearing above the dropdown
            // list, create an iframe with the same dimensions and location, and
            // place it lower in the browser's stacking context.
            //
            // TODO: Refactor to inspect element attributes via RUI.Element
            // methods.
            var shim            = document.createElement('iframe');
            shim.scrolling      = 'no';        // no scrolling
            shim.frameBorder    = '0';         // no frame border on iframe
            shim.style.position = 'absolute';  // position iframe absolutely
            shim.style.top      = dropdown.offsetTop + 'px';
            shim.style.width    = dropdown.offsetWidth + 'px';
            shim.style.height   = dropdown.offsetHeight + 'px';
            shim.style.display  = 'block';

            // Apply a css filter for IE to allow transparency in the dropdown
            // (not used in this instance, but likely to be required in future)
            if (ieVersion >= 5.5 && ieVersion < 7) {
                shim.style.filter =
                'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0,' +
                'sizingMethod="crop")';
            }

            // Set the z-indices of the relevant elements so they stack
            // correctly.
            groupnav.style.zIndex = Z_INDEX.BASE_VALUE;
            dropdown.style.zIndex = Z_INDEX.BASE_VALUE;
            shim.style.zIndex     = Z_INDEX.BASE_VALUE - 1;

            // Insert the iframe shim into the DOM
            container.appendChild(shim);
        }

        // method [static] removeShim.
        // desc   Remove the created iframe, the first iframe attached to the
        //        element.
        //param  [HTMLElement] element.
        function removeShim(element) {
            var iframe;

            if (element && element.getElementsByTagName('iframe')[0]) {
                iframe = element.getElementsByTagName('iframe')[0];
                element.removeChild(iframe);
            }
        }

        // Removes the display style attribute so that the dropdown is shown
        function show() {
            dropdown.style.display = '';
            trigger.className = CLASS.CONTRACTED;
            createShim();
        }

        // Sets the display style attribute to 'none' so that the dropdown is
        // hidden
        function hide() {
            if (visible()) {
                dropdown.style.display = 'none';
                trigger.className = '';
                removeShim(container);
            }
        }

        // Toggles the style display attribute of the dropdown
        function toggle() {
            if (visible()) {
                hide();
            }
            else {
                show();
            }
        }

        // Returns true if the dropdown is visible
        function visible() {
            return !(dropdown.style.display === 'none');
        }

        // document onclick handler for hiding the dropdown
        function documentOnclick(e) {
            // Hide if dropdown is visible and the click occured anywhere
            // except on the trigger.
            var target = window.event ? window.event.srcElement : e.target;
            if (visible() && target !== trigger) {
                hide();
            }
        }

        // Toggle display of the dropdown onclick
        trigger.onclick = function () {
            toggle();
            return false;
        };

        // Add the document onclick handler
        if (document.onclick) {
            oldOnclick = document.onclick; // Be nice to others
            document.onclick = function (e) {
                oldOnclick(e);
                documentOnclick(e);
            };
        }
        else {
            document.onclick = documentOnclick;
        }
    }
};

//class  RUI.Ticker
//desc   A replacement for the oh-so-lovely <marquee> tag.
RUI.Ticker = RUI.Class.create();

RUI.Ticker.prototype = {
    //method initialize
    //desc   Constructor.
    //param  [req] contents [String or HTMLElement]
    //param  [opt] speed: [Number] pixels per second
    //param  [opt] step: [Number] milliseconds between frames
    //param  [opt] container: [String or HTMLElement]
    //note   A container must be specified if the contents is not an id or
    //       HMTLElement.
    initialize: function (contents, options) {
        var defaults = {
            speed    : 60,
            step     : 100,
            container: null
        };
        this.options = RUI.Object.extend(defaults, options);

        // Try fetching the HTMLElement from the DOM
        var element = RUI.$(contents);
        contents = element || contents;
        // Grab the innerHTML or default to a string of HTML
        var html = contents.innerHTML || contents;

        // The container is the contents unless a container has been specified
        var container = RUI.$(this.options.container) || element;

        if (element && this.options.container) {
            // TODO: Refactor to RUI.Element.remove
            element.parentNode.removeChild(element);
        }

        RUI.Object.extend(container.style, {
            overflow: 'hidden',
            position: 'relative'
        });

        var ticker = document.createElement('span');
        ticker.innerHTML = html;
        // TODO: Refactor to HTMLElement#setStyle
        ticker.style.whiteSpace = 'nowrap';

        container.innerHTML = '';

        // TODO: Refactor to HTMLElement#getWidth
        var containerWidth = container.offsetWidth;

        container.appendChild(ticker);

        // TODO: Refactor to HTMLElement#getWidth
        var tickerWidth = ticker.offsetWidth;

        // TODO: Refactor the HTMLElement#setStyle
        container.style.height = container.offsetHeight + 'px';

        // Achieve the smoothest animation by absolutely positioning the
        // ticker.  This reduces the redraw burden on the browser.
        // TODO: Refactor to HTMLElement#setStyle
        ticker.style.position = 'absolute';

        // TODO: Refactor to PeriodicalExecutor
        // TODO: Refactor this to register the animation with a single timer for
        // the entire page.  Probably in something like RUI.Animation or
        // RUI.Effect.
        var timer    = 0;
        var position = 0;
        var step     = this.options.step;
        var speed    = this.options.speed; // pixels per second
        var interval;

        function start() {
            interval = setInterval(function () {
                timer += step;
                position = containerWidth - (speed * timer / 1000);
                if (position < -tickerWidth) {
                    position = containerWidth;
                    timer    = 0;
                }
                ticker.style.left = parseInt(position, 10) + 'px';
            }, step);
        }

        function stop() {
            clearInterval(interval);
        }

        start();

        // TODO: Refactor to HTMLElement#observe
        addEvent(container, 'mouseover', stop);
        addEvent(container, 'mouseout', start);
    }
};

// A singleton class to hold globals
RUI.Globals = RUI.Class.create();

// Constants and static methods
Object.extend(RUI.Globals, {
    // Returns a singleton instance
    instance: function () {
        if (!RUI.Globals.singleton) {
            RUI.Globals.singleton = new RUI.Globals();
        }

        return RUI.Globals.singleton;
    },

    singleton: null
});

// Instance methods
RUI.Globals.prototype = {
    initialize: function () {
        this.attributes = {};
    },

    setAttribute: function (attribute, value) {
        this.attributes[attribute] = value;
    },

    getAttribute: function (attribute) {
        return this.attributes[attribute];
    }
};

//desc   Fixes PNG transparency in IE (for example in the coBrand map).
//param  [req] id [String] ID of the element to patch.
RUI.PngMonkeyPatch = function (id) {
    // Exit early unless we need to patch (IE 5.5-6.0)
    var ieVersion = parseFloat(navigator.appVersion.split('MSIE')[1]);
    if (! ((ieVersion >= 5.5 && ieVersion < 7) && document.body.filters)) {
        return;
    }

    var elementToFix = document.getElementById(id);

    if (!elementToFix) {
        return;
    }

    var src, newElement, parent, backgroundImage;

    if (elementToFix.src) {
        // Image element
        src = elementToFix.src;
        newElement = document.createElement('div');
        newElement.style.width = elementToFix.offsetWidth + 'px';
        newElement.style.height = elementToFix.offsetHeight + 'px';
        parent = elementToFix.parentNode;
        parent.insertBefore(newElement, elementToFix);
        parent.removeChild(elementToFix);
        elementToFix = newElement;
    }
    else {
        // Background image
        backgroundImage = elementToFix.currentStyle.backgroundImage;
        src = backgroundImage.substring(
            backgroundImage.indexOf('"') + 1,
            backgroundImage.lastIndexOf('"')
        );
        elementToFix.style.backgroundImage = 'none';
    }
    elementToFix.style.filter = 'progid:DXImageTransform.'
        + 'Microsoft.AlphaImageLoader(src="' + src
        + '", sizingMethod="crop")';
};

//desc   A class to show/hide content
RUI.ContentSwitch = RUI.Class.create();

RUI.Object.extend(RUI.ContentSwitch, {
    CLASS: {
        TRIGGER : 'trigger',

        MINUS   : 'minus',
        PLUS    : 'plus'
    }
});

RUI.ContentSwitch.prototype = {
    //method initialize
    //desc   Constructor.
    //note   The content can be defined explicitly as an argument.
    //eg     Either:
    //
    //       <a href="/path/with/an/anchor#theContent" id="theTrigger">
    //          The Trigger
    //       </a>
    //       <div id="theContent">
    //          <a name="theContent"></a>
    //          The content to control
    //       </div>
    //       <script type="text/javascript">
    //         //<![CDATA[
    //         (new RUI.ContentSwitch('theTrigger'));
    //         //]]>
    //       </script>
    //
    //       or:
    //
    //       <a href="/path/without/an/anchor" id="theTrigger">The Trigger</a>
    //       <div id="theContent">The content to control</div>
    //       <script type="text/javascript">
    //         //<![CDATA[
    //         (new RUI.ContentSwitch('theTrigger', {
    //             content: 'theContent'
    //         }));
    //         //]]>
    //       </script>
    //param  [req] trigger [String] trigger anchor ID
    //param  [req] options [Hashref] containing {content: <content object ID>}
    initialize: function (trigger, options) {
        this.trigger = RUI.$(trigger);

        this._setOptions(options);

        if (this.options.content) {
            this.content = RUI.$(this.options.content);
        }

        // Bail out now if no trigger or content is found.
        if (! this.trigger || ! this.content) {
            return;
        }

        // Bind the this keyword now so that stopObserving can be passed the
        // function reference later on (it won't work otherwise)
        this.toggle = this.toggle.bindAsEventListener(this);

        RUI.Event.observe(this.trigger, 'click', this.toggle);
    },

    //method [private] _setOptions
    //desc   Sets default options and assigns named constructor arguments to
    //       this.options.
    //param  [opt] options [Object] See initialize method for details.
    _setOptions: function (options) {
        this.options = {};

        RUI.Object.extend(this.options, options || {});
    },

    //method show
    //desc   Shows the content.
    //param  [opt] event
    show: function (e) {
        this.removeClassName(this.trigger, RUI.ContentSwitch.CLASS.PLUS);
        this.addClassName(this.trigger, RUI.ContentSwitch.CLASS.MINUS);
        this.content.style.display = '';
        if (e) {
            RUI.Event.stop(e);
        }
    },

    //method hide
    //desc   Hides the content.
    //param  [opt] event
    hide: function (e) {
        this.removeClassName(this.trigger, RUI.ContentSwitch.CLASS.MINUS);
        this.addClassName(this.trigger, RUI.ContentSwitch.CLASS.PLUS);
        this.content.style.display = 'none';
        if (e) {
            RUI.Event.stop(e);
        }
    },

    //method toggle
    //desc   Toggles the display of the content.
    //param  [opt] event
    toggle: function (e) {
        if (this.content.style.display === 'none') {
            this.show(e);
        }
        else {
            this.hide(e);
        }
    },

    // TODO: Add READoc
    addClassName: function (element, className) {
        element = RUI.$(element);
        RUI.Element.removeClassName(element, className);
        element.className += ' ' + className;
    },

    // TODO: Add READoc
    removeClassName: function (element, className) {
        element = RUI.$(element);

        if (!element) {
            return;
        }

        var newClassName = '';
        var a = element.className.split(' ');
        for (var i = 0; i < a.length; i++) {
            if (a[i] !== className) {
                if (i > 0) {
                    newClassName += ' ';
                }

                newClassName += a[i];
            }
        }
        element.className = newClassName;
    }
};

//desc   A class to write container html for Accipter served ad content
RUI.Ad = {
    // Accipiter protocol constants
    ACCIPITER_PROTOCOL: {
        BSERVER: 'bserver',
        HSERVER: 'hserver',
        JSERVER: 'jserver'
    },

    //method [static] getPageNumber
    //desc   Returns a singleton random page number.  This number will remain
    //       constant over the page load.
    //return [Number] singleton random number
    getPageNumber: function () {
        // 10 digit random number singleton
        this.pageNumber = this.pageNumber
            || Math.round(Math.random() * 10000000000);

        return this.pageNumber;
    },

    //method [static] writeAdHTML
    //desc   Writes an ad tag into the page.
    //param  [req] tag [String] Accipiter ad tag
    //param  [opt] width: [String or Number] width of ad in pixels
    //param  [opt] height: [String or Number] height of ad in pixels
    //param  [opt] id: [HTMLElement or String] ad container element
    //param  [opt] adServer: [String] Accipiter server URL, including protocol
    //       but excluding the trailing slash.
    //param  [opt] accipiterProtocol: [String] Accipiter protocol to use.  One
    //       of 'bserver', 'hserver' or 'jserver'.
    writeAdHTML: function (tag, options) {
        // Default options
        var defaults = {
            width            : null,
            height           : null,
            id               : null,
            adServer         : 'http://info.realestate.com.au',
            accipiterProtocol: RUI.Ad.ACCIPITER_PROTOCOL.HSERVER
        };
        options = RUI.Object.extend(defaults, options);

        if (RUI.$(options.id)) {
            return; // Ad already rendered
        }

        var random = Math.round(Math.random() * 10000000000);
        var pageNum = RUI.Ad.getPageNumber();

        var target, idWrite, width, height, adServer, iFrameWrite, srcWrite;

        if (options.accipiterProtocol === RUI.Ad.ACCIPITER_PROTOCOL.HSERVER) {
            target = '/' + tag;
            idWrite = ' id="iframe' + random
                + '" name="iframe' + random + '" ';
            width    = options.width;
            height   = options.height;
            adServer = options.adServer;
            iFrameWrite = '<iframe ' + idWrite + ' src="' + adServer
                + '/hserver/acc_random=' + random + target + '/pageid='
                + pageNum + '" scrolling="no" ' + 'frameborder="0" '
                + 'marginheight="0" marginwidth="0" height="' + height
                + 'px" width="' + width + 'px" allowTransparency="true" >'
                + '<scr' + 'ipt src=\"' + adServer + '/jnserver/acc_random='
                + random + target + '/pageid=' + pageNum + '\">' + '</scr'
                + 'ipt>' + '</iframe>';
            document.write(iFrameWrite);
        }
        else if (
            options.accipiterProtocol === RUI.Ad.ACCIPITER_PROTOCOL.JSERVER
        ) {
            scrWrite = '<scr' + 'ipt src=\"' + options.adServer
                + '/jserver/acc_random=' + random + '/' + tag + '/pageid='
                + pageNum + '\">' + '</script>';
            document.write(scrWrite);
        }
        else if (
            options.accipiterProtocol === RUI.Ad.ACCIPITER_PROTOCOL.BSERVER
        ) {
            // TODO: Implement bserver
        }
    }
};

