/* Load
------------------------------*/
var Event = {	
	onload: [],
	loaded: function() {
		if (arguments.callee.done) return;
		arguments.callee.done = true;
		for (i = 0;i < Event.onload.length;i++) Event.onload[i]();
	},
	pageLoad : function(func) {
		var oldonload = window.onload;
		if (typeof window.onload != "function") {
			window.onload = func;
		} else {
			window.onload = function() {
				oldonload();
				func();
			}
		}
	},
	domLoad : function(fireThis) {
		this.onload.push(fireThis);
		if (document.addEventListener) 
			document.addEventListener("DOMContentLoaded", Event.loaded, null);
		if (/KHTML|WebKit/i.test(navigator.userAgent)) { 
			var _timer = setInterval(function() {
				if (/loaded|complete/.test(document.readyState)) {
					clearInterval(_timer);
					delete _timer;
					Event.loaded();
				}
			}, 10);
		}
		/*@cc_on @*/
		/*@if (@_win32)
		var proto = "src='javascript:void(0)'";
		if (location.protocol == "https:") proto = "src=//0";
		document.write("<scr"+"ipt id=__ie_onload defer " + proto + "><\/scr"+"ipt>");
		var script = document.getElementById("__ie_onload");
		script.onreadystatechange = function() {
		    if (this.readyState == "complete") {
		        Event.loaded();
		    }
		};
		/*@end @*/
		this.pageLoad(Event.loaded);
	},
	add: function(e, type ,fn) {
		if (e.attachEvent) {
		e['e' + type + fn] = fn;
		e[type + fn] = function() {e['e' + type + fn](window.event);}
		e.attachEvent('on' + type, e[type + fn]);
		} else
		e.addEventListener(type, fn, false);
	},
	remove: function(e, type, fn) {
		if (e.detachEvent) {
		e.detachEvent('on' + type, e[type + fn]);
		e[type + fn] = null;
		} else
		e.removeEventListener(type, fn, false);
	}
};

/* Utils
 * Commonly used methods
------------------------------*/

// Empty an element
function emptyElement(e) {
	while (e.firstChild) {
		e.removeChild(e.firstChild);
	}
}

// Insert element after a node as next sibling
function insertAfter(node, referenceNode) {
	var parent = referenceNode.parentNode;
	parent.insertBefore(node, referenceNode.nextSibling);
}

/* URL
------------------------------*/
var UrlUtils = {
	qs : function(param) {
		var url = location.href;
		if (url.indexOf("?") != -1) {
			var qs = url.substring(url.indexOf("?") + 1);
			var pairs = qs.split("&");
			var hash = [], key, value, pair;
			for (var i = 0, c = pairs.length; i < c; i++) {
				pair = pairs[i].split("=");
				if (param && param == pair[0]) {
					return pair[1].toString();
				}
				hash[pair[0]] = pair[1];
			}
			if (hash.length > 0) {
				return hash;
			} else {
				return null;
			}
		}
	},
	newURL : function(url, keys, values) {
		var link = url;
		if (keys && values) {
			var qs = "";
			for (var i = 0, c = keys.length; i < c; i++) {
				qs += "&" + encodeURIComponent(keys[i]) + "=" + encodeURIComponent(values[i]);
			}
			qs = "?" + qs.substring(1, qs.length);
		}
		return link + qs
	},
	redirect : function(url) {
		self.location.href = url;
	},
	replaceValue : function(url, prop, value) {
		if (url.indexOf(prop) > 0) {
			var firstPart = url.substring(0, url.indexOf(prop) + prop.length + 1);
			var secondPart = url.substring(url.indexOf(prop) + prop.length + 1);
			if (secondPart.indexOf("&") > 0) {
				secondPart = secondPart.substring(secondPart.indexOf("&"));
				return firstPart + encodeURIComponent(value) + secondPart;
			} else {
				return firstPart + encodeURIComponent(value);
			}
		} else {
			return null;
		}
	}
};

/* Pop windows and new pages
------------------------------*/
var PopUp = {
	topPos : 0,
	leftPos : 0,
	height : 400,
	width : 600,
	settings : null,
	win : null,
	winName : "pop",
	getURL : function(e) {
		if (typeof(e) == "object") {
			return e.href
		} else {
			return e;
		}
	},
	win : null,
	// Opens a new browser window
	newWindow : function(e, options) {
		return this.openWindow(e, {popup: "window"});
	},
	// Opens a pop up window
	newPopUp : function(e, options) {
		if (options) {
			options.popup = "popup";
		} else {
			options = {popup: "popup"};
		}
		return this.openWindow(e, options);
	},
	// General new window 
	openWindow : function(e, options) {
		if (options) {
			this.height = (options.height) ? options.height : this.height;
			this.width = (options.width) ? options.width : this.width;
		}
		this.leftPos = (screen.width) ? (screen.width - this.width) / 2 : 0;
		this.topPos = (screen.height) ? (screen.height - this.height) / 2 : 0;

		this.settings = (options && options.popup == "popup") ? "height=" + this.height + ",width=" + this.width + ",top=" + this.topPos + ",left=" + this.leftPos + ",scrollbars=yes,noresize" : "";

		var link = this.getURL(e);

		this.win = window.open(link, this.winName, this.settings);
		this.win.focus();
		return false;
	},
	// Finds links that have a rel attribute of value and applies a function to them
	hookup : function(value, func) {
		var items = document.getElementsByTagName("a");
		for (var i = 0, c = items.length; i < c; i++){
			if (items[i].getAttribute("rel") == value) {
				items[i].onclick = func;
			}
		}
	}
};

/* Forms
------------------------------*/
var FormUtils = {	
	preselectDropDown : function(e, v) {
		for (var i = 0, c = e.options.length; i < c; i++) {    
			if (e.options[i].value == v) {
				e.options[i].selected = true;
				break;
			}
		}
	},
	assignButton : function(e, el, buttonId) {
		var code;
		if (window.event) {
		code = e.keyCode;
		} else if (e.which) {
			code = e.which;
		}
		if (code == 13) {
			var button = document.getElementById(buttonId);
			if (button) {
				button.focus();
				return false;
			}
		}
		return true;
	},
	queryString : "",
	addQueryString : function(param, value) {
		var preffix = (this.queryString.length > 0) ? "&" : "" ;
		this.queryString += preffix + encodeURIComponent(param) + "=" + encodeURIComponent(value);
	},	
	// If ID of input is not know use the name
	getOption : function(el, container, collectValues) {
		var wrapper = (!container || container == 'document') ? document : document.getElementById(container);
		var input = wrapper.getElementsByTagName("input");
		for (var i = 0, c = input.length; i < c; i++) {
			if (input[i].name && input[i].name == el) {
				return this.getValue(input[i].id, container, collectValues)
			}
		}	
	},
	// Assign querystring params with either array list of id's or container id (group/name for radio buttons)
	// The container is optional for an array of id's - it helps narrow down the search for radio button groups
	collect : function(collection, container) {
		this.queryString = "";
		var container;
		if (typeof(collection) == 'object') {
			container = (!container || container == 'document') ? document : document.getElementById(container);
			for (var i = 0, c = collection.length; i < c; i++) {
				var el = document.getElementById(collection[i]);
				if (el) {
					this.getValue(el, container);	
				}
			}
		} else {
			container		= document.getElementById(collection);
			var inputItem	= container.getElementsByTagName("input");
			var selectItem	= container.getElementsByTagName("select");	
			var textItem	= container.getElementsByTagName("textarea");
			
			for (var i = 0, c = inputItem.length; i < c; i++) {
				this.getValue(inputItem[i], container, true);	
			}
			for (var i = 0, c = selectItem.length; i < c; i++) {
				this.getValue(selectItem[i], container, true);	
			}
			for (var i = 0, c = textItem.length; i < c; i++) {
				this.getValue(textItem[i], container, true);	
			}
		}
		return this.queryString;
	},
	// Gets a form elements and adds the value and if onto the params
	getValue : function(el, container, collectValues) {	
		el = (typeof(el) == "string") ? document.getElementById(el) : el;
		container = (!container || container == 'document') ? document : document.getElementById(container);
		var n = el.id, v = null;
	
		switch (el.nodeName.toLowerCase()) {
			case 'input':
				switch (el.getAttribute('type').toLowerCase()) {
					case 'text':
						v = el.value;
					break;
					case 'checkbox':
						if (el.checked) {
							v = el.value;
						}
					break;
					case 'radio':
						n = el.name;
						var button = container.getElementsByTagName('input');
						for (var j = 0, d = button.length; j < d; j++) {
							if (button[j].name == el.name && button[j].checked) {
								v = button[j].value;
								break;
							}
						}	
					break;
					case 'password':
						v = el.value;
					break;
					case 'hidden':
						v = el.value;
					break;
				}
			break;
			case 'select':
				if (el.multiple) {
					l = [];
					for (var j = 0, d = el.length; j < d; j++) {
						if (el.options[j].selected) {
							l.push(el.options[j].value);
						}
					}
					v = l.join('|');
				} else {
					v = el.value;
				}
			break;
			case 'textarea':
				v = el.value;
			break;
		}
		if (n != null && n != '' && v != null && v != '') {
			if (collectValues) {
				this.addQueryString(n, v);
			} else {
				return v;
			}
		}
	}
};

/*	Cookies - yum
 *	Can use single short methods, or for long values use a splitter
------------------------------ */
var Cookie = {
	maxLength : 3000,
	splitter : '||',
	get : function(name) {
		return this.getValues(name + '_0', true);	
	},
	getValues : function(name, split) {
		var cookie = this.getValue(name);
		if (cookie) {
			var splitterLength = this.splitter.length;
			var splitter = cookie.indexOf(this.splitter);
			if (splitter > 0) {
				return cookie.substr(0, splitter - 1) + this.getValues(cookie.substr(splitter + splitterLength), true);
			} else {	
				return cookie;
			}
		}
	},
	getValue : function(name) {
		var arg = name + "=";
		var alen = arg.length;
		var clen = document.cookie.length;
		var i = 0;
		while (i < clen){
			var j = i + alen;
			if (document.cookie.substring(i, j) == arg){
				return this.getOffset(j);
			}
			i = document.cookie.indexOf(" ", i) + 1;
			if (i == 0) break;
		}
		return null;
	},
	getOffset : function(offset) {
		var endstr = document.cookie.indexOf (';', offset);
		if (endstr == -1)
		endstr = document.cookie.length;
		return unescape(document.cookie.substring(offset, endstr));
	},
	set : function(name, value) {
		var tray = [];
		for (var i = 0, count = value.length; i < count; i += this.maxLength) {
			if ((i + this.maxLength) > count) {
				tray.push(value.substr(i));
			} else {
				tray.push(value.substr(i, this.maxLength + 1));
			}
		}
		var bite;
		for (var i = 0, count = tray.length; i < count; i++) {
			bite =  (i + 1 != count) ? this.splitter + name + '_' + (i + 1) : '';
			this.setValue(name + '_' + i, tray[i] + bite);
		}
	},
	setValue : function(name, value) {
		var never = new Date();
		never.setTime(never.getTime() + 2000 * 24 * 60 * 60 * 1000);
		var expString = '; expires=' + never.toGMTString();
		var newpath = '; path=/';
		document.cookie = name + '=' + escape(value) + expString + newpath;
	},
	kill : function(name) {
		var expString = '; expires=Thu, 01-Jan-1970 00:00:01 GMT';
		var newpath = '; path=/';
		document.cookie = name + '=' + '' + expString + newpath;
	}
};

/* Ajax Tools
------------------------------*/
var AjaxUtils = {
	busy : { // Site-wide generic loader
		defaultId : "ajax-load",
		init : function(loadId) {
			var load		= document.createElement('div');
			load.className	= 'ajax-load';
			load.id			= (loadId) ? loadId : AjaxUtils.busy.defaultId;
			return load;
		},
		kill : function(loadId) {
			loadId = (loadId) ? loadId : AjaxUtils.busy.defaultId;
			var load = document.getElementById(loadId);
			if (load) {
				load.parentNode.removeChild(load);
			}
		},
		button : function(e) {
			if (/-o.gif/.test(e.src)) {
				e.src = e.src.replace("-o.gif", ".gif");
			} else {
				e.src = e.src.replace(".gif", "-o.gif");
			}
		}
	},
	freeze : function() { // Prevent links from being clickable on the enitre page while Ajax is busy
		if (document.body.onclick && typeof(document.body.onclick) === 'function') {
			document.body.onclick = '';
		} else {
			document.body.onclick = function() {
				return false;
			};
		}
	},
	unfreeze : function() {
		this.freeze();
	},
	access : {
		preferences : null,
		readerCheck : null,
		readerElem : null,
		init : function() {
			this.getPreferences();
			this.readerElem = document.getElementById('txtAjaxPrefReader');
			if (this.preferences) {
				this.readerElem.checked = this.preferences.assisted;
			}
		},
		reader : function(t) {
			this.getPreferences();
			if (this.preferences) {
				Debug.w("Ajax preferences are set");
				this.readerCheck = this.preferences.assisted;
				Debug.p('Reader enabled' , this.preferences.assisted);
				this.readerElem.checked = this.preferences.assisted;
			} else {
				Debug.w("Ajax preferences are not set - using form");
				// If no cookie, check the selection
				this.readerCheck = (this.readerElem && this.readerElem.checked) ? true : false;
			}
			
			if (this.readerCheck) {
				// Currently, alert seems the best way to inform screen readers
				alert('Update - ' + t);
			}
		},
		setPreferences : function(p, v) {
			Cookie.setValue('preferences', "{'" + p + "' : " + v.checked + "}");
			if (p === 'assisted') {
				this.readerCheck = new Boolean(v.checked);
			}
		},
		getPreferences : function() {
			this.preferences = Cookie.getValue('preferences');
			Debug.p('Ajax cookie', this.preferences);
			this.preferences = Cookie.toJson(this.preferences);
		},
		killPreferences : function() {
			Cookie.kill('preferences');
		},
		debugPreferences : function() {
			this.getPreferences();
		}
	}
};

/* Ajax Cache
------------------------------*/
var AjaxCache = {
	length : 0,
	hash : [],
	set : function(key, data) {
		if (this.hash[key]) {
			Debug.p("Ajax cache exists", key);
			return false;
		} else {
			Debug.p("Ajax cache adding new", key);
			this.hash[key] = data;
			this.length++;
			return true;
		}
	},
	get : function(key) {
		var data = this.hash[key]
		if (data) { 
			Debug.p("Ajax cache exists", key);
			return data;
		} else {
			Debug.p("Ajax cache does not exist", key);
			return null;
		}
	}	
};

/* Main Ajax class
------------------------------*/
function Ajax(url, param, output) {
	if (url) {
		this.set(url, param, output);
	}
}
Ajax.prototype.set = function(url, param, output) {
	if (!document.getElementById) { return; }
	this.debug = false;
	this.param = '';
	this.method = 'GET';
	this.req = null;
	this.timeoutDuration = 1000000;
	this.timeCount = false;
	this.timeExpired = false;
	this.response = null;
	this.rawUrl = url;
	this.output = (document.getElementById(output)) ? document.getElementById(output) : document.body;
	if (typeof(url) == 'object') { // Setup fallback in call from link or button 
		if (url.href) {
			this.url = url.href;
			this.form = false;
		} else {
			this.form = true;
		}
	} else if (typeof(url) == 'string') {
		this.url = url;
	}
	if (this.url.indexOf('?') != -1) {
		var qIndex = this.url.indexOf('?') + 1;
		var qs = this.url.substr(qIndex);
		this.url = this.url.substr(0, qIndex);
		this.addParam(qs);
	}
	this.addParam(param);
};
Ajax.prototype.get = function() {	
	Debug.write('Get Ajax response');
	var ajax = this; // Show object to privileged function
	this.req = this.getXHR();
	if (!this.req) { this.fail(); }

	if(this.debug) { alert("urlparam = " + this.addUrlParam(this.url, this.param)); };

	Debug.write("URL + Param = " + this.addUrlParam(this.url, this.param));
	this.req.open(this.method, this.addUrlParam(this.url, this.param), true);
	this.req.setRequestHeader('If-Modified-Since', 'Wed, 02 Nov 2006 00:00:00 GMT');
	this.req.setRequestHeader('Connection', 'close');

	this.req.onreadystatechange = function() {
		var loader = ajax; // Show object to privileged function
		if (loader.req.readyState == 1) {
			loader.timeCount = window.setTimeout(function() {
				if (loader.req.readyState == 1) {
					loader.timeExpired = true;
					loader.req.abort();
					loader.timeout();
				}
			}, loader.timeoutDuration);
			loader.busy();
		}
		if (loader.req.readyState == 4 && !loader.timeExpired) {
			window.clearTimeout(loader.timeCount);
			Debug.write('Ajax page status = ' + loader.req.status);
			if (/200|304/.test(loader.req.status)) {
				loader.response = loader.req.responseText;
				loader.complete();
			} else {
				loader.fail();
			}
		}
	};	
	Debug.write('Ajax URL = ' + this.url);
	Debug.write('Ajax querystring = ' + this.param);
	if (this.method == 'POST') {
		this.req.send(this.param);
	} else {
		this.req.send(null);
	}
};

Ajax.prototype.getXHR = function() { // XHR object
	Debug.write('Get XHR');
	try {
		return new XMLHttpRequest();	
	}
	catch(error) {
		try {
			return new ActiveXObject('Microsoft.XMLHTTP');
		}
		catch(error) {
			return null;
		}
	}
};

Ajax.prototype.setParam = function(param) {
	this.param = null;
	this.addParam(param);
};

Ajax.prototype.addParam = function(param, paramValue) { // URL encode and add params
	if (param == null || param == '') { return; }
	if (typeof(param) == 'object') {
		for (var value in param) {
			this.param += "&" + encodeURIComponent(value) + "=" + encodeURIComponent(param[value]);
		}
	} else if (typeof(param) == 'string') {
		if (paramValue) {
			this.param += "&" + encodeURIComponent(param) + "=" + encodeURIComponent(paramValue);
		} else {
			this.param += "&" + param;
		}
	}
};

Ajax.prototype.removeParam = function(param) {
	var reg = new RegExp(param);
	var params = this.param.split('&');
	var newParams = '';
	for (var i = 0, c = params.length; i < c; i++) {
		if (!reg.test(params[i])) {
			newParams += '&' + params[i];
		}
	}
	this.param =  newParams.substr(1);
};

Ajax.prototype.addUrlParam = function(url, param) { // Add URL and params together
	if (url.indexOf('?') == -1) {
		if (param.charAt(0) == "&") {
			param = param.substring(1);
		}
		return url + '?' + param;
	} else {
		if (param.charAt(0) == "&") {
			param = param.substring(1);
		}
		return url + param;
	}
};

Ajax.prototype.toJson = function(s) {
	if (!s) {
		s = this.response;
	}
	return eval("(" + s + ")");
};

Ajax.prototype.complete = function() { // Default received ajax response
	Debug.write('Ajax complete');
	var t = document.createTextNode(this.req.responseText);
	this.output.appendChild(t);
};

Ajax.prototype.busy = function() { // While waiting for response
	Debug.write('Ajax busy');
	var t = document.createTextNode("Busy");
	this.output.appendChild(t);
};

Ajax.prototype.fail = function() { // If there is an error	
	Debug.write('Ajax fail = ' + this.req.responseText);
	var t = document.createTextNode("Fail");
	this.output.appendChild(t);
	this.fallback();
};

Ajax.prototype.timeout = function() { // If the response times out
	Debug.write('Ajax timeout');
	var t = document.createTextNode("Timeout");
	this.output.appendChild(t);
	this.fallback();
};

Ajax.prototype.fallback = function() { // Action if AJAX fails
	Debug.write('Ajax fallback');
	var t = document.createTextNode("Fallback");
	this.output.appendChild(t);
	if (this.form) {
		//document.form[0].submit();
	} else {
		//window.location = this.url;
	}
};

/*	Debug
------------------------------ */
var Debug = {
	release : !Config.debug,
	showAlert : false,
	console : null,
	lineCount : 1,
	init : function() {
		this.console = document.getElementById('console');
		if (!this.console) {
			var debug = document.createElement('div');
			debug.id = 'debug';
			this.console = document.createElement('div');
			this.console.id = 'console';

			var togglePara = document.createElement('p');
			togglePara.id = 'debug-toggle';
			var toggle = document.createElement('a');
			toggle.innerHTML = 'Debug - Close';
			toggle.href = '#';
			toggle.onclick = function() {
				return Debug.toggle(this);
			};
			togglePara.appendChild(toggle);
			debug.appendChild(togglePara);
			debug.appendChild(this.console);
			document.body.appendChild(debug);
		}
	},
	w : function(t, tabCount) {
		this.write(t, tabCount);
	},
	writeLine : function(t, tab) {
		if (this.release) { return; }
		this.console = document.getElementById('console');
		if (!this.console) {
			this.init();
		}
		var tab = '';
		if (tabCount) {
			tab = ' tab-' + tabCount;
		}

		var para = document.createElement('p');
		para.className = (this.lineCount % 2) ? 'alternate' + tab : '' + tab;
		var line = document.createTextNode(t);
		para.appendChild(line);
		if (this.console.firstChild) {
			this.console.insertBefore(para, this.console.firstChild);
		} else {
			this.console.appendChild(para);
		}
		this.lineCount ++;
	},
	write : function(t, tabCount) {
		if (this.release) { return; }
		this.console = document.getElementById('console');
		if (!this.console) {
			this.init();
		}
		var tab = '';
		if (tabCount) {
			tab = ' tab-' + tabCount;
		}

		var para = document.createElement('p');
		para.className = (this.lineCount % 2) ? 'alternate' + tab : '' + tab;
		var line = document.createTextNode(t);
		para.appendChild(line);
		if (this.console.firstChild) {
			this.console.insertBefore(para, this.console.firstChild);
		} else {
			this.console.appendChild(para);
		}
		this.lineCount ++;
	},
	alert : function(t) {
		if (!this.release && this.showAlert) {
			alert(t);
		}
	},
	p : function(p, t, tabCount) {
		if (this.release) { return; }
		this.console = document.getElementById('console');
		if (!this.console) {
			this.init();
		}
		var tab = '';
		if (tabCount) {
			tab = ' tab-' + tabCount;
		}
		var para = document.createElement('p');
		para.className = (this.lineCount % 2) ? 'alternate' + tab : '' + tab;

		var prop = document.createElement('strong');
		var propText = document.createTextNode(p + ' - ');
		prop.appendChild(propText);
		para.appendChild(prop);

		var line = document.createTextNode(t);
		para.appendChild(line);
		if (this.console.firstChild) {
			this.console.insertBefore(para, this.console.firstChild);
		} else {
			this.console.appendChild(para);
		}
		this.lineCount ++;
	},
	a : function(a) {
		var t;
		for(var i = 0, c = a.length; i < c; i++) {
			t += a[i] + ', ';
		}
		this.p('Array', t);
	},
	ex : function(t, tabCount) {
		if (this.release) { return; }
		this.console = document.getElementById('console');
		if (!this.console) {
			this.init();
		}
		var tab = '';
		if (tabCount) {
			tab = ' tab-' + tabCount;
		}

		var para = document.createElement('p');
		para.className = (this.lineCount % 2) ? 'alternate' + tab : '' + tab;
		
		para.innerHTML = t;
		if (this.console.firstChild) {
			this.console.insertBefore(para, this.console.firstChild);
		} else {
			this.console.appendChild(para);
		}
		this.lineCount ++;
	},
	toggle : function(e) {
		if (this.console.style.display == 'none') {
			this.console.style.display = 'block';
			e.innerHTML = 'Debug - Close';
		} else {
			this.console.style.display = 'none';
			e.innerHTML = 'Debug - Open';
		}
		return false;
	}
};
window.onerror = function(a, b, c) {
	if (!Debug.release) {
		Debug.ex('Exception error:' + a + ' <br />File: ' + b + ' <br />Line: ' + c);
		return true;
	} else {
		return false;
	}	
};
