/*
GeekIT.com.au JavaScript Library
Created By: Jason Elliott, jay.elliott@gmail.com 
Date: 2 October 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 geekIT namespace to avoid JS collisions with other scripts running on the page (eg. prototype, scriptaculous, or custom scripts)
_global_["@namespace"]("geekIT");

/** Define constants used in scripts on this page
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.constants");

// Set the "default" font size (relative to the browser's "default" font size. 
geekIT.constants.defaultFontSize = parseFloat(0.75);  /*  12px (16px x 0.75em) */

// Site domain required when writing cookies, so they work across subdomains
geekIT.constants.cookieDomain = "geekitgroup.com.au";

// Used to highlight search words ala Google. See functions near geekIT.string.HighlightWordsOnPage() 
geekIT.constants.searchWordsQsVar = "searchWords";
geekIT.constants.highlightCssClass = "highlighted";
geekIT.constants.textContainerId = "bodyText";


/** Event handling
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.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
geekIT.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
geekIT.event.submitFormOnEnterKeyPress = function(e)
{
	if (geekIT.event.enterKeyWasPressed(e) && (geekIT.form.defaultForm != null))
	{
		// Fire any form validation first, if specified
		if (typeof geekIT.form.defaultForm.validatorMethod != 'undefined')
			geekIT.form.defaultForm.validatorMethod();
		else
			geekIT.form.defaultForm.submit();
	}
}

// Returns the code of the key pressed
geekIT.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
geekIT.event.enterKeyWasPressed = function(e)
{
	return (geekIT.event.getKeyPressed(e) == 13);
}

/** DOM methods
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.dom");

// getElementById shorthand.  Returns a single node.
geekIT.dom.byID = function  (id, node) {
    return document.getElementById(id);
}

// getElementsByTagName shorthand. Returns an array.
geekIT.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.
geekIT.dom.byClass = function (cssClass, node, tag) {
    // create new array to store matches
    var matches = [];
    var node = node || document;
    var tag = tag || '*';
    var els = geekIT.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'.
geekIT.dom.findNodes = function (string, parent ) {
    var node = false;
    var parent = parent || document;
    // try to get by id first
    node = geekIT.dom.byID(string, parent);
    // now try by classname
    if (!node) node = geekIT.dom.byClass(string, parent);
    return node;
}

// Set inline style of an element
geekIT.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);
  }
}

geekIT.dom.hasClass = function (element, cssClassName) 
{
	if (element && element.className)
	{
		var pattern = new RegExp('(\\s|^)'+cssClassName+'(\\s|$)');
		return pattern.test(element.className);
	}
	else
	{
		return false;
	}
}

geekIT.dom.addClass = function (element, cssClassName) 
{
	if (element)
	{
		if (!geekIT.dom.hasClass(element, cssClassName)) 
		{
			if (!element.className)
				element.className = cssClassName;
			else
				element.className += " " + cssClassName;
		}
	}
}

geekIT.dom.removeClass = function (element, cssClassName) 
{
	if (element)
	{
		if (geekIT.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
geekIT.dom.replaceClass = function (element, oldClassName, newClassName) 
{
	geekIT.dom.removeClass(element, oldClassName);
	geekIT.dom.addClass(element, newClassName);
}

geekIT.dom.showElement = function(id)
{
    var e = geekIT.dom.byID(id);
    if (typeof(e) != "undefined") 
	{
        geekIT.dom.removeClass(e, "hidden");
        geekIT.dom.addClass(e, "visible"); 
	}
}

geekIT.dom.hideElement = function(id)
{
    var e = geekIT.dom.byID(id);
    if (typeof(e) != "undefined") 
	{
        geekIT.dom.removeClass(e, "visible");
		geekIT.dom.addClass(e, "hidden");  
	}
}

/** Client-side methods (browser, screen, cookie etc..)
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.client");

geekIT.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=" + geekIT.constants.cookieDomain) +
		((typeof secure != 'undefined') ? ";secure" : "");
	document.cookie = cookieString;
}

geekIT.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;
}

geekIT.client.eraseCookie = function (name, path, domain) 
{
	geekIT.client.createCookie(name,"",-1, path, domain);
}


geekIT.client.PersistentCookiesAreEnabled = function() 
{
  // Try to save a persistant cookie, then see if it was successful
  geekIT.client.createCookie("testPersistentCookie", "enabled", 1);
  var readCookie = geekIT.client.readCookie("testPersistentCookie");
  return geekIT.string.hasValue(readCookie) && (readCookie == "enabled");
}

geekIT.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 geekIT.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 geekIT.client.getScrollXY();
	size.scrollY = scrollOffset.Y;
	size.scrollX = scrollOffset.X;

	return size;
}

// From: http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
geekIT.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 (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;
}

geekIT.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;
}

// 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.
geekIT.client.openWindow = function(url, width, height, left, top, windowOptions) {
  var defaultWidth = 780;
  var defaultHeight = 560;
  var dimensions = new geekIT.client.dimensions();
  width = (typeof width != "undefined") ? width : defaultWidth;
  height = (typeof height != "undefined") ? height : defaultHeight;
  left = (typeof left != "undefined") && geekIT.string.hasValue(left) ? left : Math.ceil((dimensions.screenWidth - width)/2);
  top = (typeof top != "undefined") && geekIT.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 : '';
//  alert("height = " + height + "\nwidth = " + width + "\nscreen height = " + dimensions.screenHeight + "\nscreen width = " + dimensions.screenWidth + "\ntop = " + top + "\nleft = " + left);
  childWindow = window.open(url, 'popupWindow','height='+height+',width='+width+','+windowPos+','+windowOptions);
  childWindow.focus();
  return childWindow;
}

var childWindow;

geekIT.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
// geekIT.event.addEvent(window, 'mousedown', geekIT.client.setChildWindowFocus);

geekIT.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 geekIT.client.getBrowser()
geekIT.client.browser = null;

geekIT.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: "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
geekIT.client.registerBrowser = function()
{
	geekIT.client.browser = geekIT.client.getBrowser();
}

geekIT.event.addEvent(window, 'load', geekIT.client.registerBrowser);


/** Font resizing
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.font");

// Get font size from the saved cookie
geekIT.font.getSavedFontSize = function() {
	var savedSize = geekIT.client.readCookie('FontSize');
	return (savedSize != null) ? parseFloat(savedSize) : geekIT.constants.defaultFontSize;
}

// Set font size for the target (which may be a single container, or a collection of them)
geekIT.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
geekIT.font.changeFontSize = function(target, direction) {
	var fontSize = geekIT.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 = geekIT.dom.findNodes(target);
	if (containers) geekIT.font.setFontSize(containers, fontSize);
	containers = null;
	
    // Save the new font size
	geekIT.client.createCookie('FontSize', fontSize, 1000);
	// Don't act on the link click event 
	return false;
}

// Called on page load. 
geekIT.font.loadSavedFontSizes = function() {
	var target = geekIT.dom.findNodes('resizable');
	var size = geekIT.font.getSavedFontSize();
	if (target) geekIT.font.setFontSize(target, size);
	target = null;
}

// Set font sizes from the saved cookie value on page load
//geekIT.event.addEvent(window, 'load', geekIT.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;
	};
}

/* Add Array.inArray(value, caseSensitiveComparison) functionality
	Returns true if the value is found in the array, false if not.
	Note: Default behaviour is a case-sensitive match.  If you don’t want to perform case sensitive check, then set caseSensitve=true and call the function.
*/
if (typeof Array.prototype.inArray === 'undefined') 
{
	Array.prototype.inArray = function(value, isCaseSensitive) 
	{
		var _inArray = false;
		for (var i=0; !_inArray && (i < this.length); i++) 
		{
			// If not specified, or caseSensitive == false, do a non-case sensitive match
			if ((typeof(isCaseSensitive) === "undefined") || !isCaseSensitive) 
			{
				if (this[i].toLowerCase() == value.toLowerCase()) _inArray = true;
			}
			else 
			{
				if (this[i] == value) _inArray = true;
			}
		}
		return _inArray;
	};
}
			   
/** String functions
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.string");

// Returns true if the string parameter contains only spaces, tabs or EOL characters
geekIT.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. 
geekIT.string.hasValue = function (value) {
  if ((value==null) || (value=="") || geekIT.string.isBlank(value)) return false;
  else return true;
}

// Remove leading & trailing whitespace
/*
geekIT.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+$/, '');
	};
}

geekIT.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;
}

geekIT.string.isValidUrl = function(url) 
{
   if (!geekIT.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); 
   }
}

geekIT.string.emailDomain = function (email) {
	var domain = (email.indexOf('@') != -1) ? email.substr(email.indexOf('@') + 1) : "";
	return domain;
}

/*
Highlights search words on a page
Adapted From: http://eriwen.com/javascript/highlight-search-results-with-js/
*/
geekIT.string.HighlightWordsOnPage = function() 
{
  // Display a heading with each search term highlighted in the specified colours if showIndex is true.
  var showSummary = (typeof showSummary != "undefined") ? showSummary : false;
  var summaryText = "";
  var searchString = geekIT.uri.GetValueFromQueryString(geekIT.constants.searchWordsQsVar);
  
  // If there is a search variable in the querystring
  if (geekIT.string.hasValue(searchString)) 
  {
    // Get the pipe-delimited string of search words
	// var searchString = geekIT.string.GetSearchStringFromQS();
	//if (geekIT.string.hasValue(searchString))
	//{
	    // Define the region (starting/parent node) in which to highlight words
	    var textContainerNode = document.getElementById(geekIT.constants.textContainerId);
		if (showSummary) summaryText = 'Search Results for: ';
	
		// If only one search string
		if (searchString.indexOf('|') == -1)
		{
	      var regex = new RegExp(">([^<]*)?("+searchString+")([^>]*)?<","ig");
	      geekIT.string.HighlightTextNodes(textContainerNode, regex, i);
		  if (showSummary) summaryText += ' <span class="highlighted term'+i+'">'+searchString+'</span> ';
		}
	    // If more than one search word, split on the '|' character and highlight each individual word
		else
		{
		    var wordsArray = searchString.split('|');
		    for (var i=0; i < wordsArray.length; i++) 	{
		      var regex = new RegExp(">([^<]*)?("+wordsArray[i]+")([^>]*)?<","ig");
		      geekIT.string.HighlightTextNodes(textContainerNode, regex, i);
		      if (showSummary) summaryText += ' <span class="highlighted term'+i+'">'+wordsArray[i]+'</span> ';
		    }
		}
		
	    if (showSummary) 
		{
		    // Insert a heading above the searched container (as the first child)
			var searchTermDiv = document.createElement("H2");
		    searchTermDiv.className = 'searchterms';
		    searchTermDiv.innerHTML = summaryText;
		    textContainerNode.insertBefore(searchTermDiv, textContainerNode.childNodes[0]);
		}
	//}
  }
}

// Pull the search string out of the URL
/*
geekIT.string.GetSearchStringFromQS = function() {
  // Return sanitized search string if it exists
  var rawSearchString = geekIT.uri.GetValueFromQueryString(geekIT.constants.searchWordsQsVar);
  
  var rawSearchString = window.location.search.replace(/[a-zA-Z0-9\?\&\=\%\#]+s\=(\w+)(\&.*)?/,"$1");
  // Replace '+' with '|' for regex
  // Also replace '%20' if your cms/blog uses this instead (credit to erlando for adding this)
  return rawSearchString.replace(/\%20|\+/g,"\|");
}
*/

geekIT.string.HighlightTextNodes = function(element, regex, termid) {
  var tempinnerHTML = element.innerHTML;
  // Do regex replace
  // Inject span with class of 'highlighted termX' for google style highlighting
  element.innerHTML = tempinnerHTML.replace(regex,'>$1<span class="'+geekIT.constants.highlightCssClass+' term'+termid+'">$2</span>$3<');
}

// Highlight searched-for words (if any) on the page
geekIT.event.addEvent(window, 'load', geekIT.string.HighlightWordsOnPage);

   
/** URL & querystring functions
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.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/
	- domain: eg. www.google.com
	- path: the virtual path to the page, eg. apps/maps
	- page: the page name without the extension, eg. index
	- extension: the page file extension, eg. html
	- file: the page name including the extension, eg index.html
	- querystring: the querystring args, excluding the "?"
*/
geekIT.uri.getCurrentPageUri = function () {
	var uri = new Object();
	uri.directory = location.href.substring(0, location.href.lastIndexOf('\/'));
	uri.domain = uri.directory; 
	if (uri.domain.substr(0,7) == 'http:\/\/') uri.domain = uri.domain.substr(7);
	uri.path = ''; 
	var pos = uri.domain.indexOf('\/'); 
	if (pos > -1) {
	    uri.path = uri.domain.substr(pos+1); 
		uri.domain = uri.domain.substr(0,pos);
	}
	uri.page = location.href.substring(uri.directory.length+1, location.href.length+1);
	pos = uri.page.indexOf('?');
	if (pos > -1) { uri.page = uri.page.substring(0, pos); }
	pos = uri.page.indexOf('#');
	if (pos > -1) { uri.page = uri.page.substring(0, pos); }
	uri.extension = ''; 
	pos = uri.page.indexOf('.');
	if (pos > -1) {
	    uri.extension = uri.page.substring(pos+1); 
		uri.page = uri.page.substr(0,pos);
	}
	uri.file = uri.page;
	if (uri.extension != '') uri.file += '.' + uri.extension;
	if (uri.file == '') uri.page = 'index';
	uri.querystring = location.search.substr(1).split("?");
	return uri;
}

// Returns the site domain
geekIT.uri.domain = function() {
    var uri = new geekIT.uri.getCurrentPageUri();
	return uri.domain;
}

geekIT.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;
}

/*  
Puts the supplied parameter querystring into a array/hash of key/value pairs. If the optional parameter is missing it parses the current page's querystring.
Usage:  
    var qsArgs = geekIT.uri.GetQueryStringVariables();    
    alert(qsArgs[varName]);                                     // display single variable
    for (var arg in qsArgs) alert(arg + ' = ' + qsArgs[arg]);	// display all variables 
*/
geekIT.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;
}

geekIT.uri.GetValueFromQueryString = function(variableName) {
	var qsArgs = geekIT.uri.GetQueryStringVariables();
	if (qsArgs[variableName]) return qsArgs[variableName];
	else return '';
}


/** Form & Form-Field functions
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.form");


// Stores a reference to the page's "default form" (which will be submitted if the user presses the "Enter" key)
geekIT.form.defaultForm = null;

// This is used to register a partcular page's default form 
geekIT.form.setDefaultForm = function(frm)
{
	// If no form was supplied, use the first one found on the page.
	if (!frm) frm = document.forms[0];
	geekIT.form.defaultForm = frm;
}

/** Form-Field functions
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.form.field");

// Limit textarea fields to a maximum number of chars.
geekIT.form.field.setMaxChars = function (field, maxChars) 
{
	if (field.value.length > maxChars) field.value = field.value.substring(0, maxChars);
}


/** AJAX methods
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.ajax");

// Global xmlHttp object
geekIT.ajax.xmlHttpObject = null;

geekIT.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;
}

geekIT.ajax.GetUrl = function(url, callbackFunction)
{
	geekIT.ajax.xmlHttpObject = geekIT.ajax.GetXmlHttpObject();
	if (geekIT.ajax.xmlHttpObject == null)
	{
		alert ("Your browser does not support AJAX!");
		return;
	}
	geekIT.ajax.xmlHttpObject.onreadystatechange = callbackFunction;
	geekIT.ajax.xmlHttpObject.open("GET", url, true);
	geekIT.ajax.xmlHttpObject.send(null);	
}

/** Image functions - preloads etc.
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.image");

// A global array to store the source of images that need preloading.
geekIT.image.preloads = new Array();

// Write each image from the preloadedImages() array into a hidden container in the page footer. 
geekIT.image.preloadImages = function()
{
	var container = document.getElementById("preloadedImages") // in the page footer
	if (document.createElement && container && geekIT.image.preloads)
	{
		for	(var i = 0; i < geekIT.image.preloads.length; i++)
		{
			var img = document.createElement('img');
			img.setAttribute('src', geekIT.image.preloads[i]);
			container.appendChild(img);
		}
	}
}

//geekIT.event.addEvent(window, 'load', geekIT.image.preloadImages);


/** Client Project Brief methods
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.Projects");

geekIT.Projects.SaveAndContinue = function(nextPageNumber)
{
	document.forms['frmProject'].elements['nextPageNumber'].value = nextPageNumber;
	document.forms['frmProject'].submit();
}


/** Miscellaneous functions (eg. domain/business rules, functions unlikely to be reused on other sites)
------------------------------------------------------------------ */
_global_["@namespace"]("geekIT.misc");

// Check whether a field is empty, and set it's CSS class name accordingly
geekIT.misc.fieldIsEmpty = function(field)
{
	var isEmpty = false;
	if (!geekIT.string.hasValue(field.value)) 
	{
		isEmpty = true;
		field.className = 'error';
	}
	else 
		field.className = 'ok';
	return isEmpty;
}


// Returns true if an email address is a yahoo, hotmail, gmail, msn, inbox, aim etc. one. 
geekIT.misc.isFreeEmailAccount = function (email) {
	// trim the last letter 'm' to catch variants such as 'yahoo.com', 'yahoo.com.au', 'yahoo.co.uk'
	var freeDomains = new Array("yahoo.co", "gmail.co", "hotmail.co", "msn.co", "ninemsn.co", "inbox.co", "aim.co", "live.co", "mail.co", "msn.co");
	var domain = geekIT.string.emailDomain(email);
	var isFreeDomain = false;
	for (var i=0; !isFreeDomain && i < freeDomains.length; i++)
		if (domain.toLowerCase().indexOf(freeDomains[i]) > -1) isFreeDomain = true;
	return isFreeDomain;
}
