/** 
 * @fileoverview This file contains functions and vars to extend the document object.
 * NOTE: Global functions can also reside here.
 * @author Iain White iain.white@aotgroup.com.au
 * @version 4.0
 */

/**
 * Sniffer - Construct a new Sniffer object.
 * @class This is the basic Sniffer class.
 * Detect browser version, OS and other stuff
 * @constructor
 * @returns A new Sniffer
 */
function Sniffer()
{

    this.agt = navigator.userAgent.toLowerCase();
    this.appVer = navigator.appVersion.toLowerCase();

    this.is_minor = parseFloat(this.appVer);
    this.is_major = parseInt(this.is_minor);

    this.is_opera = (this.agt.indexOf("opera") != -1);
    this.is_opera2 = (this.agt.indexOf("opera 2") != -1 || this.agt.indexOf("opera/2") != -1);
    this.is_opera3 = (this.agt.indexOf("opera 3") != -1 || this.agt.indexOf("opera/3") != -1);
    this.is_opera4 = (this.agt.indexOf("opera 4") != -1 || this.agt.indexOf("opera/4") != -1);
    this.is_opera5 = (this.agt.indexOf("opera 5") != -1 || this.agt.indexOf("opera/5") != -1);
    this.is_opera6 = (this.agt.indexOf("opera 6") != -1 || this.agt.indexOf("opera/6") != -1);
    this.is_opera7 = (this.agt.indexOf("opera 7") != -1 || this.agt.indexOf("opera/7") != -1);
    this.is_opera8 = (this.agt.indexOf("opera 8") != -1 || this.agt.indexOf("opera/8") != -1);
    this.is_opera9 = (this.agt.indexOf("opera 9") != -1 || this.agt.indexOf("opera/9") != -1);
    this.is_opera5up = (this.is_opera && !this.is_opera2 && !this.is_opera3 && !this.is_opera4);
    this.is_opera6up = (this.is_opera && !this.is_opera2 && !this.is_opera3 && !this.is_opera4 && !this.is_opera5);
    this.is_opera7up = (this.is_opera && !this.is_opera2 && !this.is_opera3 && !this.is_opera4 && !this.is_opera5 && !this.is_opera6);
    this.is_opera8up = (this.is_opera && !this.is_opera2 && !this.is_opera3 && !this.is_opera4 && !this.is_opera5 && !this.is_opera6  && !this.is_opera7);
    this.is_opera9up = (this.is_opera && !this.is_opera2 && !this.is_opera3 && !this.is_opera4 && !this.is_opera5 && !this.is_opera6  && !this.is_opera7 && !this.is_opera8);

    // On IE, appVersion return 3 or 4 which is the version of Netscape it is compatible with.
    // On Mac IE5+ use is_minor in the ua; since it appears to be more accurate than appVersion.
    this.is_mac = (this.agt.indexOf("mac") != -1);
    var iePos  = this.appVer.indexOf('msie');
    if (iePos !=-1) {
        if (this.is_mac) {
            var iePos = this.agt.indexOf('msie');
            this.is_minor = parseFloat(this.agt.substring(iePos + 5, this.agt.indexOf(';', iePos)));
        } else {
            this.is_minor = parseFloat(this.appVer.substring(iePos + 5, this.appVer.indexOf(';', iePos)));
        }
        this.is_major = parseInt(this.is_minor);
    }

    // Konqueror
    this.is_konq = false;
    var kqPos = this.agt.indexOf('konqueror');
    if (kqPos !=-1) {
        this.is_konq  = true;
        this.is_minor = parseFloat(this.agt.substring(kqPos + 10, this.agt.indexOf(';', kqPos)));
        this.is_major = parseInt(this.is_minor);
    }

    // DOM  
    this.is_getElementById = (document.getElementById) ? "true" : "false";
    this.is_getElementsByTagName = (document.getElementsByTagName) ? "true" : "false";
    this.is_documentElement = (document.documentElement) ? "true" : "false";

    this.is_safari = ((this.agt.indexOf('safari') != -1) && (this.agt.indexOf('mac') != -1)) ? true : false;
    this.is_khtml  = (this.is_safari || this.is_konq);
    this.is_gecko = ((!this.is_khtml) && (navigator.product) && (navigator.product.toLowerCase() == "gecko")) ? true : false;
    
    if (this.is_safari) {
        this.safari_ver = this.agt.substr((str_pos + 7), 5);
    }
    
    this.is_gver = 0;
    if (this.is_gecko) {
        this.is_gver = navigator.productSub;
    }
    this.is_moz = ((this.agt.indexOf('mozilla/5') != -1) && (this.agt.indexOf('spoofer') == -1) && (this.agt.indexOf('compatible') == -1) && (this.agt.indexOf('opera') == -1) && (this.agt.indexOf('webtv') == -1) && (this.agt.indexOf('hotjava') == -1) && (this.is_gecko) && ((navigator.vendor == "") || (navigator.vendor == "Mozilla") || (navigator.vendor == "Debian")));
    this.is_fb = ((this.agt.indexOf('mozilla/5') != -1) && (this.agt.indexOf('spoofer') == -1) && (this.agt.indexOf('compatible') == -1) && (this.agt.indexOf('opera') == -1) && (this.agt.indexOf('webtv') == -1) && (this.agt.indexOf('hotjava') == -1) && (this.is_gecko) && (navigator.vendor == "Firebird"));
    this.is_phoenix = ((this.agt.indexOf('mozilla/5') != -1) && (this.agt.indexOf('spoofer') == -1) && (this.agt.indexOf('compatible') == -1) && (this.agt.indexOf('opera') == -1) && (this.agt.indexOf('webtv') == -1) && (this.agt.indexOf('hotjava') == -1) && (this.is_gecko) && (navigator.vendor == "Phoenix"));
    this.is_fx = ((this.agt.indexOf('mozilla/5') != -1) && (this.agt.indexOf('spoofer') == -1) && (this.agt.indexOf('compatible') == -1) && (this.agt.indexOf('opera') == -1) && (this.agt.indexOf('webtv') == -1) && (this.agt.indexOf('hotjava') == -1) && (this.is_gecko) && (navigator.vendor == "Firefox"));
    if (!this.is_fx) {
        this.is_fx = ((this.agt.indexOf('firefox') != -1) && (this.agt.indexOf('mozilla/5') != -1) && (this.agt.indexOf('spoofer') == -1) && (this.agt.indexOf('compatible') == -1) && (this.agt.indexOf('opera') == -1) && (this.agt.indexOf('webtv') == -1) && (this.agt.indexOf('hotjava') == -1) && (this.is_gecko));
    }
    if ((this.is_moz) || (this.is_fb) || (this.is_fx) || (this.is_phoenix)) {
        this.is_moz_ver = (navigator.vendorSub) ? navigator.vendorSub : 0;
        if (!(this.is_moz_ver)) {
            this.is_moz_ver = this.agt.indexOf('rv:');
            this.is_moz_ver = this.agt.substring(this.is_moz_ver + 3);
            this.is_paren = this.is_moz_ver.indexOf(')');
            this.is_moz_ver = this.is_moz_ver.substring(0, this.is_paren);
        }
        this.is_minor = this.is_moz_ver;
        this.is_major = parseInt(this.is_moz_ver);
    }
    this.is_fb_ver = this.is_moz_ver;
    this.is_fx_ver = this.is_moz_ver;
    this.is_phoenix_ver = this.is_moz_ver;

    if (this.is_fx) {
        pattern = /[(); \n]/;
        rv_pos = this.agt.indexOf('rv');
        rv_full = this.agt.substr(rv_pos + 3, 6);
        rv_slice = (rv_full.search(pattern) != -1) ? rv_full.search(pattern) : '';
        (rv_slice) ? rv_full = rv_full.substr(0, rv_slice) : '';
        nu = rv_full.substr(0, 3);
        str_pos = this.agt.indexOf('firefox');
        moz_brow_nu = this.agt.substr((str_pos + 7 + 1 ) , 3);
        moz_brow_nu = (isNaN(moz_brow_nu)) ? moz_brow_nu = nu : moz_brow_nu;
        moz_brow_nu_sub = this.agt.substr((str_pos + 7 + 1), 8);
        sub_nu_slice = (moz_brow_nu_sub.search(pattern) != -1 ) ? moz_brow_nu_sub.search(pattern) : '';
        (sub_nu_slice) ? moz_brow_nu_sub = moz_brow_nu_sub.substr(0, sub_nu_slice) : '';
        this.is_fx_ver = moz_brow_nu_sub;
        this.is_minor = this.is_fx_ver;
        this.is_major = parseInt(this.is_fx_ver);
    }

    this.is_nav  = ((this.agt.indexOf('mozilla') != -1) && (this.agt.indexOf('spoofer') == -1) && (this.agt.indexOf('compatible') == -1) && (this.agt.indexOf('opera') == -1) && (this.agt.indexOf('webtv') == -1) && (this.agt.indexOf('hotjava') == -1) && (!this.is_khtml) && (!(this.is_moz)) && (!this.is_fb) && (!this.is_fx));

    // Netscape6 is mozilla/5 + Netscape6/6.0
    // Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20001108 Netscape6/6.0
    if ((navigator.vendor) && ((navigator.vendor == "Netscape6") || (navigator.vendor == "Netscape")) && (this.is_nav)) {
        this.is_major = parseInt(navigator.vendorSub);
        this.is_minor = parseFloat(navigator.vendorSub);
    }
    this.is_nav2 = (this.is_nav && (this.is_major == 2));
    this.is_nav3 = (this.is_nav && (this.is_major == 3));
    this.is_nav4 = (this.is_nav && (this.is_major == 4));
    this.is_nav4up = (this.is_nav && this.is_minor >= 4);
    this.is_navonly = (this.is_nav && ((this.agt.indexOf(";nav") != -1) || (this.agt.indexOf("; nav") != -1)) );
    this.is_nav6 = (this.is_nav && this.is_major == 6);
    this.is_nav6up = (this.is_nav && this.is_minor >= 6)
    this.is_nav5 = (this.is_nav && this.is_major == 5 && !this.is_nav6);
    this.is_nav5up = (this.is_nav && this.is_minor >= 5);
    this.is_nav7 = (this.is_nav && this.is_major == 7);
    this.is_nav7up = (this.is_nav && this.is_minor >= 7);
    this.is_nav8 = (this.is_nav && this.is_major == 8);
    this.is_nav8up = (this.is_nav && this.is_minor >= 8);
    this.is_ie = ((iePos != -1) && (!this.is_opera) && (!this.is_khtml));
    this.is_ie3 = (this.is_ie && (this.is_major < 4));
    this.is_ie4 = (this.is_ie && this.is_major == 4);
    this.is_ie4up = (this.is_ie && this.is_minor >= 4);
    this.is_ie5 = (this.is_ie && this.is_major == 5);
    this.is_ie5up = (this.is_ie && this.is_minor >= 5);
    this.is_ie5_5 = (this.is_ie && (this.agt.indexOf("msie 5.5") != -1));
    this.is_ie5_5up =(this.is_ie && this.is_minor >= 5.5);	
    this.is_ie6 = (this.is_ie && this.is_major == 6);
    this.is_ie6up = (this.is_ie && this.is_minor >= 6);
    this.is_ie7 = (this.is_ie && this.is_major == 7);
    this.is_ie7up = (this.is_ie && this.is_minor >= 7);

    // On AOL4, returns false if IE3 is embedded browser or if this is the first browser window opened.
    this.is_aol = (this.agt.indexOf("aol") != -1);
    this.is_aol3 = (this.is_aol && this.is_ie3);
    this.is_aol4 = (this.is_aol && this.is_ie4);
    this.is_aol5 = (this.agt.indexOf("aol 5") != -1);
    this.is_aol6 = (this.agt.indexOf("aol 6") != -1);
    this.is_aol7 = ((this.agt.indexOf("aol 7") != -1) || (this.agt.indexOf("aol7") != -1));
    this.is_aol8 = ((this.agt.indexOf("aol 8") != -1) || (this.agt.indexOf("aol8") != -1));
    this.is_webtv = (this.agt.indexOf("webtv") != -1);
    this.is_TVNavigator = ((this.agt.indexOf("navio") != -1) || (this.agt.indexOf("navio_aoltv") != -1));
    this.is_AOLTV = this.is_TVNavigator;
    this.is_hotjava = (this.agt.indexOf("hotjava") != -1);
    this.is_hotjava3 = (this.is_hotjava && (this.is_major == 3));
    this.is_hotjava3up = (this.is_hotjava && (this.is_major >= 3));

    // JavaScript Version
    this.is_js = 0;
    if (this.is_nav2 || this.is_ie3)
        this.is_js = 1.0;
    else if (this.is_nav3)
        this.is_js = 1.1;
    else if ((this.is_opera5) || (this.is_opera6))
        this.is_js = 1.3;
    else if (this.is_opera7up)
        this.is_js = 1.5;
    else if (this.is_khtml)
        this.is_js = 1.5;
    else if (this.is_opera)
        this.is_js = 1.1;
    else if ((this.is_nav4 && (this.is_minor <= 4.05)) || this.is_ie4)
        this.is_js = 1.2;
    else if ((this.is_nav4 && (this.is_minor > 4.05)) || this.is_ie5)
        this.is_js = 1.3;
    else if (this.is_nav5 && !(this.is_nav6))
        this.is_js = 1.4;
    else if (this.is_hotjava3up)
        this.is_js = 1.4;
    else if (this.is_nav6up)
        this.is_js = 1.5;
    // Future profing
    else if (this.is_nav && (this.is_major > 5))
        this.is_js = 1.4;
    else if (this.is_ie && (this.is_major > 5))
        this.is_js = 1.3;
    else if (this.is_moz)
        this.is_js = 1.5;
    else if (this.is_fb || this.is_fx)
        this.is_js = 1.5;
    else
        this.is_js = 0.0;
    // Fix for IE5 MAC 1.4
    if ((this.agt.indexOf("mac") != -1) && this.is_ie5up)
        this.is_js = 1.4;
    // Fix for Firefox 1.5
    if (this.is_fx && parseFloat(this.is_fx_ver) >= 1.5) {
        this.is_js = 1.6;
    }
    // Fix for Firefox 2
    if (this.is_fx && parseFloat(this.is_fx_ver) >= 2.0) {
        this.is_js = 1.7;
    }

    // Done with is_minor testing; revert to real for N6/7
    if (this.is_nav6up) {
        this.is_minor = navigator.vendorSub;
    }

    // Platform
    this.is_win = ((this.agt.indexOf("win") != -1) || (this.agt.indexOf("16bit") != -1) );
    // On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
    this.is_win95 = ((this.agt.indexOf("win95") != -1) || (this.agt.indexOf("windows 95") != -1));
    // A 16 bit compiled version?
    this.is_win16 = ((this.agt.indexOf("win16") != -1) || (this.agt.indexOf("16bit") != -1) || (this.agt.indexOf("windows 3.1") != -1) || (this.agt.indexOf("windows 16-bit") != -1));
    this.is_win31 = ((this.agt.indexOf("windows 3.1") != -1) || (this.agt.indexOf("win16") != -1) || (this.agt.indexOf("windows 16-bit") != -1));	
    this.is_winme = ((this.agt.indexOf("win 9x 4.90") != -1));
    this.is_win2k = ((this.agt.indexOf("windows nt 5.0") != -1) || (this.agt.indexOf("windows 2000") != -1));
    this.is_winxp = ((this.agt.indexOf("windows nt 5.1") != -1) || (this.agt.indexOf("windows xp") != -1));
    this.is_win2003 = ((this.agt.indexOf("windows nt 5.2") != -1) || (this.agt.indexOf("windows server 2003") != -1));
    this.is_winvista = ((this.agt.indexOf("windows nt 6.0") != -1) || (this.agt.indexOf("windows vista") != -1));

    if (this.is_winxp) {
        this.is_sp2 = (window.navigator.userAgent.indexOf("SV1") != -1);
    }

    // Reliable detection of Win98 may not be possible. It appears that:
    // On Nav 4.x and before you'll get plain "Windows" in userAgent.
    // On Mercury client, the 32-bit version will return "Win98", but the 16-bit version running on Win98 will still return "Win95".
    this.is_win98 = ((this.agt.indexOf("win98") != -1) || (this.agt.indexOf("windows 98") != -1));
    this.is_winnt = ((this.agt.indexOf("winnt") != -1) || (this.agt.indexOf("windows nt") != -1));
    this.is_win32 = (this.is_win95 || this.is_winnt || this.is_win98 || ((this.is_major >= 4) && (navigator.platform == "Win32")) || (this.agt.indexOf("win32") != -1) || (this.agt.indexOf("32bit") != -1));
    this.is_os2 = ((this.agt.indexOf("os/2") != -1) || (navigator.appVersion.indexOf("OS/2") != -1) || (this.agt.indexOf("ibm-webexplorer") != -1));
    this.is_mac = (this.agt.indexOf("mac") != -1);
    if (this.is_mac)
        this.is_win = !this.is_mac;
    this.is_mac68k = (this.is_mac && ((this.agt.indexOf("68k") != -1) || (this.agt.indexOf("68000") != -1)));
    this.is_macppc = (this.is_mac && ((this.agt.indexOf("ppc") != -1) || (this.agt.indexOf("powerpc") != -1)));
    this.is_sun = (this.agt.indexOf("sunos") != -1);
    this.is_sun4  = (this.agt.indexOf("sunos 4") != -1);
    this.is_sun5 = (this.agt.indexOf("sunos 5") != -1);
    this.is_suni86 = (this.is_sun && (this.agt.indexOf("i86") != -1));
    this.is_irix = (this.agt.indexOf("irix") !=-1);
    this.is_irix5 = (this.agt.indexOf("irix 5") !=-1);
    this.is_irix6 = ((this.agt.indexOf("irix 6") != -1) || (this.agt.indexOf("irix6") != -1));
    this.is_hpux = (this.agt.indexOf("hp-ux") != -1);
    this.is_hpux9 = (this.is_hpux && (this.agt.indexOf("09.") != -1));
    this.is_hpux10 = (this.is_hpux && (this.agt.indexOf("10.") != -1));
    this.is_aix = (this.agt.indexOf("aix") != -1);
    this.is_aix1 = (this.agt.indexOf("aix 1") != -1);
    this.is_aix2 = (this.agt.indexOf("aix 2") != -1);
    this.is_aix3 = (this.agt.indexOf("aix 3") != -1);
    this.is_aix4 = (this.agt.indexOf("aix 4") != -1);
    this.is_linux = (this.agt.indexOf("inux") != -1);
    this.is_sco = (this.agt.indexOf("sco") != -1) || (this.agt.indexOf("unix_sv") != -1);
    this.is_unixware = (this.agt.indexOf("unix_system_v") != -1);
    this.is_mpras = (this.agt.indexOf("ncr") != -1);
    this.is_reliant = (this.agt.indexOf("reliantunix") != -1);
    this.is_dec = ((this.agt.indexOf("dec") != -1) || (this.agt.indexOf("osf1") != -1) || (this.agt.indexOf("dec_alpha") != -1) || (this.agt.indexOf("alphaserver") != -1) || (this.agt.indexOf("ultrix") != -1) || (this.agt.indexOf("alphastation") != -1));
    this.is_sinix = (this.agt.indexOf("sinix") != -1);
    this.is_freebsd = (this.agt.indexOf("freebsd") != -1);
    this.is_bsd = (this.agt.indexOf("bsd") != -1);
    this.is_unix = ((this.agt.indexOf("x11") != -1) || this.is_sun || this.is_irix || this.is_hpux || this.is_sco || this.is_unixware || this.is_mpras || this.is_reliant || this.is_dec || this.is_sinix || this.is_aix || this.is_linux || this.is_bsd || this.is_freebsd);
    this.is_vms = ((this.agt.indexOf("vax") != -1) || (this.agt.indexOf("openvms") != -1));

    this.is_anchors = (document.anchors) ? "true" : "false";
    this.is_regexp = (window.RegExp) ? "true" : "false";
    this.is_option = (window.Option) ? "true" : "false";
    this.is_all = (document.all) ? "true" : "false";
    document.cookie = "cookies=true";
    this.is_cookie = (document.cookie) ? "true" : "false";
    this.is_images = (document.images) ? "true" : "false";
    this.is_layers = (document.layers) ? "true" : "false";
    this.is_forms = (document.forms) ? "true" : "false";
    this.is_links = (document.links) ? "true" : "false";
    this.is_frames = (window.frames) ? "true" : "false";
    this.is_screen = (window.screen) ? "true" : "false";
    
    // css compatibility mode
    this.is_campatibility_mode = document.compatMode ? document.compatMode : 'BackCompat';

    this.is_java = (navigator.javaEnabled());
}

// Create a Global instance of the sniffer
var sniffer = new Sniffer();

/**
 * JavaScript Manager
 * 
 * @param string application - name of application / site
 * @param string ver - application version number
 */
JSManager = function(application, ver)
{
    this.application = application;
    this.version = ver;
    this.defaultDir = "";
    this.includedJSArray = new Array();
    this.includedJSArray[0] = new Array();
    this.includedJSArray[0][0] = "Document.js";
    this.includedJSArray[0][1] = "AOT JavaScript Library";
    this.includedJSArray[0][2] = "1.0";
    this.includedJSArray[0][3] = true;
    this.includedJSArray[0][4] = false; 
    this.includedCSSArray = [];
}

/**
 * Set application name and versioon number
 * 
 * @param string application - name of application / site
 * @param string ver - application version number
 */
JSManager.prototype.setApplication = function(application, ver)
{
    this.application = application;
    this.version = ver;
}

/**
 * Get application name
 * 
 */
JSManager.prototype.getApplicationName = function()
{
    return this.application;
}

/**
 * Get application versioon number
 * 
 */
JSManager.prototype.getApplicationVersion = function()
{
    return this.version;
}

/**
 * Record a files name and version number
 * 
 * @param string filename - file name
 * @param string module - module name
 * @param string ver - module version number
 */
JSManager.prototype.addVersion = function(filename, module, ver)
{
    var added = false;
	for (var i = 0; i < this.includedJSArray.length; i++) {
        if (this.includedJSArray[i][0] == filename) {
            this.includedJSArray[i][1] = module;
            this.includedJSArray[i][2] = ver;
            added = true;
		}
    }
	if (!added) {
        var newRecord = this.includedJSArray.length;
        this.includedJSArray[newRecord] = new Array();
        this.includedJSArray[newRecord][0] = filename;
        this.includedJSArray[newRecord][1] = module;
        this.includedJSArray[newRecord][2] = ver;
        this.includedJSArray[newRecord][3] = false;
        this.includedJSArray[newRecord][4] = true; 
	}
}

/**
 * Det module versioon number
 * 
 * @param string elName - file name / module name
 * @param string useModule - If true use module name
 */
JSManager.prototype.getVersion = function(elName, usemodule)
{
    var aEl = usemodule ? 1 : 0;
    for (var i = 0; i < this.includedJSArray.length; i++) {
        if (this.includedJSArray[i][aEl] == elName) {
            return this.includedJSArray[i][2];
        }
    }
}

/**
 * Get module name
 * 
 * @param string filename - file name
 */
JSManager.prototype.getmodule = function(filename)
{
    for (var i = 0; i < this.includedJSArray.length; i++) {
        if (this.includedJSArray[i][0] == filename) {
            return this.includedJSArray[i][1];
        }
    }
}

/**
 * Alert box with all loaded modules and version numbers
 * 
 */
JSManager.prototype.doAlertVersions = function()
{
    str = "Version Dump:\n\n";
    for (var i = 0; i < this.includedJSArray.length; i++) {
	    str += this.includedJSArray[i][1] + ' ' + this.includedJSArray[i][2] + '\n';
    }
    alert(str);
}


/**
 * Alert box with all loaded module and version numbers that can be called externialy
 * 
 */
JSManager.prototype.doAOTHelp = function(e)
{
    var evt = e ? e:event;
    var shiftPressed = evt.shiftKey;
    var altPressed = evt.altKey;
    var ctrlPressed = evt.ctrlKey;
    
    if (typeof(evt) == 'string') {
        if (evt == "1") {
            shiftPressed = false;
            altPressed = false;
            ctrlPressed = true;
        }
    }
    
    if (ctrlPressed && !shiftPressed & !altPressed) {
        var str = "Version Dump:\n\n";
        for (var i = 0; i < JSLib.includedJSArray.length; i++) {
	        str += JSLib.includedJSArray[i][1] + ' ' + JSLib.includedJSArray[i][2] + '\n';
        }
        alert(str);
        return false;
    }

    if (shiftPressed && ctrlPressed && !altPressed) {
        var str = "Event and Layer Information:\n\n";
        
        var pSize = getPageSize();
        var spSize = getPagePosScroll(false);
        var spSize2 = getPagePosScroll(true);
        str += "Page size = " + pSize[0] + " x " + pSize[1] + ", Scroll = " + spSize[0] + " x " + spSize[1] + " (" + spSize2[0] + " x " + spSize2[1] + ")\n\n";
        if (window.globPathPrefix) {
            str += "Global Path Prefix is " + globPathPrefix + "\n";
        }
        if (window.AjaxRequest) {
            str += "AJAX Transport: ";
            if (AjaxRequest.NotSupported) {
                str += "Not supported.\n";
            } else {            
                if (AjaxRequest.NativeSupport) {
                    str += "Native support.\n";
                } else {
                    str += "Supported.\n";
                    if (AjaxRequest.xmlHttpRequestVersion) {
                        str += "   XMLHTTP = " + AjaxRequest.xmlHttpRequestVersion + '\n';
                    }
                }
                str += "Number AjaxRequests " + AjaxRequest.numActiveAjaxRequests;
                str += " / " + AjaxRequest.numAjaxRequests + '\n';
            }
            str += '\n';
        }
        str += "onMouseMove handlers = " + document.onMouseMoveHandlers.length + '\n';
        str += "onClick handlers = " + document.onClickHandlers.length + '\n';
        str += "onClick active handlers = " + document.onClickHandlersActive.length + '\n';
        str += "onKeyUp handlers = " + document.onKeyUpHandlers.length + '\n';
        if (window.DhtmlLayer_layers) {
            str += "\n";
            str += "DHTML Layers = " + DhtmlLayer_layers.length + '\n';
            for (var i = 0; i < DhtmlLayer_layers.length; i++) {
                obj = DhtmlLayer_layers[i];
                str += "    " + obj.layerID + ' ';
                if (obj.isVisible()) {
                    str += "Visible";
                } else {
                    str += "Hidden";
                }
                pos = Position.get(obj.getLayer());
                str += ", L = " + pos.left;
                str += ", T = " + pos.top;
                str += ", W = " + pos.width;
                str += ", H = " + pos.height;             
                str += ", Class = " + obj.cssClass;
                str += '\n';
            }
        }

        if (location.search) {
            str += "\nQuery:\n";
            query = location.search.substring(1);
            pairs = query.split("&");
            for (i = 0; i < pairs.length; i++) {
                key = pairs[i].split("=")[0];
                value = pairs[i].split("=")[1];
                str += "   " + key + " = " + value + "\n";
            }
        }

        if (window.PRELOADED_IMAGES) {
            str += "\nPreloaded Images:\n";
            str += "  Images loaded " + PRELOADED_IMAGES.numImagesLoaded + " of " + PRELOADED_IMAGES.numImagesToLoad + "\n";
            if (PRELOADED_IMAGES.numErrors > 0) {
                str += "  " + PRELOADED_IMAGES.numErrors + " errors:\n";
                for (var i = 0; i < PRELOADED_IMAGES.numErrors; i++) {
                    var url = PRELOADED_IMAGES.errorArray[i];
                    var parsedURL = parseURL(url);
                    var filename = parsedURL.path + parsedURL.file;
                    str += "    " + filename + "\n";
                }
            }
        }
        
        alert(str);
        return false;
    } 
    return true;
}


/**
 * Return HTML formated loaded modules and version numbers
 * 
 */
JSManager.prototype.showVersions = function()
{
    str = "<div class='JSVersions'>";
    str += "<h2 class='JSVersionHeader'>Version Numbers</h2>";
    for (var i = 0; i < this.includedJSArray.length; i++) {
	    str += "<p class='JSPara'><b class='JSModule'>" + this.includedJSArray[i][1] + "</b> <span class='JSVersion'>" + this.includedJSArray[i][2] + '</span></p>';
    }
    str += "</div>";
    return str;
}

/**
 * Flag a file as loaded
 * 
 * @param string filename - file name
 */
JSManager.prototype.setLoaded = function(filename)
{
    for (var i = 0; i <  this.includedJSArray.length; i++) {
        if (this.includedJSArray[i][0] == filename) {
            this.includedJSArray[i][3] = true;
        }
    }    
}

/**
 * test if file is loaded
 * 
 * @param string filename = file name
 */
JSManager.prototype.isLoaded = function(filename)
{
    for (var i = 0; i <  this.includedJSArray.length; i++) {
        if (this.includedJSArray[i][0] == filename) {
            return this.includedJSArray[i][3];
        }
    }
    return false;  
}

/**
 * Check if file has already been included
 * 
 * @param string filename - file name
 */
JSManager.prototype.isIncluded = function(filename)
{
    for (var i = 0; i <  this.includedJSArray.length; i++) {
        if (this.includedJSArray[i][0] == filename) {
            return true;
        }
    }
    return false;    
}

/**
 * Check if all files have loaded
 * 
 */
JSManager.prototype.isAllLoaded = function()
{
    for (var i = 0; i <  this.includedJSArray.length; i++) {
        if (this.includedJSArray[i][3] == false) {
            return false;
        }
    }
    return true;
}

/**
 * Execute function only after file has loaded
 * 
 * @param string filename - file name
 * @param function fn - function to call
 */
JSManager.prototype.waitForLoaded = function(filename, fn)
{
    if (!this.isLoaded(filename)) {
        var callwrapper = new CCallWrapper(this, 10, 'waitForLoaded', filename, fn);
        CCallWrapper.asyncExecute(callwrapper);
    } else {
        fn();
    }
}

/**
 * Execute function only after all files have loaded
 * 
 * @param function fn - function to call
 */
JSManager.prototype.waitForAllLoaded = function(fn)
{
    if (!this.isAllLoaded()) {
        var callwrapper = new CCallWrapper(this, 10, 'waitForAllLoaded', fn);
        CCallWrapper.asyncExecute(callwrapper);
    } else {
        fn();
    }
}

/**
 * Include JavaScript file using DOM
 * 
 * @param string script_filename - file name
 * @param string dir - directory
 */
JSManager.prototype.js_include_dom = function(script_filename, dir)
{
    dir = dir ? dir : "";
    if (dir.length != 0) {
        script_filename = dir + "/" + script_filename;
    } else {
        if (this.defaultDir.length != 0) {
            script_filename = this.defaultDir + "/" + script_filename;
        }
    }
    // Opera 6 claims to support createElement, but does not - so test for createTextNode
    // Opera 7 can not append a script tag
    var op7 = (navigator.userAgent.indexOf("Opera 7") != -1); 
    if (document.getElementsByTagName && document.createTextNode && !Sniffer.is_opera7) {   
        var html_doc = document.getElementsByTagName('head').item(0);
        var js = document.createElement('script');
        js.type = "text/javascript";
        js.src = script_filename;
        js.language = "javascript";
        if (!html_doc.appendChild(js)) {
            document.write('<script src="' + script_filename + '" type="text/javascript" language="JavaScript"></script>');
        }
    } else {    
        document.write('<script src="' + script_filename + '" type="text/javascript" language="JavaScript"></script>');
    }
    return false;
}

/**
 * Include style sheet file using DOM
 * 
 * @param string script_filename - file name
 * @param string dir - directory
 */
JSManager.prototype.css_include_dom = function(css_file, dir)
{
    dir = dir ? dir : "";
    if (dir.length != 0) {
        css_file = dir + "/" + css_file;
    } else {
        if (this.defaultDir.length != 0) {
            css_file = this.defaultDir + "/" + css_file;
        }
    }
    if (document.getElementsByTagName && document.createTextNode && !Sniffer.is_opera7) {
	    var html_doc = document.getElementsByTagName('head').item(0);
	    var css = document.createElement('link');
	    css.rel = "stylesheet";
	    css.type = "text/css";
	    css.href = css_file;
        if (!html_doc.appendChild(css)) {
            document.write('<link href="' + css_file + '" rel="stylesheet" type="text/css" />');
        }
	} else {
        document.write('<link href="' + css_file + '" rel="stylesheet" type="text/css" />');
    }
    return false;
}

/**
 * Include a file
 * 
 * @param string script_filename - file name
 * @param string dir - directory
 * @param string type - JS for JavaScript, CSS for style sheet
 */
JSManager.prototype.include = function(script_filename, dir, type)
{
    type = type ? type : "JS";
    if (type == "CSS") {
        if (!in_array(script_filename, this.includedCSSArray)) {
            this.includedCSSArray[this.includedCSSArray.length] = script_filename;
            this.css_include_dom(script_filename, dir);
        }
    } else {
        if (!in_array(script_filename, this.includedJSArray)) {
            var newRecord = this.includedJSArray.length;
            this.includedJSArray[newRecord] = new Array();
            this.includedJSArray[newRecord][0] = script_filename;
            this.includedJSArray[newRecord][1] = "Unknown";
            this.includedJSArray[newRecord][2] = "0.1a";
            this.includedJSArray[newRecord][3] = false;
            this.includedJSArray[newRecord][4] = false; 
            this.js_include_dom(script_filename, dir);
        }
    }
}

/**
 * Include once required files
 */
JSManager.prototype.required = function()
{
    for (var i = 0; i < arguments.length; i++) {    
        this.include(arguments[i]);
    }
}

/**
 * Set default directory for included files
 * 
 * @param string dir - directory
 */
JSManager.prototype.setDefaultDirectory = function(dir)
{
    this.defaultDir = dir;
}

/**
 * Return true if item is in array
 * 
 * @param string needle - what we ar looking for
 * @param array haystack - array to search
 */
function in_array(needle, haystack)
{
    for (var i = 0; i < haystack.length; i++) {
        if (haystack[i][0] == needle) return true;
    }
    return false;
}
  
// Create global reference
JSLib = new JSManager();

// Show version number as alert on F1
window.onhelp = JSLib.doAOTHelp;

/**
 * Timed call with parameters.
 * 
 * @param 
 */
function CCallWrapper(aObjectReference, aDelay, aMethodName, aArgument0, aArgument1, aArgument2, aArgument3, aArgument4, aArgument5, aArgument6, aArgument7, aArgument8, aArgument9)
{
    this.mId = 'CCallWrapper_' + (CCallWrapper.mCounter++);
    this.mObjectReference = aObjectReference;
    this.mDelay = aDelay;
    this.mTimerId = 0;
    this.mMethodName = aMethodName;
    this.mArgument0 = aArgument0;
    this.mArgument1 = aArgument1;
    this.mArgument2 = aArgument2;
    this.mArgument3 = aArgument3;
    this.mArgument4 = aArgument4;
    this.mArgument5 = aArgument5;
    this.mArgument6 = aArgument6;
    this.mArgument7 = aArgument7;
    this.mArgument8 = aArgument8;
    this.mArgument9 = aArgument9;
    CCallWrapper.mPendingCalls[this.mId] = this;
 }

CCallWrapper.prototype.execute = function()
{
    this.mObjectReference[this.mMethodName](this.mArgument0, this.mArgument1, this.mArgument2, this.mArgument3, this.mArgument4, this.mArgument5, this.mArgument6, this.mArgument7, this.mArgument8, this.mArgument9);
    delete CCallWrapper.mPendingCalls[this.mId];
}

CCallWrapper.prototype.cancel = function()
{
    clearTimeout(this.mTimerId);
    delete CCallWrapper.mPendingCalls[this.mId];
}

CCallWrapper.asyncExecute = function (/* CCallWrapper */ callwrapper)
{
    CCallWrapper.mPendingCalls[callwrapper.mId].mTimerId = setTimeout('CCallWrapper.mPendingCalls["' + callwrapper.mId + '"].execute()', callwrapper.mDelay);
}

CCallWrapper.mCounter = 0;
CCallWrapper.mPendingCalls = {};


/**
 * Execute a function after the page has loaded
 * e.g. addLoadListener(load1);
 * 
 * @param function fn
 */ 
function addLoadListener(fn) 
{ 
    if (typeof window.addEventListener != 'undefined') { 
        window.addEventListener('load', fn, false); 
    } 
    else if (typeof document.addEventListener != 'undefined') { 
        document.addEventListener('load', fn, false);
    } 
    else if (typeof window.attachEvent != 'undefined') { 
        window.attachEvent('onload', fn); 
    } 
    else { 
        var oldfn = window.onload; 
        if (typeof window.onload != 'function') { 
            window.onload = fn; 
        } 
        else { 
            window.onload = function() 
                { 
                oldfn(); 
                fn(); 
                }; 
        } 
    } 
}

/**
 * Variable Dump
 * 
 * @param mixed object - item to dump
 */
function vd(object)
{
    alert(var_dump(object));
}

/**
 * A better Variable Dump
 * 
 * @param mixed object - item to dump
 */
function var_dump(obj)
{
    if (typeof obj == "object") {
        return "Type: " + typeof(obj) + ((obj.constructor) ? "\nConstructor: " + obj.constructor : "") + "\nValue: " + obj;
    } else {
        return "Type: " + typeof(obj) + "\nValue: "+obj;
   }
}

/**
 * Variable Dumper class
 * 
 */
var Dumper = (function(){
	// "Private"
	var maxIterations = 1000;
	var maxDepth = -1; // Max depth that Dumper will traverse in object
	var iterations = 0;
	var indent = 1;
	var indentText = " ";
	var newline = "\n";
	var object = null; // Keeps track of the root object passed in
	var properties = null; // Holds properties of top-level object to traverse - others are ignored

	function args(a,index) {
		var myargs = new Array();
		for (var i=index; i<a.length; i++) {
			myargs[myargs.length] = a[i];
		}
		return myargs;
	}

	function pad(len) {
		var ret = "";
		for (var i=0; i<len; i++) {
			ret += indentText;
		}
		return ret;
	}

	function string(o) {
		var level = 1;
		var indentLevel = indent;
		var ret = "";
		if (arguments.length>1 && typeof(arguments[1])=="number") {
			level = arguments[1];
			indentLevel = arguments[2];
			if (o == object) {
				return "[original object]";
			}
		}
		else {
			iterations = 0;
			object = o;
			// If a list of properties are passed in
			if (arguments.length>1) {
				var list = arguments;
				var listIndex = 1;
				if (typeof(arguments[1])=="object") {
					list = arguments[1];
					listIndex = 0;
				}
				for (var i=listIndex; i<list.length; i++) {
					if (properties == null) { properties = new Object(); }
					properties[list[i]]=1;
				}
			}
		}
		if (iterations++>maxIterations) { return "[Max Iterations Reached]"; } // Just in case, so the script doesn't hang
		if (maxDepth != -1 && level > (maxDepth+1)) {
			return "...";
		}
		// undefined
		if (typeof(o)=="undefined") {
			return "[undefined]";
		}
		// NULL
		if (o==null) {
			return "[null]";
		}
		// DOM Object
		if (o==window) {
			return "[window]";
		}
		if (o==window.document) {
			return "[document]";
		}
		// FUNCTION
		if (typeof(o)=="function") {
			return "[function]";
		} 
		// BOOLEAN
		if (typeof(o)=="boolean") {
			return (o)?"true":"false";
		} 
		// STRING
		if (typeof(o)=="string") {
			return "'" + o + "'";
		} 
		// NUMBER	
		if (typeof(o)=="number") {
			return o;
		}
		if (typeof(o)=="object") {
			if (typeof(o.length)=="number" ) {
				// ARRAY
				if (maxDepth != -1 && level > maxDepth) {
					return "[ ... ]";
				}
				ret = "[";
				for (var i=0; i<o.length;i++) {
					if (i>0) {
						ret += "," + newline + pad(indentLevel);
					}
					else {
						ret += newline + pad(indentLevel);
					}
					ret += string(o[i],level+1,indentLevel-0+indent);
				}
				if (i > 0) {
					ret += newline + pad(indentLevel-indent);
				}
				ret += "]";
				return ret;
			}
			else {
				// OBJECT
				if (maxDepth != -1 && level > maxDepth) {
					return "{ ... }";
				}
				ret = "{";
				var count = 0;
				for (i in o) {
					if (o==object && properties!=null && properties[i]!=1) {
						// do nothing with this node
					}
					else {
						if (typeof(o[i]) != "unknown") {
							var processAttribute = true;
							// Check if this is a DOM object, and if so, if we have to limit properties to look at
							if (o.ownerDocument|| o.tagName || (o.nodeType && o.nodeName)) {
								processAttribute = false;
								if (i=="tagName" || i=="nodeName" || i=="nodeType" || i=="id" || i=="className") {
									processAttribute = true;
								}
							}
							if (processAttribute) {
								if (count++>0) {
									ret += "," + newline + pad(indentLevel);
								}
								else {
									ret += newline + pad(indentLevel);
								}
								ret += "'" + i + "' => " + string(o[i],level+1,indentLevel-0+i.length+6+indent);
							}
						}
					}
				}
				if (count > 0) {
					ret += newline + pad(indentLevel-indent);
				}
				ret += "}";
				return ret;
			}
		}
	}

	string.popup = function(o) {
		var w = window.open("about:blank");
		w.document.open();
		w.document.writeln("<HTML><BODY><PRE>");
		w.document.writeln(string(o,args(arguments,1)));
		w.document.writeln("</PRE></BODY></HTML>");
		w.document.close();
	};

	string.alert = function(o) {
		alert(string(o,args(arguments,1)));
	};

	string.write = function(o) {
		var argumentsIndex = 1;
		var d = document;
		if (arguments.length>1 && arguments[1]==window.document) {
			d = arguments[1];
			argumentsIndex = 2;
		}
		var temp = indentText;
		indentText = "&nbsp;";
		d.write(string(o,args(arguments,argumentsIndex)));
		indentText = temp;
	};
	
	string.setMaxIterations = function(i) {
		maxIterations = i;
	};
	
	string.setMaxDepth = function(i) {
		maxDepth = i;
	};
	
	return string;
})();


/**
 *  Popup window.
 * 
 * @param string url - The url to show in the popup window
 * @param integer width - (optional) The width in pixels
 * @param integer height - (optional) The height in pixels
 * @author stew@aot.com.au 2004-02-03
 */
function popUp(url) { 
    var width = arguments[1] ? arguments[1] : 455;
    var height = arguments[2] ? arguments[2] : 500;
    var scrollbars = arguments[3] == 'no' ? 'no' : 'yes';
    var popup = window.open(url, 'info','top=20,left=20,scrollbars=' + scrollbars + 
            ',width=' + width + ',height=' + height + ',resizable=yes');
    popup.focus();
    return false;
}

/**
 * Define undefined for older browsers
 * 
 */
var undefined;
function isUndefined(property)
{
    return (typeof property == 'undefined');
}

// Array.pop() - Remove the last element of an array and return it
if (isUndefined(Array.prototype.pop) == true) {
    Array.prototype.pop = function()
    {
        var lastItem = undefined;
        if (this.length > 0) {
            lastItem = this[this.length - 1];
            this.length--;
        }
        return lastItem;
    }
}

// Array.push() - Add an element to the end of an array
if (isUndefined(Array.prototype.push) == true) {
    Array.prototype.push = function()
    {
        var currentLength = this.length;
        for (var i = 0; i < arguments.length; i++) {
            this[currentLength + i] = arguments[i];
        }
        return this.length;
    }
}

// Array.splice() - Splice out and / or replace several elements of an array and return any deleted elements
if (isUndefined(Array.prototype.splice) == true)
  {
  Array.prototype.splice = function(start, deleteCount)
    {
  	if (deleteCount == null || deleteCount == '')
	  deleteCount = this.length - start;
  	// Create a temporary copy of the array
  	var tempArray = this.copy();
  	// Copy new elements into array (over-writing old entries)
  	for (var i = start; i < start + arguments.length - 2; i++)
	  {
  	  this[i] = arguments[i - start + 2];
  	  }
  	
  	// Copy old entries after the end of the splice back into array and return
  	for (var i = start + arguments.length - 2; i < this.length - deleteCount + arguments.length - 2; i++)
	  {
  	  this[i] = tempArray[i + deleteCount - arguments.length + 2];
  	  }
  	this.length = this.length - deleteCount + (arguments.length - 2);
  	return tempArray.slice(start, start + deleteCount);
    }
  }

// Array.copy() - Copy an array
if (isUndefined(Array.prototype.copy) == true)
  {
  Array.prototype.copy = function()
    {
  	var copy = new Array();
  	for (var i = 0; i < this.length; i++)
	  {
  	  copy[i] = this[i];
  	  }
  	return copy;
    }
  }  

/**
 * A call to get an element by its id.
 * All javascript should use this to ensure browser compatability.
 * 
 * @param string id - The id of the element.
 * @return DOMElement - 
 */
function getElementById(id)
{
    if (document.getElementById) {
        return document.getElementById(id);
    } 
    if (document.all) {
        return document.all(id);
    }
}

/**
 * Get element by class name
 * 
 * @param class name.
 * @param parent element
 * @param tag name
 * @param function to match
 */
function aotGetElementsByClassName(clsName, parentEle, tagName, fn)
{
    var found = new Array();
    var re = new RegExp('\\b' + clsName + '\\b', 'i');
    var list = aotGetElementsByTagName(tagName, parentEle);
    for (var i = 0; i < list.length; ++i) {
        if (list[i].className.search(re) != -1) {
            found[found.length] = list[i];
            if (fn) {
                fn(list[i]);
            }
        }
    }
    return found;
}

/**
 * Get element by tag name
 * 
 * @param tag name.
 * @param parent element
 */
function aotGetElementsByTagName(tagName, parentEle)
{
    var list = null;
    tagName = tagName || '*';
    parentEle = parentEle || document;
    if (sniffer.is_ie4 || sniffer.is_ie5) {
        if (tagName == '*') {
            list = parentEle.all;
        } else {
            list = parentEle.all.tags(tagName);
        }
    } else if (parentEle.getElementsByTagName) {
        list = parentEle.getElementsByTagName(tagName);
    }
    return list || new Array();
}

/**
 * Get element by attribute
 * 
 * @param tag name.
 * @param attribute
 * @param regular expression
 * @param function to match
 */
function aotGetElementsByAttribute(sTag, sAtt, sRE, fn)
{
    var a;
    var list;
    var found = new Array();
    var re = new RegExp(sRE, 'i');
    list = aotGetElementsByTagName(sTag);
    for (var i = 0; i < list.length; ++i) {
        a = list[i].getAttribute(sAtt);
        if (!a) {
            a = list[i][sAtt];
        }
        if (typeof(a) == 'string' && a.search(re) != -1) {
            found[found.length] = list[i];
            if (fn) {
                fn(list[i]);
            }
        }
    }
    return found;
}

// Use inplace of removeChild to prevent memory leeks
function discardElement(element)
{
    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(element);
    garbageBin.innerHTML = '';    
}

/*
 * The following code taken from: 
 *   http://www.mattkruse.com/javascript/validations/source.html
 * 
 * @param boolean val - possible number value to be tested.
 * @return boolen - Returns true if value contains a positive float value
 */
function isNumeric(val)
{
    return(parseFloat(val, 10) == (val * 1));
}

/**
 * javascript:turnOnHourglass() a simple function for ie5.5+ to have an hourglass cursor 
 * whilst waiting for the background page to begin loading
 * 
 */
function turnOnHourglass()
{
    document.body.style.cursor = "wait";
}

function turnOffHourglass()
{
    document.body.style.cursor = "default";
}

/**
 * Fill a select element with an array of supplied option objects.
 * 
 * Notes: 
 *  o If selected is not defined the first element is selected
 * 
 * @param DOMElement select - The select form element
 * @param array options - The array of new options
 * @param integer selected - (optional) The selected element
 */
setSelectOptions = function(select, options) {
    // The optional argument selected?
    var selected = arguments[2] ? arguments[2] : 0; //options.length-1;
    
    clearSelectOptions(select);
    i = 0;
    for (i = 0; i < options.length; i++) {
        select.options[i] = options[i];
        if (i == selected) {
          select.options[i].selected = true;
        }
    }
    
    return select;
}

/**
 * Clear a select element.
 * 
 * @param DOMElement select - The form select element
 * @note Thanks to http://simon.incutio.com/archive/2002/12/13/clearingASelectBox for this.
 */
clearSelectOptions = function(select) {
    select.options.length = 0;
}

/**
 * Submit a form once only, used for submitting a payment form.
 * Put a call to this function in an onSubmit event on a form.
 * 
 * @param DOMElement btn - 
 */
var wasSubmitted = false;
function submitOnce(btn)
{
    if (wasSubmitted == true) {
        alert("Request already submitted, please wait....");
     } else {
        btn.className = 'btn_disable';
        btn.blur();
        wasSubmitted = true;
     }
}

/**
 * Change the class name of an element in the HTML page.
 * 
 * @param id string - the id of the element
 * @param newClass string - The new css class name
 */
function changeClass(id, cssClass) {
    var identity = getElementById(id);
    if (identity) {
        identity.className = cssClass;
    }
}

/**
 * Change the class name of a group of elements using a form field.
 * 
 * @param object / string fld - form field or string containing comma seperated list of id, class name pairs
 */
function doChangeClasses(fld)
{
    if (fld && typeof fld == 'object') {
        argStr = fld.value;
    } else {
        argStr = fld;
    }
    argStr = argStr.replace(/\s+/g, ''); // Remove any spaces
    if (argStr.length == 0) {
        return;
    }
    var argArray = argStr.split(','); // Split into array
    for (var i = 0; i < argArray.length; i++) {
        // Only work on pairs
        if (i % 2 == 0) {
            // Missing param?
            if ((i + 1) != argArray.length) {
                // Chnage the class
                changeClass(argArray[i], argArray[i + 1]); 
            }
        }
    }
}

/**
 * Get position of mouse pointer
 * 
 * @param event e -
 */
function getMousePos(e)
{
    var docX = 0;
    var docY = 0;
    if (e) {
        if (typeof(e.pageX) == 'number') {
            docX = e.pageX;
            docY = e.pageY;
        } else {
            docX = e.clientX;
            docY = e.clientY;
        }
    } else {
        e = window.event;
        docX = e.clientX;
        docY = e.clientY;
        if (document.documentElement
                && (document.documentElement.scrollTop
                || document.documentElement.scrollLeft)) {
            docX += document.documentElement.scrollLeft;
            docY += document.documentElement.scrollTop;
        } else if (document.body
                && (document.body.scrollTop
                || document.body.scrollLeft)) {
            docX += document.body.scrollLeft;
            docY += document.body.scrollTop;
        }
    }
    return [docX, docY];
}

// Set default browser window size
document.winWidth = 800;
document.winHeight = 600;

// Get height of browser window
function getWindowHeight()
  {
  var myHeight = 0;
  if (typeof(window.innerHeight) == 'number')
    {
    // Non-IE
    myHeight = window.innerHeight;
    }
  else if (document.documentElement && document.documentElement.clientHeight)
    {
    // IE 6+ in 'standards compliant mode'
    myHeight = document.documentElement.clientHeight;
    }
  else if (document.body && document.body.clientHeight)
    {
    // IE 4 compatible
    myHeight = document.body.clientHeight;
    }
  return myHeight;
  }  


// get width of browser window
function getWindowWidth()
  {
  var myWidth = 0;
  if (typeof(window.innerWidth) == 'number')
    {
    // Non-IE
    myWidth = window.innerWidth;
    }
  else if (document.documentElement && document.documentElement.clientWidth)
    {
    // IE 6+ in 'standards compliant mode'
    myWidth = document.documentElement.clientWidth;
    }
  else if (document.body && document.body.clientWidth)
    {
    // IE 4 compatible
    myWidth = document.body.clientWidth;
    }
  return myWidth;
  }  
 
// Update browser window stored sizes
function storePageSize()
{ 
    document.winHeight = getWindowHeight();
    document.winWidth = getWindowWidth();
} 

// On page load and resize store browser window size
addLoadListener(storePageSize);
window.onresize = storePageSize;

// Get the page size
function getPageSize()
{
    var scrollWidth = document.winHeight;
    var scrollHeight = document.winWidth;
    var test1 = document.body.scrollHeight;
    var test2 = document.body.offsetHeight;
    if (test1 > test2) {    // All but Explorer Mac
	    scrollWidth = document.body.scrollWidth;
	    scrollHeight = document.body.scrollHeight;
    } else {                // Explorer Mac & Explorer 6 Strict, Mozilla and Safari
	    scrollWidth = document.body.offsetWidth;
	    scrollHeight = document.body.offsetHeight;
    }
    return [scrollWidth, scrollHeight];
}

// get the page position including scrolling
function getPagePosScroll(full)
{
    full = full ? full : false;
    var x;
    var y;
    if (self.pageYOffset)
        {
	    x = self.pageXOffset;
	    y = self.pageYOffset;
        }
    else if (document.documentElement && document.documentElement.scrollTop)
        {
	    x = document.documentElement.scrollLeft;
	    y = document.documentElement.scrollTop;
        }
    else if (document.body)
        {
	    x = document.body.scrollLeft;
	    y = document.body.scrollTop;
        }
    if (full) {
        x = x + document.winWidth;
        y = y + document.winHeight;
    }
    return [x, y];
}
 
// General event arrays
document.onMouseMoveHandlers = new Array();
document.onClickHandlers = new Array();
document.onClickHandlersActive = new Array();
document.onKeyUpHandlers = new Array();

document.KEY_LEFT = 37;
document.KEY_UP = 38;
document.KEY_RIGHT = 39;
document.KEY_DOWN = 40;
document.KEY_ENTER = 13;
document.KEY_TAB = 9;
document.KEY_DEL = 46;
document.KEY_BACKSPACE = 8;

/**
 * Stop the event from bubbling up to the browser level.
 * 
 */
document.stopBubble = function(e)
{
    if (!e) {
        e = window.event;
    }
    if (document.all) {
        window.event.cancelBubble = true;
        window.event.returnValue = false;
    } else if (e.preventDefault) {
        e.cancelBubble = true;
        e.stopPropagation();
        e.preventDefault();
    }
    return false;
}

/**
 * Mouse Move
 */
 
/**
 * Method to add a document mouseMove event handler.
 * 
 * @param string handler - A callback event handler.
 */
document.addOnMouseMoveHandler = function(handler)
{
    if (!document.isSetOnMouseMoveHandler(handler)) {
        document.onMouseMoveHandlers[document.onMouseMoveHandlers.length] = handler;
    }
}

/**
 * Has this function already been set?
 * 
 */
document.isSetOnMouseMoveHandler = function(handler)
{
    for (var i = 0; i < document.onMouseMoveHandlers.length; i++) {
        if (document.onMouseMoveHandlers[i] == handler) {
            return true;
        }
    }
    return false;
}

/**
 * Method to remove a document mouseMove event handler.
 * 
 * @param string handler - A callback event handler.
 */
document.removeOnMouseMoveHandler = function(handler)
{
    for (var i = 0; i < document.onMouseMoveHandlers.length; i++) {
        if (document.onMouseMoveHandlers[i] == handler) {
            document.onMouseMoveHandlers.splice(i, 1);
        return true;
        }
    }
    return false;
}

/**
 * On Click
 */

/**
 * Method to add a document onClick event handler.
 * 
 * @param string handler - A callback event handler.
 */
document.addOnClickHandler = function(handler)
{
    if (!document.isSetOnClickHandler(handler)) {
        document.onClickHandlers[document.onClickHandlers.length] = handler;
    }
    document.activateOnClickHandler(handler);
}

/**
 * Has this function already been set?
 * 
 */
document.isSetOnClickHandler = function(handler)
{
    for (var i = 0; i < document.onClickHandlers.length; i++) {
        if (document.onClickHandlers[i] == handler) {
            return true;
        }
    }
    return false;
}

/**
 * Remove this function
 * 
 */
document.removeOnClickHandler = function(handler)
{
    for (var i = 0; i < document.onClickHandlers.length; i++) {
        if (document.onClickHandlers[i] == handler) {
            document.onClickHandlers.splice(i, 1);
            document.onClickHandlersActive.splice(i, 1);
        return true;
        }
    }
    return false;
}

/**
 * Deactive this function
 * 
 */
document.deactivateOnClickHandler = function(handler)
{
    for (var i = 0; i < document.onClickHandlers.length; i++) {
        if (document.onClickHandlers[i] == handler) {
            document.onClickHandlersActive[i] = false;
        return true;
        }
    }
    return false;
}

/**
 * Activate this function
 * 
 */
document.activateOnClickHandler = function(handler)
{
    for (var i = 0; i < document.onClickHandlers.length; i++) {
        if (document.onClickHandlers[i] == handler) {
            document.onClickHandlersActive[i] = true;
        return true;
        }
    }
    return false;
}

/**
 * On Key Up
 */

/**
 * Method to add a document onKeyUp event handler.
 * 
 * @param string handler - A callback event handler.
 */
document.addOnKeyUpHandler = function(handler)
{
    if (!document.isSetOnKeyUpHandler(handler)) {
        document.onKeyUpHandlers[document.onKeyUpHandlers.length] = handler;
    }
}

/**
 * Has this function already been set?
 * 
 */
document.isSetOnKeyUpHandler = function(handler)
{
    for (var i = 0; i < document.onKeyUpHandlers.length; i++) {
        if (document.onKeyUpHandlers[i] == handler) {
            return true;
        }
    }
    return false;
}

/**
 * Method to remove a document onKeyPress event handler.
 * 
 * @param string handler - A callback event handler.
 */
document.removeOnKeyUpHandler = function(handler)
{
    for (var i = 0; i < document.onKeyUpHandlers.length; i++) {
        if (document.onKeyUpHandlers[i] == handler) {
            document.onKeyUpHandlers.splice(i, 1);
        return true;
        }
    }
    return false;
}

/////////////////////// Event Methods ///////////////////////

/**
 * Callbacks for document.oncmousemove
 */
document.onmousemove = function(e)
{
    if (!document.onMouseMoveHandlers) {
        return false;
    }
    for (var i = 0; i < document.onMouseMoveHandlers.length; i++) { 
        if (typeof document.onMouseMoveHandlers[i] == "function") {
            document.onMouseMoveHandlers[i](e);
        } else {
            eval(document.onMouseMoveHandlers[i] + '(e)');
        }
    }
}

/**
 * Callbacks for document.onclick
 */
document.onclick = function(e)
{
    if (!document.onClickHandlers) {
        return false;
    }
    for (var i = 0; i < document.onClickHandlers.length; i++) {
        if (document.onClickHandlersActive[i]) {
            if (typeof document.onClickHandlers[i] == "function") {
                document.onClickHandlers[i](e);
            } else {
                eval(document.onClickHandlers[i] + '(e)');
            }        
        }
    }
}

/**
 * 
 * 
 * NOTE: Instead of e.keyCode OR e.which use the defined e.bcKeyCode
 */
document.onkeypress = function(e)
{
    if (!document.onKeyUpHandlers) {
        return false;
    }
    var code;
    if (!e) {
        var e = window.event;
    }
    if (!e) {
        return true;
    }
	if (e.keyCode) {
        code = e.keyCode;
	} else if (e.which) {
        code = e.which;
	}
    e.bcKeyCode = code;
    
    for (var i = 0; i < this.onKeyUpHandlers.length; i++) {
        if (typeof document.onKeyUpHandlers[i] == "function") {
            document.onKeyUpHandlers[i](e);
        } else {
            eval(document.onKeyUpHandlers[i] + '(e)');
        }
    }
}

function htmlEncode(s)
{
// Not IE5 complient
//    return s.replace(/&(?!\w+([;\s]|$))/g, "&").replace(/</g, "<").replace(/>/g, ">");
}

/**
 * Remove event handlers are erase any layers
 * 
 */
function tidyOnExit()
{
    document.onMouseMoveHandlers = null;
    document.onClickHandlers = null;
    document.onClickHandlersActive = null;
    document.onKeyUpHandlers = null;
    if (window.DhtmlLayer) {
        DhtmlLayer.tidyOnExit();
    }
}

window.onunload = tidyOnExit;

/**
 * __construct
 * 
 * @package iresScript
 * @subpackage idGroup
 */
idGroup = function()
{
    this.ids = new Array();
    this.useVisability = false;
	if (arguments.length > 0) {
	    for (var i = 0; i < arguments.length; i++) {
		    this.ids[i] = arguments[i];
		}
	}
}

/**
 * Set ID Group to use visability rather than display
 *
 * @param bool value - true if to use visability
 * @todo - not fully implimented
 */
idGroup.prototype.setUseVisability = function(value)
{
    this.useVisability = value;
}

/**
 * Add IDs to the group after it has been created
 *
 * @param array - ID(s) to add
 */
idGroup.prototype.addIds = function()
{
	if (arguments.length > 0) {
	    for (var i = 0; i < arguments.length; i++) {
		    this.ids[this.ids.length] = arguments[i];
		}
	}
}

/**
 * Show one ID (and hide the rest)
 *
 * @param string id - ID to show
 */
idGroup.prototype.showOne = function(id)
{
    if (this.ids.length > 0) {
        for (var i = 0; i < this.ids.length; i++) {
            var el = document.getElementById(this.ids[i]);
            if (el) {
                if (id == this.ids[i]) {
                    if (this.useVisability) {
                        el.visibility = 'visible';
                    } else {
                        el.style.display = 'block';
                    }
                } else {
                    if (this.useVisability) {
                        el.visibility = 'hidden';
                    } else {
                        el.style.display = 'none';
                    }
                }
            }
        }
    }
}

idGroup.prototype.showMultiple = function(ids)
{
    var showIds = new Array();
    showIds = ids.split(',');
    if (this.ids.length > 0) {
        for (var i = 0; i < this.ids.length; i++) {
            var el = document.getElementById(this.ids[i]);
            if (el) {
                if (this.useVisability) {
                    el.visibility = 'hidden';
                } else {
                    el.style.display = 'none';
                }            
                for (var j = 0; j < showIds.length; j++) {
                    if (showIds[j] == this.ids[i]) {
                        if (this.useVisability) {
                            el.visibility = 'visible';
                        } else {
                            el.style.display = 'block';
                        }
                    }
                }
            }
        }
    }
}

/**
 * Use a form field to show one ID
 *
 * @param object fld - field to get the ID from
 */
idGroup.prototype.showOneUsingField = function(fld)
{
    var id = fld.value;
    if (id.length > 0) {
      this.showOne(id);  
    }
}

/**
 * __construct
 * 
 * @package iresScript
 * @subpackage pageIDGroupCollection
 */
pageIDGroupColection = function()
{
    this.idGroupsCount = 0;
    this.idGroups = new Array();
}

// Generic page wide holder for all hide / shbow groups
var PageIDGroupColection = new pageIDGroupColection();

/**
 * Create a new group
 *
 */
pageIDGroupColection.prototype.newGroup = function()
{
    this.idGroupsCount++;
    this.idGroups[this.idGroupsCount] = new idGroup();
    return this.idGroupsCount;
}

/**
 * Add ID(s) to a group using page collection
 *
 * @param integer group - Group number
 * @param string / array id - ID(s) to add
 */
pageIDGroupColection.prototype.addIds = function(group, id)
{
    this.idGroups[group].addIds(id);

}

/**
 * Show one ID using page collection
 *
 * @param integer group - Group number
 * @param object fld - field
 */
pageIDGroupColection.prototype.showOneUsingField = function(group, fld)
{
    this.idGroups[group].showOneUsingField(fld);

}

/**
 * show one ID using page collection
 *
 * @param integer group - Group number
 * @param string id - ID to show
 */
pageIDGroupColection.prototype.showOne = function(group, id)
{
    this.idGroups[group].showOne(id);

}

/**
 * Initinalise hide / show anchors
 *
 * @param string optional showing - ID to stil be visable after page load
 * @param string optional className - class name for holder of links
 */
function initShowHideA(showing, className)
{
    if (!document.getElementById) {
        return false;
    }
    className = (className) ? className : 'showHideControl';
    showing = (showing) ? showing : '';
    var linksContainer = aotGetElementsByClassName(className);
    if (linksContainer) {
        var idGroupNo = PageIDGroupColection.newGroup();
        for (var i = 0; i < linksContainer.length; i++) {
            var links = aotGetElementsByTagName('a', linksContainer[i]);
            for (var j = 0; j < links.length; j++) {
                if (links[j].href.match(/#(\w.+)/)) {
                    var id = links[j].href.match(/#(\w.+)/)[1];
                    var obj = document.getElementById(id);
                    if (obj) {
                        PageIDGroupColection.addIds(idGroupNo, id);
                        if (showing == id) {
                            obj.style.display = 'block';
                        } else {
                            obj.style.display = 'none';
                        }
                        links[j].idGroupNo = idGroupNo;
                        links[j].showId = id;
                        links[j].orgOnClick = links[j].onclick;
                        links[j].onclick = function() {
                            PageIDGroupColection.showOne(this.idGroupNo, this.showId);
                            if (typeof this.orgOnClick == "function") {
                                this.orgOnClick();
                            }
                            return false;
                        }
                    }
                }
            }
        }
    }
}

/**
 * Initialise hide / show group using SELECT
 *
 * @param string optional id - ID of SELECT to use
 */
function initShowHideSelect(id)
{
    if (!document.getElementById) {
        return false;
    }
    id = (id) ? id : 'showHideSelect';
    var sel = document.getElementById(id);
    if (sel) {
        sel.idGroupNo = PageIDGroupColection.newGroup();
        var opts = sel.options;
        for (var i = 0; i < opts.length; i++) {
            var id = opts[i].value;
            var obj = document.getElementById(id);
            if (obj) {
                PageIDGroupColection.addIds(sel.idGroupNo, id);
                if (opts[i].selected) {
                    obj.style.display = 'block';
                } else {
                    obj.style.display = 'none';
                }
            }
        }
        sel.orgOnchange = sel.onchange;
        sel.onchange = function() {
            PageIDGroupColection.showOneUsingField(this.idGroupNo, this);
            if (typeof this.orgOnchange == "function") {
                this.orgOnchange();
            }
        }
    }
}

// Do standard hide / show initilization on page load
function initShowHide()
{
   initShowHideA(showingID);
   initShowHideSelect();
}

// Generic show ID
var showingID = '';
// Do onLoad
addLoadListener(initShowHide);

/**
 * Very basic JavaScript version of PHP GET for query strings
 *
 * @param string parameter - query string parameter
 */
function GET(argname)
{
    query = unescape(location.search.substring(1));
    pairs = query.split("&");
    for (i = 0; i < pairs.length; i++) {
        key = pairs[i].split("=")[0];
        value = pairs[i].split("=")[1];
        if (key == argname) {
            return value;
        }
    }
    return "";
}


// Convert a list of strings into a query string
function makeQueryString()
{
    var args = makeQueryString.arguments;
    var searchString = "?";
    var pair;
    for (var i = 0; i < args.length; i++) {
        pair = escape(args[i++]) + "=";
        pair += escape(args[i]);
        searchString += pair + "&";
    }
    return searchString.substring(0, searchString.length - 1);
}


function getStyle(el, styleProp)
{
    var x = document.getElementById(el);
    if (x.currentStyle)
        var y = x.currentStyle[styleProp];
    else if (window.getComputedStyle)
        var y = document.defaultView.getComputedStyle(x, null).getPropertyValue(styleProp);
    return y;
}

if (GET('JSVERSION') == "1") {
    JSLib.doAOTHelp("1");
}

var DOM = (function() { 
    var dom = {};

    dom.addPX = function(value) {
        return parseInt(value) + "px";
    }
 
    dom.removeChildrenFromNode = function(node) {
	    while (node.hasChildNodes()) {
	        node.removeChild(node.firstChild);
	    }
    }
 
    dom.removeNode = function(o) {
        if (o != null && o.parentNode && o.parentNode.removeChild) {
            // First remove all attributes which are func references, to avoid memory leaks
            for (var i in o) {
                if (typeof(o[i]) == "function") {
                    o[i] = null;
                }
            }
            o.parentNode.removeChild(o);
            return true;
        }
        return false;
    }
  
  return dom;
})();

var CSS = (function() { 
    var css = {};

    css.getCuomputedStyleOrValue = function(el, attribute, defaultValue) {
        var computedAttribute = getStyle(el, attribute);
        if (computedAttribute && computedAttribute != 'auto' && parseInt(computedAttribute) > 0) {
            return parseInt(computedAttribute);
        } else {
            return defaultValue;
        }
    }
    
    css.setStyle = function(el, passedStyle) {
         alert(passedStyle.position);
  for (property in passedStyle) {
//    alert(property + " = " + passedStyle[property]);
  }

    }
 
  return css;
})();

var SCREEN = (function() { 
    var screen = {};

    screen.getPageBigestSize = function() {
        var pagePos = getPagePosScroll(true);
        var pageSize = getPageSize();
        var w = pagePos[0];
        var h = pagePos[1];
        if (pageSize[0] > w) {
            w = pageSize[0];
        }
        if (pageSize[1] > h) {
            h = pageSize[1];
        }
        w = parseInt(w);
        h = parseInt(h);
        return [w, h];
    }
 
  return screen;
})();
 
function parseURL(data) {
    var e = /((http|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+\.[^#?\s]+)(#[\w\-]+)?/;
    if (data.match(e)) {
        return {url: RegExp['$&'],
                protocol: RegExp.$2,
                host: RegExp.$3,
                path: RegExp.$4,
                file: RegExp.$6,
                hash: RegExp.$7};
    } else {
        return  {url: "", protocol: "", host: "", path: "", file: "", hash: ""};
    }
}

function parseFilename(data ) {
    data = data.replace(/^\s|\s$/g, "");
    if (data.match(/([^\/\\]+)\.(asp|html|htm|shtml|php)$/i)) {
        return {filename: RegExp.$1, ext: RegExp.$2};
    } else {
        return {filename: null, ext: null};
    }
}

/**
 * StringBuffer - Construct a new StringBuffer object.
 * @class This is a string buffer class.
 * Uses arrays for faster string concatination
 * @constructor
 * @returns A new StringBuffer
 */
function StringBuffer() {
    this.buffer = [];
}

/**
 * StringBuffer.prototype.append - Append a string to the buffer.
 * @param {string} string String to append
 * @returns {StringBuffer} Buffered text
 */
StringBuffer.prototype.append = function append(string) {
   this.buffer.push(string);
   return this;
};

/**
 * StringBuffer.prototype.toString - Convert string buffer to string.
 * @returns {string} Text
 */
StringBuffer.prototype.toString = function toString() {
    return this.buffer.join("");
};
 
if (window.JSLib) {
    JSLib.setLoaded("Document.js");
}

