/* CORE SCRIPTS
 * Required functionality
 * 1.0
 
 * SCRIPT CHANGES (Eg. Date (dd/mm/yyyy), Name (Tom.McCourt), Change (function name))
 *
 * 13/07/2007, Tom.McCourt, Created
------------------------------------------------------------*/

/* Migration to new namespace
------------------------------*/
var Core = {};

Core.Image = {
	cache: [],				
	cacheProgress: 0,		
	cacheLength: 0,			
	cacheCallback: null,	
	cacheError: [],		
	_load: function(a) {
		var i = new Image(), o = this;
		i.onload = function() {
			Core.Image._loadComplete.call(o);
		}
		i.onerror = function() {
			Core.Image.cacheError[Core.Image.cacheError.length] = o;
			Core.Image._loadComplete.call(o);
		};
		i.onabort = function() {
			Core.Image.cacheError[Core.Image.cacheError.length] = o;
			Core.Image._loadComplete.call(o);
		};
		i.src = a;
		this.cache[this.cache.length] = i;
	},
	preload: function(a, f) {
		this.cacheProgress = 0;
		this.cacheCallback = f;
		if (typeof(a) == "string") {
			this.cacheLength = 1;
			this._load(a);
		} else {
			this.cacheLength = a.length;
			for (var i = 0; i < this.cacheLength; i++) {
				this._load(a[i]);
			}
		}
	},
	_loadComplete: function() {
		this.cacheProgress++;
		if (this.cacheProgress == this.cacheLength) {
			if (this.cacheCallback) {
				this.cacheCallback.call(this);
			}
		}
	},
	swap: function(e, el, cache) {
		// Only gif for now - will add other types
		var s = el.src, t = el.src.replace(".gif", "-o.gif");
		
		// Preload the image if required (true by default)
		if (typeof(cache) == "undefined" || cache) {
			this.preload(t);
		}

		// Do the mouseover events
		e.onmouseover = function() {
			el.src = t;
		}
		e.onmouseout = function() {
			el.src = s;
		}
	}
};

var Site = {
	Pages: {}
};

Site.Pages.Home = {
	Merchandising: {
		list: null, // The merchandising list from CMS
		init: function() {
			var content = document.getElementById("content");
			if (content) {
				this.list = content.getElementsByTagName("ul")[0];
			}
			if (this.list) {
				var items = this.list.getElementsByTagName("a");
				for (var i = 1, c = items.length; i < c; i++) {
					var img = items[i].getElementsByTagName("img")[0];
					if (img) {
						Core.Image.swap(img, img, true);
					}
				}
			}
		}
	}
};

/* Utils
 * Commonly used methods
------------------------------*/

// Empty an element
function emptyElement(e) {
	while (e.firstChild) {
		e.removeChild(e.firstChild);
	}
}

/* URL
------------------------------*/
var UrlUtils = {
	protocol : function() {
		var url = location.href;
		return url.substring(0, url.indexOf("://"));
	},
	absoluteWebPath : function() {
		if (this.protocol().toLowerCase() == "https") {
			return Config.absoluteHttpsPath;
		} else {
			return Config.absoluteHttpPath;
		}
	},
	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
	},
	timedRedirect : function(url, t) {
		self.setTimeout("self.location.href = '" + url + "';",t * 1000);
	}
};

/* Controlling position
------------------------------*/
var Position = {
	getElement : function(e) {
		if (typeof(e) == "string") {
			return document.getElementById(e);
		} else if (typeof(e) == "object") {
			return e;
		} else {
			return null;
		}
	},
	getLeft : function(e) {
		e = this.getElement(e);
		var curLeft = 0;
		if (e.offsetParent) {
			while (e.offsetParent) {
				curLeft += e.offsetLeft
				e = e.offsetParent;
			}
		} else if (e.x) {
			curLeft += e.x;
		}
		return curLeft;
	},
	getTop : function(e) {
		e = this.getElement(e);
		var curTop = 0;
		if (e.offsetParent) {
			while (e.offsetParent) {
				curTop += e.offsetTop
				e = e.offsetParent;
			}
		} else if (e.y) {
			curTop += e.y;
		}
		return curTop;
	},
	// e (object) - the element you want to position
	// el (object) - the element you want to anchor another element to
	// options (object) - options e.g. {"offsetX": 10, "offsetY": 50}
	// Position.anchor("basket-message", "add-to-basket", {"offsetX": 10, "offsetY": 50});
	anchor : function(e, el, options) {
		e = this.getElement(e);
		el = this.getElement(el);

		var elY = this.getTop(el);
		var elX = this.getLeft(el);

		if (e && el) {
			e.style.top			= (options.offsetY) ? options.offsetY + elY + "px" : elY + "px";
			e.style.left		= (options.offsetX) ? options.offsetX + elX + "px" : elX + "px";

			if (options.position) e.style.position	= options.position;
		}
	},
	// e (object) - the element you want to position
	// options (object) - options e.g. {"top": Position.getTop("add-to-basket"), "offsetX": 10, "offsetY": 50}
	// Position.anchor("basket-message", "add-to-basket", {"offsetX": 10, "offsetY": 50});
	position : function(e, options) {
		if (e) {
			if (options.top) e.style.top			= (options.offsetY) ? options.offsetY + options.top + "px" : options.top + "px";
			if (options.right) e.style.right		= (options.offsetX) ? options.offsetX + options.right + "px" : options.right + "px";
			if (options.bottom) e.style.bottom		= (options.offsetY) ? options.offsetY + options.bottom + "px" : options.bottom + "px";
			if (options.left) e.style.left			= (options.offsetX) ? options.offsetX + options.left + "px" : options.left + "px";
			if (options.position) e.style.position	= options.position;
			//Debug.w("Position: " + e.id + ", top: " + options.top + ", right: " + options.right + ", bottom: " + options.bottom + ", left: " + options.left);
		}
	}
};

/* Pop windows and new pages
------------------------------*/
var PopUp = {
	topPos : 0,
	leftPos : 0,
	height : 480,
	width : 700,
	settings : null,
	win : null,
	winName : "pop",
	getURL : function(e) {
		if (typeof(e) == "object") {
			return e.href
		} else {
			return e;
		}
	},
	win : null,
	newWindow : function(e, options) {
		return this.openWindow(e, {popup: "window"});
	},
	newPopUp : function(e, options) {
		if (options) {
			options.popup = "popup";
		} else {
			options = {popup: "popup"};
		}
		return this.openWindow(e, options);
	},
	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;
	},
	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;
			}
		}
	},
	getVariants : function(objectname) {
		var wrapper = document;
		var input = wrapper.getElementsByTagName("input");
		var cbvalues = "";
		for (var i = 0, c = input.length; i < c; i++) {
			if (input[i].name && input[i].name == objectname && input[i].checked) {
				cbvalues += input[i].value + ";";
			}
		}
		if (cbvalues.charAt(cbvalues.length-1) == ';')
			cbvalues = cbvalues.substring(0, cbvalues.length-1);
		
		return cbvalues;
	},
	assignButton : function(e, buttonId) {
		var code;
		if (!e) {
			e = window.event
		}
		if (e.keyCode) {
			code = e.keyCode;
		}
		else if (e.which) {
			code = e.which;
		}
		if (code == 13) {
			var button = document.getElementById(buttonId);
			if (button) {
				button.focus();
				button.Click();
				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();
		}
	}
};

/* 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.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);
	}
	//alert("new url = " + url.href);
	this.addParam(param);
};
Ajax.prototype.get = function() {	
	Debug.w('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.w("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.w('Ajax page status = ' + loader.req.status);
			if (/200|304/.test(loader.req.status)) {
				loader.response = loader.req.responseText;
				loader.complete();
			} else if(/404|500|302/.test(loader.req.status)) {
				// If the response is errored or not found
				this.error();
			} else {
				loader.fail();
			}
		}
	};	
	Debug.w('Ajax URL = ' + this.url);
	Debug.w('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.w('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);
			//alert(param);
		}
		return url + '?' + param;
	} else {
		if (param.charAt(0) == "&") {
			param = param.substring(1);
			//alert(param);
		}
		//alert("char = " + url + param);
		return url + param;
	}
};

Ajax.prototype.toJson = function(s) {
// If not using own Json string, use the one returned by the Xhr
	s = (!s) ? this.response : s;

	// Check for correctness
	if (s && s.length > 0) {
		// Try to convert to Json
		try {
			return eval("(" + s + ")");
		} catch(e) {
			// Return undefined for failed Json 
			return undefined;
		}
	} else {
		// Return null for empty Json
		return null;
	}
};

Ajax.prototype.complete = function() { // Default received ajax response
	Debug.w('Ajax complete');
	var t = document.createTextNode(this.req.responseText);
	this.output.appendChild(t);
};

Ajax.prototype.busy = function() { // While waiting for response
	Debug.w('Ajax busy');
	if (Config.debug) {
		var t = document.createTextNode("Busy");
		this.output.appendChild(t);
	}
};

Ajax.prototype.error = function() { // If it goes wrong
	Debug.w('Ajax error');
	if (Config.debug) {
		var t = document.createTextNode("Error");
		this.output.appendChild(t);
	}
};


Ajax.prototype.fail = function() { // If there is an error	
	Debug.w('Ajax fail = ' + this.req.responseText);
	if (Config.debug) {
		var t = document.createTextNode("Fail");
		this.output.appendChild(t);
	}
	this.fallback();
};

Ajax.prototype.timeout = function() { // If the response times out
	Debug.w('Ajax timeout');
	if (Config.debug) {
		var t = document.createTextNode("Timeout");
		this.output.appendChild(t);
	}
	this.fallback();
};

Ajax.prototype.fallback = function() { // Action if AJAX fails
	Debug.w('Ajax fallback');
	if (Config.debug) {
		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() {
		// Check if console exists
		this.console = document.getElementById("console");
		if (!this.console) {
			// Create console
			var debug = document.createElement("div");
			debug.id			= "debug";
			this.console		= document.createElement("div");
			this.console.id		= "console";

			// Create control paragraph
			var togglePara		= document.createElement("p");
			togglePara.id		= "debug-toggle";
			
			// Create hide/show link
			var toggle			= document.createElement("a");
			toggle.innerHTML	= "Debug - Close";
			toggle.href			= "#";
			toggle.onclick		= function() {
				return Debug.toggle(this);
			};
			
			// Create clear link
			var clear			= document.createElement("a");
			clear.innerHTML		= "Clear";
			clear.href			= "#";
			clear.className		= "clear-debug";
			clear.onclick		= function() {
				return Debug.clear(this);
			};
			
			// Add the elements together
			togglePara.appendChild(toggle);
			togglePara.appendChild(clear);
			debug.appendChild(togglePara);
			debug.appendChild(this.console);
			document.body.appendChild(debug);
		}
	},
	clear : function(e) {
		this.console.innerHTML = "";
	},
	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 ++;
	},
	w : function(t, tabCount) {
		if (this.release) { return; }
		this.console = document.getElementById('console');
		if (!this.console) {
			this.init();
		}
		var tab = '';
		if (tabCount) {
			tab = ' tab-' + tabCount;
		}
		
		if (this.w.caller) {
			var callHolder = document.createElement("div");
			callHolder.className = "caller";
			var para = document.createElement("p");
			var line = document.createTextNode(t);
			para.innerHTML = "<strong><em>&#x2191;</em> " + this.w.caller.toString().substring(0, 60) + "...</strong><a href=\"#\" onclick=\"return Debug.caller(this, 'caller-" + this.lineCount + "')\">Show</a>";
			
			
			var paraFunction = document.createElement("p");
			paraFunction.id = "caller-" + this.lineCount;
			paraFunction.className = "caller-function";
			paraFunction.innerHTML = this.w.caller.toString().replace(/;/g, ";<br />").replace(/{/g, "<br />{<br />").replace(/}/g, "<br />}<br />");
			callHolder.appendChild(para);
			
			if (this.w.caller.arguments.length > 0) {
				var paraParam = document.createElement("dl");
				for (var i = 0, c = this.w.caller.arguments.length; i < c; i++) {
					paraParam.innerHTML += 	"<dt>" + typeof(arguments[i]) + " - </dt><dd>" + this.w.caller.arguments[i] + "</dd>";
				}
				callHolder.appendChild(paraParam);
			}
			
			callHolder.appendChild(paraFunction);
			if (this.console.firstChild) {
				this.console.insertBefore(callHolder, this.console.firstChild);
			} else {
				this.console.appendChild(callHolder);
			}
		}

		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 ++;
	},
	caller : function(e, i) {
		var caller = document.getElementById(i);
		if (caller.style.display == "block") {
			caller.style.display = "none";
		} else {
			caller.style.display = "block";
		}
		return false;
	},
	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;
		}
		
		if (this.p.caller) {
			var callHolder = document.createElement("div");
			callHolder.className = "caller";
			var para = document.createElement("p");
			var line = document.createTextNode(t);
			para.innerHTML = "<strong><em>&#x2191;</em> " + this.p.caller.toString().substring(0, 60) + "...</strong><a href=\"#\" onclick=\"return Debug.caller(this, 'caller-" + this.lineCount + "')\">Show</a>";
			var paraFunction = document.createElement("p");
			paraFunction.id = "caller-" + this.lineCount;
			paraFunction.className = "caller-function";
			paraFunction.innerHTML = this.p.caller;
			callHolder.appendChild(para);
			callHolder.appendChild(paraFunction);
			if (this.console.firstChild) {
				this.console.insertBefore(callHolder, this.console.firstChild);
			} else {
				this.console.appendChild(callHolder);
			}
		}
		
		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;
	}
};
// Catch runtime errors and debug
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;
	}	
};			