/*
WhatsOnSale.com.au JavaScript Library
Created By: Jason Elliott, jay.elliott@gmail.com 
Date: 1 Sept 2008

Any code in this library that has been adapted from other people's code acknowledges the source of the original code near the function concerned.
*/


/*** Base methods for object & namespace creation - IMPORTANT: Do NOT change these!
------------------------------------------------------------------ */

function object(o) {
     function F() {}
     F.prototype = o;
     return new F();
}

/** global scope */
if (typeof _global_ === "undefined") {
    _global_ = {
        /*
         Use function @namespace to create dot separated namespaces. For example: 
		 Create a nested namespace:
		 	_global_["@namespace"]("foo");
		 	_global_["@namespace"]("foo.bar");
		 	_global_["@namespace"]("foo.bar.something");
         Then add functions to the namespace:	
			foo.bar.something.else = function() {};
         */
        "@namespace": function (str) {
            var a = str.split(".");
            var o = window;
            for(var i=0; i < a.length; i++) {
                if (!o[a[i]]) {
                    o[a[i]] = {};
                }
                o = o[a[i]];
            }
        }
    }
};

// Create the global whatsonsale namespace to avoid JS collisions with other scripts running on the page (eg. prototype, scriptaculous, or custom scripts)
_global_["@namespace"]("wos");

/** Define constants used in scripts on this page
------------------------------------------------------------------ */
_global_["@namespace"]("wos.constants");

// Set the "default" font size (relative to the browser's "default" font size. 
wos.constants.defaultFontSize = parseFloat(0.75);  /*  12px (16px x 0.75em) */

// Site domain required when writing cookies, so they work across subdomains
// NOTE: this has been moved into the header.php file because the domain is now dynamic depending on the website/URL (server aliasing)
// wos.constants.cookieDomain = "whatsonsale.com.au";

wos.constants.WosWebsites = new Array("boxingdaysales.com.au", "boxingdaysales.net.au", "christmassales.com.au", "fathersdaysale.com.au", "fathersdaysales.com.au", "whatsonsale.com.au",
	"stocktakesales.com.au", "xmassale.com.au", "xmassales.com.au", "mothersdaysale.com.au", "mothersdaysales.com.au", "junesales.com.au", "junesales.net.au", "clubforlife.com.au");

/** Event handling
------------------------------------------------------------------ */
_global_["@namespace"]("wos.event");

// Attach functions to handle events that occur on the named event source. Doesn't override previously registered handlers for the same source/event.
// See: http://www.howtocreate.co.uk/tutorials/javascript/domevents
wos.event.addEvent = function(source, eventName, functionName, useCapture) {
    useCapture = (typeof(useCapture) == "undefined") ? false : true;  // if true the event is only handled when it occurs on child/ancestor elements of the source/target element
	if (source.addEventListener) {
		source.addEventListener(eventName, functionName, useCapture);
		return true;
	}
	else if (source.attachEvent) {
		var r = source.attachEvent('on' + eventName, functionName);
		return r;
	}
	else {
		source['on' + eventName] = functionName;
	}
}

// Use this to set a default form to submit if the user presses the 'Enter' key
wos.event.submitFormOnEnterKeyPress = function(e)
{
	if (wos.event.enterKeyWasPressed(e) && (wos.form.defaultForm != null))
	{
		// Don't submit forms when the "Enter" key is pressed while insde a textarea field
		var target = wos.event.GetEventTarget(e);
		var isTextArea = target && target.type && (target.type == "textarea");
		if (!isTextArea)
		{
			// Fire any form validation first, if specified
			if (typeof wos.form.defaultForm.validatorMethod != 'undefined')
				wos.form.defaultForm.validatorMethod();
			else
				wos.form.defaultForm.submit();
		}
	}
}

// Returns the code of the key pressed
wos.event.getKeyPressed = function(e)
{
	code = -1;
	if (!e) e = window.event;
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;
//	var character = String.fromCharCode(code);
	return code;
}

// Returns true if the "Enter" key was pressed
wos.event.enterKeyWasPressed = function(e)
{
	return (wos.event.getKeyPressed(e) == 13);
}


// Return the HTML element an event took place on
wos.event.GetEventTarget = function(e)
{
	var targ;
	if (!e) 
		var e = window.event;
	if (e.target) // W3C & Netscape
		targ = e.target;
	else if (e.srcElement) // IE
		targ = e.srcElement;
	if (targ.nodeType == 3) // In Safari the event target is the text node (not the field). To get the target field find the parent node. 
		targ = targ.parentNode;
	return targ;	
}


/** DOM methods
------------------------------------------------------------------ */
_global_["@namespace"]("wos.dom");

// getElementById shorthand.  Returns a single node.
wos.dom.byID = function  (id, node) {
    return document.getElementById(id);
}

// getElementsByTagName shorthand. Returns an array.
wos.dom.byTag = function (tag, node) {
    var tag = tag || '*';
    var node = node || document;
    var e = node.getElementsByTagName(tag);
    return e;
}

// Returns elements that contain a CSS class. Returns an array.
wos.dom.byClass = function (cssClass, node, tag) {
    // create new array to store matches
    var matches = [];
    var node = node || document;
    var tag = tag || '*';
    var els = wos.dom.byTag(tag,node);
    var elsLen = els.length;
    var pattern = new RegExp("(^|\\s)"+cssClass+"(\\s|$)");
    for (i = 0, j = 0; i < elsLen; i++) {
          if (pattern.test(els[i].className)) {
                matches[j] = els[i];
                j++;
          }
    }
    return matches;
}

// Returns an element with ID = 'string'. If none it returns a collection of elements that have CSS class name = 'string'.
wos.dom.findNodes = function (string, parent ) {
    var node = false;
    var parent = parent || document;
    // try to get by id first
    node = wos.dom.byID(string, parent);
    // now try by classname
    if (!node) node = wos.dom.byClass(string, parent);
    return node;
}

// Set inline style of an element
wos.dom.setNodeStyle = function (element, newStyle) {
  if (element && newStyle)
  {
    // IE
    if ( typeof(element.style.cssText) != 'undefined' ) 
		element.style.cssText = newStyle;
    // older browsers; not IE
    else 
		element.setAttribute('style',newStyle);
  }
}

wos.dom.hasClass = function (element, cssClassName) 
{
	if (element && element.className)
	{
		var pattern = new RegExp('(\\s|^)'+cssClassName+'(\\s|$)');
		return pattern.test(element.className);
	}
	else
	{
		return false;
	}
}

wos.dom.addClass = function (element, cssClassName) 
{
	if (element)
	{
		if (!wos.dom.hasClass(element, cssClassName)) 
		{
			if (!element.className)
				element.className = cssClassName;
			else
				element.className += " " + cssClassName;
		}
	}
}

wos.dom.removeClass = function (element, cssClassName) 
{
	if (element)
	{
		if (wos.dom.hasClass(element, cssClassName)) 
		{
			var reg = new RegExp('(\\s|^)'+cssClassName+'(\\s|$)');
			element.className = element.className.replace(reg,' ');
		}
	}
}

// use to replace one CSS class with another on an element
wos.dom.replaceClass = function (element, oldClassName, newClassName) 
{
	wos.dom.removeClass(element, oldClassName);
	wos.dom.addClass(element, newClassName);
}

wos.dom.showElement = function(id)
{
    var e = wos.dom.byID(id);
    if (typeof(e) != "undefined") 
	{
        wos.dom.removeClass(e, "hidden");
        wos.dom.addClass(e, "visible"); 
	}
}

wos.dom.hideElement = function(id)
{
    var e = wos.dom.byID(id);
    if (typeof(e) != "undefined") 
	{
        wos.dom.removeClass(e, "visible");
		wos.dom.addClass(e, "hidden");  
	}
}

/** Client-side methods (browser, screen, cookie etc..)
------------------------------------------------------------------ */
_global_["@namespace"]("wos.client");

wos.client.createCookie = function  (name, value, days, path, domain, secure) 
{
	if (typeof days != 'undefined') 
	{
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
    }
    else 
		var expires = "";
    
	var cookieString = name + "=" + escape(value) + expires +
		((typeof path != 'undefined') ? ";path=" + path : ";path=/") + 
		((typeof domain != 'undefined') ? ";domain=" + domain : ";domain=" + wos.constants.cookieDomain) +
		((typeof secure != 'undefined') ? ";secure" : "");
	document.cookie = cookieString;
}

wos.client.readCookie = function (name) 
{
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

wos.client.eraseCookie = function (name, path, domain) 
{
	wos.client.createCookie(name,"",-1, path, domain);
}

wos.client.dimensions = function () {
	var d = document;
	var size = new Object();
	size.innerHeight = 0; // Usable visible browser canvas height (after subtracting toolbar, status bar, scrollbar etc.)
	size.innerWidth = 0;
	size.screenHeight = 0; // Screen dimensions
	size.screenWidth = 0;
	size.scrollY = 0;	// how far the user has scrolled their browser page down
	size.scrollX = 0;	// "    	"		"		"		"		"		right
	
	// Get browser inner/usable dimensions
	var browser = new wos.client.getBrowserSize();
	size.innerHeight = browser.innerHeight; 
	size.innerWidth = browser.innerWidth; 
	size.screenHeight = browser.screenHeight;
	size.screenWidth = browser.screenWidth;
		
	// Get scroll window offsets
	var scrollOffset = new wos.client.getScrollXY();
	size.scrollY = scrollOffset.Y;
	size.scrollX = scrollOffset.X;

	return size;
}

// From: http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
wos.client.getBrowserSize = function()
{
	var d = document;
	var browser = new Object();
	browser.innerHeight = 0;
	browser.innerWidth = 0;
	browser.screenHeight = 0;
	browser.screenWidth = 0;
    if (typeof (window.innerWidth) == 'number') 
	{
        // Not IE
		browser.innerHeight = window.innerHeight;
        browser.innerWidth = window.innerWidth;
	}
/*	else if (screen)
	{
        browser.innerHeight = screen.availHeight;
        browser.innerWidth = screen.availWidth;
	} */
    else if (d.documentElement && (d.documentElement.clientWidth || d.documentElement.clientHeight) ) 
	{
		// IE 6+ in 'standards compliant mode'
        browser.innerHeight = d.documentElement.clientHeight;
        browser.innerWidth = d.documentElement.clientWidth;
	}
    else if (d.body &&  (d.body.clientWidth || d.body.clientHeight) ) 
	{
		// IE 4 compatible
        browser.innerHeight = d.body.clientHeight;
        browser.innerWidth = d.body.clientWidth;
	}
	if (screen)
	{
        browser.screenHeight = screen.height;
        browser.screenWidth = screen.width;
	}
	return browser;
}

wos.client.getScrollXY = function() {
  var d = document;
  var w = window;
  var scroll = new Object();
  scroll.X = 0
  scroll.Y = 0;
  if ( typeof( w.pageYOffset ) == 'number' ) 
  {
    //Netscape compliant
    scroll.Y = w.pageYOffset;
    scroll.X = w.pageXOffset;
  } 
  else if( d.body && ( d.body.scrollLeft || d.body.scrollTop ) ) 
  {
    //DOM compliant
    scroll.Y = d.body.scrollTop;
    scroll.X = d.body.scrollLeft;
  } 
  else if( d.documentElement && ( d.documentElement.scrollLeft || d.documentElement.scrollTop ) ) 
  {
    //IE6 standards compliant mode
    scroll.Y = d.documentElement.scrollTop;
    scroll.X = d.documentElement.scrollLeft;
  }
  return scroll;
}


wos.client.ScrollToTopOfPage = function() 
{
    var x1 = x2 = x3 = 0;
    var y1 = y2 = y3 = 0;

    if (document.documentElement) {
        x1 = document.documentElement.scrollLeft || 0;
        y1 = document.documentElement.scrollTop || 0;
    }

    if (document.body) {
        x2 = document.body.scrollLeft || 0;
        y2 = document.body.scrollTop || 0;
    }

    x3 = window.scrollX || 0;
    y3 = window.scrollY || 0;

    var x = Math.max(x1, Math.max(x2, x3));
    var y = Math.max(y1, Math.max(y2, y3));

    window.scrollTo(Math.floor(x / 2), Math.floor(y / 2));

    if (x > 0 || y > 0) {
        window.setTimeout("wos.client.ScrollToTopOfPage()", 25);
    }
}

// Open a popup window with the specified dimension & position. Only the first parameter is required. If dimensions are not supplied, a default size will be given. 
// If no position is specified it will be centered on the screen.
wos.client.openWindow = function(url, width, height, windowName, left, top, windowOptions) {
  var defaultWidth = 780;
  var defaultHeight = 560;
  var dimensions = new wos.client.dimensions();
  width = (typeof width != "undefined") ? width : defaultWidth;
  height = (typeof height != "undefined") ? height : defaultHeight;
  left = (typeof left != "undefined") && wos.string.hasValue(left) ? left : Math.ceil((dimensions.screenWidth - width)/2);
  top = (typeof top != "undefined") && wos.string.hasValue(top) ? top : Math.ceil((dimensions.screenHeight - height)/2);
  var windowPos = 'screenX='+left+',screenY='+top+',left='+left+',top='+top;
  windowOptions = (typeof windowOptions != "undefined") ? windowOptions : 'childWindow';
  windowName = (typeof windowOptions != "undefined") ? windowName : 'popupWindow';
//  alert("height = " + height + "\nwidth = " + width + "\nscreen height = " + dimensions.screenHeight + "\nscreen width = " + dimensions.screenWidth + "\ntop = " + top + "\nleft = " + left);
  childWindow = window.open(url, windowName,'height='+height+',width='+width+','+windowPos+','+windowOptions);
  childWindow.focus();
  return childWindow;
}

var childWindow;

wos.client.setChildWindowFocus = function()
{
	if (typeof childWindow == 'object')
		childWindow.focus();
}

// Required for Firefox - If the user clicks in the parent window bring the child window on top
wos.event.addEvent(window, 'mousedown', wos.client.setChildWindowFocus);


wos.client.OS = function()
{
	var OS = new Object();
	function getName() 
	{
		for (var i=0; i < data.length; i++)	
			if (data[i].nav && (data[i].nav.indexOf(data[i].str) != -1))
				return data[i].id;
	}
	var data = [
		{
			nav: navigator.platform,
			str: "Win",
			id: "Windows"
		},
		{
			nav: navigator.platform,
			str: "Mac",
			id: "Mac"
		},
		{
			nav: navigator.platform,
			str: "Linux",
			id: "Linux"
		}
	];
	OS.name = getName();
	return OS;
}

// Contains the browser object set in wos.client.getBrowser()
wos.client.browser = null;

wos.client.getBrowser = function()
{
	var browser = new Object();
	var data = [
		{ 	nav: navigator.userAgent,
			str: "OmniWeb",
			searchStr: "OmniWeb/",
			id: "OmniWeb"
		},
		{
			nav: navigator.vendor,
			str: "Apple",
			id: "Safari"
		},
		{
			prop: window.opera,
			id: "Opera"
		},
		{
			nav: navigator.vendor,
			str: "iCab",
			id: "iCab"
		},
		{
			nav: navigator.vendor,
			str: "KDE",
			id: "Konqueror"
		},
		{
			nav: navigator.userAgent,
			str: "Firefox",
			id: "Firefox"
		},
		{
			nav: navigator.vendor,
			str: "Camino",
			id: "Camino"
		},
		{		// for newer Netscapes (6+)
			nav: navigator.userAgent,
			str: "Netscape",
			id: "Netscape"
		},
		{
			nav: navigator.userAgent,
			str: "MSIE",
			id: "Explorer",
			searchStr: "MSIE"
		},
		{
			nav: navigator.userAgent,
			str: "Chrome",
			id: "Chrome",
			searchStr: "Chrome"
		},
		{
			nav: navigator.userAgent,
			str: "Gecko",
			id: "Mozilla",
			searchStr: "rv"
		},
		{ 		// for older Netscapes (4-)
			nav: navigator.userAgent,
			str: "Mozilla",
			id: "Netscape",
			searchStr: "Mozilla"
		}];	
	var versionInfo = "";
	function getName() 
	{
		for (var i=0; i < data.length; i++)	
		{
			versionInfo = data[i].searchStr || data[i].id;
			if (data[i].nav && (data[i].nav.indexOf(data[i].str) != -1))
				return data[i].id;
			else if (data[i].prop)
				return data[i].id;
		}
	}
	function getVersion(value) 
	{
		var index = value.indexOf(versionInfo);
		if (index == -1) return;
		return parseFloat( value.substring(index + versionInfo.length + 1) );
	}
	browser.name = getName();
	browser.version = getVersion(navigator.userAgent) || getVersion(navigator.appVersion) || "an unknown version";
	return browser;
}

// Save the browser's details to a global variable
wos.client.registerBrowser = function()
{
	wos.client.browser = wos.client.getBrowser();
}

wos.event.addEvent(window, 'load', wos.client.registerBrowser);



/** Font resizing
------------------------------------------------------------------ */
_global_["@namespace"]("wos.font");

// Get font size from the saved cookie
wos.font.getSavedFontSize = function() {
	var savedSize = wos.client.readCookie('FontSize');
	return (savedSize != null) ? parseFloat(savedSize) : wos.constants.defaultFontSize;
}

// Set font size for the target (which may be a single container, or a collection of them)
wos.font.setFontSize = function (target, size) {
	// If a collection of nodes
	if (target.length)
	{
		for (var i=0; i<target.length; i++)
			if (target[i] && target[i].style) target[i].style.fontSize = size + 'em';
	}
	// If a single node
	else if (target.style) target.style.fontSize = size + 'em'; 		
}

// Called when the font resizing icons are clicked
wos.font.changeFontSize = function(target, direction) {
	var fontSize = wos.font.getSavedFontSize();
    var fontMaxSize  = 2;    		// ems
    var fontMinSize  = 0.75; 		// ems
    var increment    = 0.0625;	 	// ems (increment is 1/16 = 0.0625)

    // Change the size of any text in any container that has an ID or CSS class name = 'target'.
	if ((direction == 'up') && (fontSize + increment <= fontMaxSize)) fontSize += increment;
	else if ((direction == 'down') && (fontSize - increment  >= fontMinSize)) fontSize -= increment; 
	
	var containers = wos.dom.findNodes(target);
	if (containers) wos.font.setFontSize(containers, fontSize);
	containers = null;
	
    // Save the new font size
	wos.client.createCookie('FontSize', fontSize, 365);
	// Don't act on the link click event 
	return false;
}

// Called on page load. 
wos.font.loadSavedFontSizes = function() {
	var target = wos.dom.findNodes('resizable');
	var size = wos.font.getSavedFontSize();
	if (target) wos.font.setFontSize(target, size);
	target = null;
}

// Set font sizes from the saved cookie value on page load
wos.event.addEvent(window, 'load', wos.font.loadSavedFontSizes);


/** Extend the client's native browser prototypes (where required)
------------------------------------------------------------------ */

/* 	Add Array.push() functionality 
 	Can add multiple elements to an array. Eg Array.push(value1[, value2[, value3]]) 
	Returns the new length of the array. 
*/
if (typeof Array.prototype.push === 'undefined') 
{
	Array.prototype.push = function() 
	{
		for (var i = 0, b = this.length, a = arguments, l = a.length; i<l; i++) 
		{
			this[b+i] = a[i];
		}
 		return this.length;
	};
}

if (typeof Array.prototype.indexOf === 'undefined') 
{
    Array.prototype.indexOf = function(value) 
    {
        for (var i=0; i < this.length; i++) 
        {
            if (this[i] === value) return i;
        }
        return -1;
    };
}

if (typeof Array.prototype.contains === 'undefined') 
{
    Array.prototype.contains = function(value) 
    {
        return this.indexOf(value) > -1;
    };
}

/** Link functions
------------------------------------------------------------------ */
_global_["@namespace"]("wos.link");


// Changes the "target" attribute of any links (anchor tags) on the page to external websites to "_blank" to force them to open in a new window.
wos.link.checkExternalLinks = function() {
	var d = document;
	for (var i=0; i < d.links.length; i++) 
	{
		var isValidLink = false;
		try
		{
			strUrl = d.links[i].href;
			strUrl = (wos.string.isValidUrl(strUrl)) ? strUrl.toLowerCase() : "";
			if (strUrl != "")
				isValidLink = true;
		}
		catch(e)
		{
		}
	    if (isValidLink && !wos.uri.IsWosWebsite(strUrl) && (strUrl.indexOf("mailto") == -1)) {
		 	d.links[i].target = "_blank";
	 	}
	}
}

// Make outbound links pop up in their own window
wos.event.addEvent(window, 'load', wos.link.checkExternalLinks);


// Called on pages that show ads. Changes the "target" attribute of any links to external websites to "_blank", and redirects first through our link logger page (log-external-link-click.php)
// The second parameter is an optional boolean. In all cases external links need to be rewritten to pop up in a new window, however the click logging is optional (eg. we don't log clicks for archived ads)
wos.link.logExternalAdLinkClicks = function(fromPage, logClick)
{
	// Iterate through each Ad on this page and change each external link to route through the click logger file 
	if ((typeof wos.ads.advertIds != "undefined") && (wos.ads.advertIds.length > 0))
	{
		var adWrapper, links, adId, sellerId = "";
		logClick = (logClick) ? logClick : true;  // Log clicks by default (if not specified)
		var domain = wos.uri.domain().toLowerCase();
		for (i=0; i < wos.ads.advertIds.length; i++)
		{
			adId = wos.ads.advertIds[i];
			// Get the seller ID (from the hidden SPAN)
			eval('var sellerIdSpan = wos.dom.byID("sellerId'+adId+'")');
			sellerId = (typeof sellerIdSpan != "undefined") ? sellerIdSpan.innerHTML : "";
			// Get the ad wrapper, then get all external links in the Ad
			eval('adWrapper = wos.dom.byID("adWrapper'+adId+'")');
			if (typeof adWrapper != "undefined")
			{
				links = wos.dom.byTag("a", adWrapper);
				if (links.length > 0)
				{
					// Rewrite the links
					for (j=0; j<links.length; j++)
					{
				   		var isValidLink = false;
						try
						{
							strUrl = links[j].href;
							strUrl = (wos.string.isValidUrl(strUrl)) ? strUrl.toLowerCase() : "";
							if (strUrl != "")
								isValidLink = true;
						}
						catch(e)
						{
						}
					    if (isValidLink && (strUrl.indexOf(domain) == -1) && (strUrl.indexOf("mailto") == -1))
							wos.link.rewriteExternalLink(adId, links[j], fromPage, sellerId, logClick);
					}
				}
			}
		}
	}
}

// Change a links attributes so it redirects first to our link logging page.
wos.link.rewriteExternalLink = function(adId, link, fromPage, sellerId, logClick) 
{
	var oldUrl = link.href; 
	if (logClick)
		link.href = "/log-external-link-click.php?adId="+adId+"&fromPage=" + fromPage + "&sellerId=" + sellerId + "&url="+wos.uri.urlEncode(oldUrl);
	link.target = "_blank";
}	


// Add keypress & other event handlers for "link buttons" on the page. 
wos.link.setLinkButtonEvents = function()
{
	var anyLinkButtons = false;
	// Blur links with "button" class after they have been clicked so IE shows the correct background image on buttons.
	for (var i=0; i < document.links.length; i++) 
	{
   		var linkTag = document.links[i];
		if (wos.dom.hasClass(document.links[i], "button"))
		{
			wos.event.addEvent(linkTag, 'click', function() { linkTag.blur(); } );
			anyLinkButtons = true;
		}
	}
	// Register a keypress event handler so that the page automatically submits when the "Enter"  key is pressed (makes link act like a input type="[image|submit]" button.
	if (anyLinkButtons)
	{
		// Keypress events are captured in diff. ways in diff. browsers.
		if ((wos.client.browser != null) && (wos.client.browser.name == "Netscape"))
			document.captureEvents(Event.KEYUP);
		wos.event.addEvent(document, 'keyup', function (e) { wos.event.submitFormOnEnterKeyPress(e) } );
	}
}

// Setup any link buttons on this page.
wos.event.addEvent(window, 'load', wos.link.setLinkButtonEvents );

			   
/** String functions
------------------------------------------------------------------ */
_global_["@namespace"]("wos.string");

// Returns true if the string parameter contains only spaces, tabs or EOL characters
wos.string.isBlank = function (string){
  var _isBlank = true;
  for (var i=0; _isBlank && (i < string.length); i++) {
    var c = string.charAt(i);
    if ((c != ' ') && (c != '\n') && (c != '\t')) _isBlank = false;
  }
  return _isBlank;
}

// Returns true if the string parameter equals null, an empty string, a tab, EOL or space character. 
wos.string.hasValue = function (value) {
  if ((value==null) || (value=="") || wos.string.isBlank(value)) return false;
  else return true;
}

// Remove leading & trailing whitespace
/*
wos.string.trim = function(string) {
	return string.replace(/^\s+|\s+$/g,"");
}
*/

// Create string trim() prototype method
if (typeof String.prototype.trim === 'undefined') 
{
	String.prototype.trim = function() 
	{
		s = this.replace(/^\s+/, '');
		return s.replace(/\s+$/, '');
	};
}

wos.string.isValidEmail = function (value) {
	var emailOk   = true;
	var atPos     = value.indexOf('@');
	var periodPos = value.lastIndexOf('.');
	var spacePos  = value.indexOf(' ');
	var length    = value.length - 1;         // Array is from 0 to length-1
	if ((atPos < 1) ||                        // '@' cannot be in first position
	    (periodPos <= atPos+1) ||             // Must be at least one valid char between '@' and '.'
	    (periodPos == length ) ||             // Must be at least one valid char after '.'
	    (spacePos  != -1))                    // No empty spaces permitted
	      emailOk = false;
	return emailOk;
}

wos.string.isValidUrl = function(url) 
{
   if (!wos.string.hasValue(url)) return false
   else 
   {
	var v = new RegExp();
    v.compile("^(http|https)://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+$");
    return v.test(url); 
   }
}

wos.string.countWords = function(field) 
{
  var isInputField = (field.value != null);
  var value = isInputField ? field.value : field.innerHTML;
  var charCount = value.length;
  var fullStr = value + " ";
  var whiteSpaceRegExp = /^[^A-Za-z0-9]+/gi;
  var nonAlphanumericRegExp = /[^A-Za-z0-9]+/gi;
  var leftTrimmedStr = fullStr.replace(whiteSpaceRegExp, "");
  var cleanedStr = leftTrimmedStr.replace(nonAlphanumericRegExp, " ");
  var splitString = cleanedStr.split(" ");
  var wordCount = splitString.length - 1;
  if (fullStr.length < 2) wordCount = 0;
  return wordCount;
}

// Updates a character count field with the number of characters left remaining
wos.string.updateCharCounter = function(field, counterField, maxChars)
{
	var length = wos.string.trimToMaxChars(field, maxChars);
	counterField.value = maxChars - length;
}

// Updates a word count field
wos.string.updateWordCounter = function(field, counterField)
{
	counterField.value = wos.string.countWords(field)
}

// Restricts a textarea or other field to a set maximum number of characters.
wos.string.trimToMaxChars = function(field, maxChars)
{
	var isInputField = (field.value != null);
	var value = isInputField ? field.value : field.innerHTML;
	// If too long, trim the last chars
	if (value.length > maxChars) value = value.substring(0, maxChars);
	if (isInputField) field.value = value;
	else field.innerHTML = value;
	return value.length;
}
   
/** URL & querystring functions
------------------------------------------------------------------ */
_global_["@namespace"]("wos.uri");

/* Returns an object with the following properties:
	- directory: the protocol, domain and virtual path to the web page, eg. http://www.google.com/apps/maps/
	- domainAndPath: eg. http://www.google.com/subfolder/
	- path: the virtual path to the page, eg. /folder1/subfolder2
	- page: the page name without the extension, eg. index
	- extension: the page file extension, eg. html
	- file: the full page name including the extension, eg index.html
	- querystring: the querystring args, excluding the "?"
	- protocol http, https etc.
  Can either provide the URL parts for a supplied parameter, or the current page.
*/
wos.uri.getCurrentPageUri = function (url) {
	var uri = new Object();
	if (typeof url == 'undefined') {
	  url = location.href;
	  uri.querystring = location.search.substr(1).split("?");
	}
	else {
	  uri.querystring = (url.indexOf('?') > -1) ? url.split("?")[1] : ''; 
	};
	uri.domainAndPath = url.substring(0, url.lastIndexOf('\/'));
	parts = url.split("/");
	uri.protocol = parts[0].substring(0, parts[0].length-1); // remove the :
	uri.domain = parts[2];
	uri.path = ''; 
	for (var i=3; i < parts.length-1; i++) uri.path += '/' + parts[i];
	var pageAndQs = url.substring(uri.domainAndPath.length+1, url.length+1);
	uri.file = (pageAndQs.indexOf('?') > -1) ? pageAndQs.substring(0, pageAndQs.indexOf('?')) : pageAndQs; 
	if (uri.file.indexOf('#') > -1) uri.file = uri.file.substring(0, uri.file.indexOf('#'));
	uri.extension = (uri.file.indexOf('.') > -1) ? uri.file.substring(uri.file.indexOf('.')+1) : ''; 
	uri.page = (uri.file.indexOf('.') > -1) ? uri.file.substr(0, uri.file.indexOf('.')) : uri.file;
	if (uri.page == '') { uri.file = 'index.php'; uri.page = 'index'; uri.extension = 'php'; }
	return uri;
}

// Returns the site domain
wos.uri.domain = function() {
    var uri = new wos.uri.getCurrentPageUri();
	return uri.domain;
}

wos.uri.urlEncode = function(value) {
  var output = '';
  var x = 0;
  value = value.toString();
  var regex = /(^[a-zA-Z0-9_.]*)/;
  while (x < value.length) 
  {
    var match = regex.exec(value.substr(x));
    if ((match != null) && (match.length > 1) && (match[1] != '')) 
	{
    	output += match[1];
      	x += match[1].length;
    } 
	else 
	{
      if (value[x] == ' ')
        output += '+';
      else 
	  {
        var charCode = value.charCodeAt(x);
        var hexVal = charCode.toString(16);
        output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase();
      }
      x++;
    }
  }
  return output;
}


wos.uri.IsWosWebsite = function(url)
{
	var isAWosWebsite = false;
	url = url.toLowerCase();
	for (var i=0; !isAWosWebsite && (i < wos.constants.WosWebsites.length); i++)
	{
		isAWosWebsite = (url.indexOf(wos.constants.WosWebsites[i]) >= 0);
	}
	return isAWosWebsite;
}

// Gets an associative array of querystring name/value pairs
wos.uri.GetQueryStringVariables = function(qString) 
{
  qString = qString ? qString : location.search;
  var query = qString.charAt(0) == '?' ? qString.substring(1) : qString;
  var args = new Object();
  if (query) 
  {
    var fields = query.split('&');
    for (var f = 0; f < fields.length; f++) 
	{
      var field = fields[f].split('=');
	  if (field[0] && field[1]) 
	  {
	      args[unescape(field[0].replace(/\+/g, ' '))] = unescape(field[1].replace(/\+/g, ' '));
	  }
    }
  }
  return args;
}

// Returns the value of a particular querystring variable as a string
wos.uri.GetValueFromQueryString = function(variableName) {
	var qsArgs = wos.uri.GetQueryStringVariables();
	if (qsArgs[variableName]) return qsArgs[variableName];
	else return '';
}


/** Form & Form-Field functions
------------------------------------------------------------------ */
_global_["@namespace"]("wos.form");


// Stores a reference to the page's "default form" (which will be submitted if the user presses the "Enter" key)
wos.form.defaultForm = null;

// This is used to register a partcular page's default form 
wos.form.setDefaultForm = function(frm)
{
	// If no form was supplied, use the first one found on the page.
	if (!frm) frm = document.forms[0];
	wos.form.defaultForm = frm;
}

/** Form-Field functions
------------------------------------------------------------------ */
_global_["@namespace"]("wos.form.field");

// Limit textarea fields to a maximum number of chars.
wos.form.field.setMaxChars = function (field, maxChars) 
{
	if (field.value.length > maxChars) field.value = field.value.substring(0, maxChars);
}

// Select/deselect all checkboxes in a collection
wos.form.field.CheckAllCheckBoxes = function(checkboxes, checkAll)
{
	checkAll = (checkAll) ? checkAll : false;
	// If there is more than one checkbox...
	if (checkboxes.length)
	{ 
		for (var i=0; i < checkboxes.length; i++)
			checkboxes[i].checked = checkAll;
	}
	// If there is only one checkbox
	else
		checkboxes.checked = checkAll;
}


/** AJAX methods
------------------------------------------------------------------ */
_global_["@namespace"]("wos.ajax");

// Global xmlHttp object
wos.ajax.xmlHttpObject = null;

wos.ajax.GetXmlHttpObject = function()
{
  	var xmlHttpObject = null;
	try
	{
		// Firefox, Opera 8.0+, Safari
		xmlHttpObject = new XMLHttpRequest();
	}
	catch (e)
	{
		// Internet Explorer
		try
		{
			xmlHttpObject = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e)
		{
			xmlHttpObject = new ActiveXObject("Microsoft.XMLHTTP");
		}
	}
	return xmlHttpObject;
}

// Asynchronous GET
wos.ajax.GetUrl = function(url, callbackFunction)
{
	wos.ajax.xmlHttpObject = wos.ajax.GetXmlHttpObject();
	if (wos.ajax.xmlHttpObject == null)
	{
		alert ("Your browser does not support AJAX!");
		return;
	}
	wos.ajax.xmlHttpObject.onreadystatechange = callbackFunction;
	wos.ajax.xmlHttpObject.open("GET", url, true);
	wos.ajax.xmlHttpObject.send(null);	
}

// Asynchronous POST
wos.ajax.PostToUrl = function(url, postData, callbackFunction)
{
	wos.ajax.xmlHttpObject = wos.ajax.GetXmlHttpObject();
	if (wos.ajax.xmlHttpObject == null)
	{
		alert ("Your browser does not support AJAX!");
		return;
	}
	wos.ajax.xmlHttpObject.onreadystatechange = callbackFunction;
	wos.ajax.xmlHttpObject.open("POST", url, true);
	wos.ajax.xmlHttpObject.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    wos.ajax.xmlHttpObject.setRequestHeader("Content-length", postData.length);
    wos.ajax.xmlHttpObject.setRequestHeader("Connection", "close");
	wos.ajax.xmlHttpObject.send(null);	
}


/** Advertisement functions
------------------------------------------------------------------ */
_global_["@namespace"]("wos.ads");
			
// When the user selects a retailer from the Retailer drop-down list, redirect the page.
wos.ads.showRetailerAds = function(retailers)
{
	var redirectUrl;
	// If the second parameter isn't supplied, determine the page to redirect to based on the selected retailer
	if ((retailers.selectedIndex == 0) && (retailers.options[retailers.selectedIndex].value == "all"))
		redirectUrl = "/view-all-retailers.php";
	if (retailers.selectedIndex > 0)
	{
		// The drop-down list option values are of the form "/retailerName-sale/r(retailer ID)"
		var selectedIdAndName = retailers.options[retailers.selectedIndex].value;
		redirectUrl = selectedIdAndName.toLowerCase();
	}
	location.href = redirectUrl;
}

// Swaps content into the specified region
wos.ads.swapIn = function (regionId, contentId)
{
	var regionDiv = wos.dom.byID(regionId);
	var contentDiv = wos.dom.byID(contentId);
	if (regionDiv && contentDiv)
		regionDiv.innerHTML = contentDiv.innerHTML;
}

// Swap the main ad's image back in when the user clicks the "Main Ad" button
wos.ads.swapInMainAd = function(adId, largeImageSrc, regionId, contentId)
{
	var largeImgWrapper = wos.dom.byID("adImageDiv" + adId);
	var imageId = 'ad'+ adId +'LargeImage';
	if (largeImgWrapper)
	{
		largeImgWrapper.innerHTML = '<img src="'+ largeImageSrc +'" name="ad'+ adId +'LargeImage" id="ad'+ adId +'LargeImage" width="300" height="300" border="0" class="corners iradius6 iborder1 icolorDDDDDD">';
		var newLargeImage = document.getElementById(imageId); 
		if (newLargeImage) 
		{
			// Firefox throws an exception on the canvas.drawImage() method. Disable for now. 
			if (wos.client.browser != null)
			{
				if ((wos.client.browser.name == "Firefox") || (wos.client.browser.name == "Chrome"))
					newLargeImage.style.border = '1px solid #DDDDDD';
				else
					AddCornersToImage(newLargeImage); 
			}
		}
	}
	wos.ads.swapIn(regionId, contentId);
}

// When user clicks a thumbnail image show the larger image version plus the associated text
wos.ads.swapInThumbContent = function(adId, thumbNumber, largeImageSrc)
{
	var largeImgWrapper = wos.dom.byID("adImageDiv" + adId);
	var imageId = 'ad'+ adId +'LargeImage';
	if (largeImgWrapper)
	{
		largeImgWrapper.innerHTML = '<img src="'+ largeImageSrc +'" name="'+imageId+'" id="'+imageId+'" width="300" height="300" border="0" class="corners iradius6 iborder1 icolorDDDDDD">';
		var newLargeImage = document.getElementById(imageId); 
		if (newLargeImage) 
		{
			// Firefox throws an exception on the canvas.drawImage() method. Disable for now. 
			if (wos.client.browser != null)
			{
				if ((wos.client.browser.name == "Firefox") || (wos.client.browser.name == "Chrome"))
					newLargeImage.style.border = '1px solid #DDDDDD';
				else
					AddCornersToImage(newLargeImage); 
			}
		}
	}
	var thumbContentId = 'thumbText' + adId + '-' + thumbNumber;
	wos.ads.swapIn('swapArea' + adId, thumbContentId);
}


/** Thumbnail animation functions
------------------------------------------------------------------ */

// Image scroller code adapted from: http://www.learningjquery.com/2006/10/scroll-up-headline-reader
_global_["@namespace"]("wos.thumbs");

// The number of thumbnails images to display
wos.thumbs.numberToDisplay = 4;
// Speed in milliseconds
wos.thumbs.animateSpeed = 2000;
// Width of thumb image (containers) in pixels
wos.thumbs.imageWidth = 71;
// Gap between thumbs (margin)
wos.thumbs.spacing = 5;
// Use a global array to store references to one imageSet object per ad
wos.thumbs.imageSets = new Array();  
// The prefix of the thumbnail container's ID
wos.thumbs.wrapperPrefix = "thumbstrip-";


// This object represents a block of thumbnail images associated with an advert
wos.thumbs.imageSet = function()
{
	this.adId = "";
	this.numberOfImages = 0;
	this.isMoving = false;
	// This array of integers is used to indicate which thumbnails in the set are visible & need to be moved next. The zero-indexed element is the left-most image.
	this.images = new Array(); 
	for (var i=0; i <= wos.thumbs.numberToDisplay; i++)
		this.images[i] = i;
}

// For each ad on this page, initialize an ImageSet object and store it in the global wos.thumbs.imageSets array
wos.thumbs.init = function() 
{
	var k, adId;
	var imageWidth = wos.thumbs.imageWidth + wos.thumbs.spacing;
	var numVisibleImages = wos.thumbs.numberToDisplay;
	var prefix = wos.thumbs.wrapperPrefix;
	// For each ad...
	for (var i=0; i < wos.ads.advertIds.length; i++)
	{
		adId = wos.ads.advertIds[i];
		var thumbSet = new wos.thumbs.imageSet();
		thumbSet.adId = adId;
		// Count & store the number of thumbnails in this ad
		thumbSet.numberOfImages = $('#' + prefix + adId + ' div.thumb').size();
		// Move the initially visible images into place
		for (var j = 0; j < numVisibleImages; j++) 
			$('#' +  prefix + adId + ' div.thumb:eq(' + j + ')').css('left', (j * imageWidth) + 'px');   
		// Keep the other images just offscreen
		for (var j = numVisibleImages; j < thumbSet.numberOfImages; j++) 
			$('#' + prefix + adId + ' div.thumb:eq(' + j + ')').css('left', ((numVisibleImages * imageWidth) + 'px'));   
		// Store the ImageSet object reference in the global array
		wos.thumbs.imageSets[adId] = thumbSet;
		// add debug events to the element
		// $('#' + prefix + adId + ' div img').click(function() { alert(this.style.left); } );  
	}
}

// Animates images moving left. Use the ImageSet.images values to find the correct images to move. 
wos.thumbs.rotateImages = function(adId) 
{ 
	var thumbSet = wos.thumbs.imageSets[adId];
	// Only move thumbs if they aren't already moving
	if (!thumbSet.isMoving)
	{
		thumbSet.isMoving = true;
		var totalNumberOfThumbs = thumbSet.numberOfImages;
		var animateSpeed = wos.thumbs.animateSpeed;
		var numVisibleImages = wos.thumbs.numberToDisplay;
		var move = wos.thumbs.imageWidth + wos.thumbs.spacing;
		var viewPortWidth = numVisibleImages * (wos.thumbs.imageWidth + wos.thumbs.spacing);
		var prefix = wos.thumbs.wrapperPrefix;
		// Scroll the left-most image off screen
		$('#' +  prefix + adId + ' div.thumb:eq(' + thumbSet.images[0] + ')').animate({left: ((-1 * move) + 'px')}, animateSpeed, function() { 
			// Add a callback function so it moves back to the right-side (out of view) immediately afterwards
			$(this).css('left', (viewPortWidth + 'px')); 
		}); 
		// Scroll the next images to the left
		for (var i=0; i< (numVisibleImages-1); i++)
			$('#' +  prefix + adId + ' div.thumb:eq(' + thumbSet.images[i+1] + ')').animate({left: ((i * move) + 'px')}, animateSpeed);
		// Move the right-most image, and use a callback function to indicate when the set has finished moving
		$('#' +  prefix + adId + ' div.thumb:eq(' + thumbSet.images[numVisibleImages] + ')').animate({left: (((numVisibleImages-1) * move) + 'px')}, animateSpeed, function() {
			thumbSet.isMoving = false; 
		});
		// Increment the index that shows which images to show next
		for (var i=0; i<=numVisibleImages; i++)
			thumbSet.images[i] = (thumbSet.images[i] + 1) % totalNumberOfThumbs; 	
		// Store the updated thumb object
		wos.thumbs.imageSets[adId] = thumbSet;
	}
}


/** Image functions - preloads etc.
------------------------------------------------------------------ */
_global_["@namespace"]("wos.image");

// A global array to store the source of images that need preloading.
wos.image.preloads = new Array();

// Write each image from the preloadedImages() array into a hidden container in the page footer. 
wos.image.preloadImages = function()
{
	var container = document.getElementById("preloadedImages") // in the page footer
	if (document.createElement && container && wos.image.preloads)
	{
		for	(var i = 0; i < wos.image.preloads.length; i++)
		{
			var img = document.createElement('img');
			img.setAttribute('src', wos.image.preloads[i]);
			container.appendChild(img);
		}
	}
}

wos.event.addEvent(window, 'load', wos.image.preloadImages);


/** DHTML Tooltips
------------------------------------------------------------------ */
_global_["@namespace"]("wos.toolTip");


var oToolTip;

wos.toolTip.Create = function()
{
	var d = document;
	
	if (!d.getElementById('toolTipDiv'))
	{
		// Create a DIV with ID toolTipDiv on the page
		var body = d.getElementsByTagName('body');
		var div = document.createElement('div');
		div.setAttribute('id', 'toolTipDiv');
		body[0].appendChild(div);
	}
	
	// Create a tooltip object
	oToolTip = new Object();
	oToolTip.toolTipId = "toolTipDiv";
	oToolTip.offsetX = -60;
	oToolTip.offsetY = 20;
	oToolTip.isIE4 = document.all;
	oToolTip.isNewButNotIE4 = document.getElementById && !document.all;
	oToolTip.enabled = false;
	if (oToolTip.isIE4 || oToolTip.isNewButNotIE4)
		oToolTip.div = d.all ? d.all[oToolTip.toolTipId] : d.getElementById ? d.getElementById(oToolTip.toolTipId) : "";
}

wos.toolTip.ShowImage = function(imageSource, bgColour, width, height)
{
	if (typeof oToolTip != "object")
		wos.toolTip.Create();
	
	if (oToolTip.div)
	{
		var size = "";
		if (typeof width != "undefined") 
		{
			oToolTip.div.style.width = width + "px";
			size = "width='" + width + "' ";
		}
		if ((typeof bgColour != "undefined") && (bgColour != "")) oToolTip.div.style.backgroundColor = bgColour;
		if (typeof height != "undefined") size += " height='" + height + "'";
		oToolTip.div.innerHTML = "<img src='" + imageSource + "' border='0' " + size + ">";
		oToolTip.enabled = true;
		return false;
	}
}

wos.toolTip.ShowHtml = function(html, cssClassName, width, height)
{
	if (typeof oToolTip != "object")
		wos.toolTip.Create();
	
	if (oToolTip.div)
	{
		var size = "";
		if (typeof width != "undefined") 
		{
			oToolTip.div.style.width = width + "px";
			size = "width='" + width + "' ";
		}
		if ((typeof cssClassName != "undefined") && (cssClassName != "")) oToolTip.div.className = cssClassName;
		if (typeof height != "undefined") size += " height='" + height + "'";
		oToolTip.div.innerHTML = html;
		oToolTip.enabled = true;
		return false;
	}
}

wos.toolTip.ShowPageContent = function(url, width, height)
{
	if (typeof oToolTip != "object")
		wos.toolTip.Create();
	
	if (oToolTip.div)
	{
		var size = (typeof height != "undefined") ? "height='" + height + "'" : "height='100%'";
		if (typeof width != "undefined") 
		{
			oToolTip.div.style.width = width + "px";
			size += " width='" + width + "'";
		}
		else
			size += " width='100%'";
		if ((typeof bgColour != "undefined") && (bgColour != "")) oToolTip.div.style.backgroundColor = bgColour;
		oToolTip.div.innerHTML = "<iframe src='" + url + "' border='0' frameborder='1' scrolling='auto' " + size + "></iframe>";
		oToolTip.enabled = true;
		return false;
	}
}

/*
wos.toolTip.ShowPageContent2 = function(url, cssClassName, width, height)
{
	var content = wos.ajax.GetUrl(url, function () {
	    if (wos.ajax.xmlHttpObject && (wos.ajax.xmlHttpObject.readyState == 4))
			wos.toolTip.ShowHtml(wos.ajax.xmlHttpObject.responseText, cssClassName, width, height);
	});
}
*/

wos.toolTip.AdjustPosition = function(e)
{
	var d = document;
	var iePageBody = (d.compatMode && (d.compatMode != "BackCompat"))? d.documentElement : d.body;
	if ((typeof oToolTip == "object") && oToolTip.enabled)
	{
		var curX = (oToolTip.isNewButNotIE4) ? e.pageX : event.clientX + iePageBody.scrollLeft;
		var curY = (oToolTip.isNewButNotIE4) ? e.pageY : event.clientY + iePageBody.scrollTop;
		var rightEdge = oToolTip.isIE4 && !window.opera ? iePageBody.clientWidth - event.clientX - oToolTip.offsetX : window.innerWidth - e.clientX - oToolTip.offsetX - 20;
		var bottomEdge = oToolTip.isIE4 && !window.opera ? iePageBody.clientHeight - event.clientY - oToolTip.offsetY : window.innerHeight - e.clientY - oToolTip.offsetY - 20;
		var leftEdge = (oToolTip.offsetX  <  0) ? oToolTip.offsetX * (-1) : -1000;
		if (rightEdge < oToolTip.div.offsetWidth)
			oToolTip.div.style.left = oToolTip.isIE4 ? iePageBody.scrollLeft + event.clientX - oToolTip.div.offsetWidth + "px" : window.pageXOffset + e.clientX - oToolTip.div.offsetWidth + "px";
		else if (curX < leftEdge)
			oToolTip.div.style.left = "5px";
		else
			oToolTip.div.style.left = curX + oToolTip.offsetX + "px";
		if (bottomEdge < oToolTip.div.offsetHeight)
			oToolTip.div.style.top = oToolTip.isIE4 ? iePageBody.scrollTop + event.clientY - oToolTip.div.offsetHeight - oToolTip.offsetY + "px" : window.pageYOffset + e.clientY - oToolTip.div.offsetHeight - oToolTip.offsetY + "px";
		else
		oToolTip.div.style.top = curY + oToolTip.offsetY + "px";
		oToolTip.div.style.visibility = "visible";
	}
}

wos.toolTip.Hide = function(wait)
{
	if ((typeof oToolTip == "object") && oToolTip.div)
	{
		if (arguments.length == 1)
			setTimeout(function(oToolTip) { 
				wos.toolTip.HideNow(oToolTip) 
			}, wait);
		else
			wos.toolTip.HideNow(oToolTip); 
	}
}

wos.toolTip.HideNow = function(oToolTip)
{
	oToolTip.enabled = false;
	oToolTip.div.style.visibility = "hidden";
	oToolTip.div.style.left = "-1000px";
	oToolTip.div.style.backgroundColor = '';
	oToolTip.div.style.width = '';
}

// Move the tooltip layer near the mouse or nearest screen edge.
wos.event.addEvent(document, 'mousemove', wos.toolTip.AdjustPosition);


/** Miscellaneous functions (eg. WOS domain/business rules, functions unlikely to be reused on other sites)
------------------------------------------------------------------ */
_global_["@namespace"]("wos.misc");


// only submit the form if required fields have values
wos.misc.validateFriendForm = function(formName, adId)
{
	eval("var f = document.getElementById('" + formName + "')");
	if (typeof f != "undefined")
	{
		var isErrors = false;
		eval("var name = document.getElementById('personsName" + adId + "')");
		eval("var fName = document.getElementById('friendsName" + adId + "')");
		eval("var email = document.getElementById('friendsEmail" + adId + "')");
		eval("var comments = document.getElementById('comments" + adId + "')");
		isErrors = wos.misc.fieldIsEmpty(name);
		isErrors = (wos.misc.fieldIsEmpty(fName) || isErrors);
		isErrors = (wos.misc.fieldIsEmpty(email) || isErrors);
		if (wos.string.hasValue(email.value))
		{
			isValidEmail = wos.string.isValidEmail(email.value);
			isErrors = !isValidEmail || isErrors;
			email.className = (isValidEmail) ? 'ok' : 'error';
		}
		isErrors = (wos.misc.fieldIsEmpty(comments) || isErrors);
		if (!isErrors) f.submit();
	}
}

// Check whether a field is empty, and set it's CSSS class name accordingly
wos.misc.fieldIsEmpty = function(field)
{
	var isEmpty = false;
	if (!wos.string.hasValue(field.value)) 
	{
		isEmpty = true;
		field.className = 'error';
	}
	else 
		field.className = 'ok';
	return isEmpty;
}

wos.misc.filterByState = function(states, friendlyUrl, uglyUrl)
{
	var selectedStateId = states.options[states.selectedIndex].value;
	
	// If a state was chosen save it to a cookie and reload the current page. 
	if (wos.string.hasValue(selectedStateId) && (selectedStateId != "all"))
	{
		// NOTE: This is a session cookie (not persistant) as no expiry date is specified. This means people who choose a state from the drop-down list will retain the chosen state 
		// between pages for the duration of their session, people who visit the site from a regional URL (eg. .../sydney in Google) will not have a saved region/state cookie, and
		// so they will see the region in the URL.
		wos.client.createCookie('stateId', selectedStateId);
	}
	// If "all states" ("choose a state") was chosen, delete the stateId cookie and reload the page
	else
	{
/*		if (wos.misc.States && (typeof wos.misc.States[selectedStateId] != 'undefined'))
		{
			// wos.uri.GetRegionalisedUrl(friendlyUrl, selectedStateId);
		}
		*/
		wos.client.eraseCookie('stateId');
	}
	location.reload();
}

wos.misc.showGoogleMap = function(branchId)
{
	wos.client.openWindow('/view-branch-location-map.php?branchId='+branchId, 500, 400, 'googleMapPopup', null, null, 'modal=yes');
}


// Submit the search form only if something has been entered into the search field
wos.misc.validateSearchForm = function(formName)
{
	eval("var f = document.getElementById('" + formName + "')");
	if (typeof f != "undefined")
	{
		var field;
		if (f.elements) field = f.elements['query'];
		if ((typeof field != 'undefined') && wos.string.hasValue(field.value.trim()))
			f.submit();
	}
}


// Returns true if the file 'path' ends with one of the acceptable extensions in the pipe-delimited string ''. 
wos.misc.isAllowedFileExtension = function(path, acceptedExtensions){
    return new RegExp("\.(" + acceptedExtensions + ")$","i").test(path);
}


