DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Motivational Australia AJAX Backend (complete)

03.02.2009
| 977 views |
  • submit to reddit
        // description of your code here

var selected = null;
var lselected = null;

function swapin(element) {
	element = $(element);
	if (selected!= null && selected.id == element.id && !cd(element))
		return false;
	new Effect.Opacity(element, {from: 1.0, to: 0.01, duration: 0.3});
}

function swapout(element) {
	element = $(element);
	if (selected!= null && selected.id == element.id && !cd(element))
		return false;
	new Effect.Opacity(element, {from: 0.01, to: 1.0, duration: 0.3});
} 

function is_a(obj) {
   return obj.constructor.toString().indexOf("Array") == -1;
}
function cd(element){ 
	if (element.id == 'LogIn')
		return lselected;
	else return false;
}

function dselect(element) {
	if (selected != null && selected != $(element))
		desel(selected);
	selected = $(element);
}

function desel(element) {
	element = $(element);
	new Effect.Opacity(element, {from: 0.01, to: 1.0, duration: 0.2});
}
function displayUserBar() {
	new Effect.Opacity("userbar", {from: 0.01, to: 1.0, duration: 0.3});
	new Effect.SlideDown("userbar_Sh", {duration: 0.5});
}

function displayUserBarInstantly() {
	$("userbar").style.display = "block";
	new Effect.Opacity("userbar", {from: 0.99, to: 1.0, duration: 0.1});
}

function isDisplayingUserBar() {
	return $("userbar").style.display != "none";
}

var clb = true;

function currentLogButton() {
	return clb;
}

function lselect() {
	lselected = true;
}
function ldeselect() {
	lselected = false;
}

function switchLogButtonInstantly() {
	nextImgDesel = (currentLogButton()) ? 'images/nav_05_logout_desel.jpg' :
		'images/nav_05_login_desel.jpg';
	nextImgSel = (currentLogButton()) ? 'url(images/nav_05_logout_sel.jpg)' :
		'url(images/nav_05_login_sel.jpg)';

	$("nav_login").style.backgroundImage = nextImgSel;
	$("LogIn").src = nextImgDesel;
	
	toggleClb();
}

function switchLogButton() {
	nextImgDesel = (currentLogButton()) ? 'images/nav_05_logout_desel.jpg' :
		'images/nav_05_login_desel.jpg';
	nextImgSel = (currentLogButton()) ? 'url(images/nav_05_logout_sel.jpg)' :
		'url(images/nav_05_login_sel.jpg)';

	$("nav_login").style.backgroundImage = nextImgSel;
	$("LogIn").src = nextImgDesel;
	new Effect.Opacity('LogIn', {from: 0.0, to: 1.0, duration: 0.5});
	
	toggleClb();
}

function getLogButton() {
	return $('LogIn');
}

function toggleClb() {
	ldeselect();
	clb = !clb;
	if (!clb) {
		getLogButton().onclick = function() {
			logout();
			return true;
		};
	} else {
		getLogButton().onclick = function() {
			displayUserBar();
			lselect(this);
			return true;
		}
	}
}


function putContentDim() {
	cdiv = $("content_content");
	cdiv.style.height = pxof(innerHeight() - 281);
}

function ie() {
	return navigator.appName == "Microsoft Internet Explorer";
}

function pxof(integer) {
	if (ie())
		return integer;
	return integer + "px";
}

function innerHeight() {
	if (typeof(window.innerHeight) == 'number') 
		return window.innerHeight;
	else if (document.documentElement && document.documentElement.clientHeight)
		return document.documentElement.clientHeight;
	else if (document.body && document.body.clientHeight)
		return document.body.clientHeight;
	return 1;
}

function innerWidth() {
	if (typeof(window.innerWidth) == 'number') 
		return window.innerWidth;
	else if (document.documentElement && document.documentElement.clientWidth)
		return document.documentElement.clientWidth;
	else if (document.body && document.body.clientWidth)
		return document.body.clientWidth;
	return 1;
}

var c_sstr;
var c_cr;
function setLoginStatus(statusStr, color) {
	$('userbar_error').innerHTML = statusStr;
	$('userbar_error').style.color = color;
	c_sstr = statusStr;
	c_cr = color;
}
function __looseSetLoginStatus(statusStr, color) {
	$('userbar_error').innerHTML = statusStr;
	$('userbar_error').style.color = color;
	c_sstr = statusStr;
	c_cr = color;
}
function emptyLoginStatus() {
	setLoginStatus("", "black");
}

var currentDots = 3;
var continuevve = false;
function commence_Vve()  {
	continuevve = true;
	__vve();	
}

function __vve() {
	if (!continuevve)
		return;

	var cdstr;
	if (currentDots == 1) {
		cdstr = "..";
		currentDots++;
	}
	else if (currentDots == 2) {
		cdstr = "...";
		currentDots++;
	}
	else if (currentDots == 3) {
		currentDots = 1;
		cdstr = ".";
	}
	
	__looseSetLoginStatus("Validating" + cdstr, "yellow");
	setTimeout(function () {
		__vve();
	}, 250);
}

String.prototype.trim = function() {
	return this.replace(/^\s*|\s*$/g, '');
}

function halt_Vve() {
	continuevve = false;
	setTimeout(function () {
		setLoginStatus(c_sstr, c_cr);
	}, 250);
}

function chksub(e) {
	var ccode;
	if (e && e.which)
		ccode  = e.which;
	else if (event)
		ccode = event.keyCode;
		
	if (ccode == 13)
		$('userbar_submit').click();
		
	return true;
}

function chkssub(e) {
	var ccode;
	if (e && e.which)
		ccode  = e.which;
	else if (event != null && event)
		ccode = event.keyCode;
		
	if (ccode == 13)
		JSAL.Domestic.SearchRenderer.search();
		
	return true;
}

function getKeyCode(e) {
	var ccode;
	if (e && e.which)
		ccode  = e.which;
	else if (event)
		ccode = event.keyCode;
	return ccode;
}
var __SHIFT__ = false;
function shiftdown(e) {
	if (e && e.which == 16)
		__SHIFT__ = true;
}
function shiftup(e) {
	if (e && e.which == 16)
		__SHIFT__ = false;
}
document.onkeydown = shiftdown;
document.onkeyup = shiftup;

/******************************************************************************
 AJAX HANDLERS
******************************************************************************/


var User = Class.create();
User.prototype = {
	initialize: function(user, pass, email, firstName, lastName, address, city, 
		postCode, state) {
		this.user = user.replace(/^\s*|\s*$/g, '');
		this.pass = pass;
		this.email = email;
		this.firstName = firstName;
		this.address = address;
		this.lastName = lastName;
		this.city = city;
		this.postCode = postCode;
		this.state = state;
	},
	getUser: function() {
		return this.user;
	},
	/**
	 * This is NOT a literal pass.
	 */
	getPass: function() {
		return this.pass;
	},
	getEmail: function() {
		return this.email;
	},
	getAddress: function() {
		return this.address;
	},
	getFirstName: function() {
		return this.firstName;
	},
	getLastName: function() {
		return this.lastName;
	},
	getCity: function() {
		return this.city;
	},
	getPostCode: function() {
		return this.postCode;
	},
	getState: function() {
		return this.state;
	},
	getStateStr: function() {
		switch (this.state) {
			case 1: return "QLD";
			case 2: return "NSW";
			case 3: return "VIC";
			case 4: return "SA";
			case 5: return "WS";
			case 6: return "NT";
			case 7: return "ACT";
			case 8: return "TAS";
			default: return null;
		}
	}
};

function toState(intrep) {
switch (intrep) {
			case 1: return "QLD";
			case 2: return "NSW";
			case 3: return "VIC";
			case 4: return "SA";
			case 5: return "WS";
			case 6: return "NT";
			case 7: return "ACT";
			case 8: return "TAS";
			default: return null;
		}
}

function buildSessionFactory() {
	new Ajax.Request("util.jsf?function=cr_Sfac");
}
function buildUserBar() {
	new Ajax.Updater("ubcont", "userbar.jsf", {evalScripts: true});
}

function utility(func) {
	new Ajax.Request("util.jsf?function=" +func);
}
function rebuildUserBar() {
	setTimeout(function() {
		new Ajax.Updater("ubcont", "userbar.jsf", {
			evalScripts: true,
			onComplete: function() {
				new Effect.Opacity('ubcont', {from: 0.0, to: 1.0, 
					duration: 0.5});
			}
		});
	}, 500);
	new Effect.Opacity('ubcont', {from: 1.0, to: 0.0, duration: 0.5});
}
function loginValidate() {
	Thread.KillAll(); //stop stuff that should no longer be processing.
	user = $('userbar_login').value;
	pass = $('userbar_password').value;
	commence_Vve();
	req = new Ajax.Request("login.jsf?userbar_login=" + user + 
		"&userbar_password=" + pass, {
		onComplete: function(transport) {
			response = transport.responseText;
			halt_Vve();
			if (response.match('t')) {
				setLoginStatus("Authenticated Successfully.", "green");
				setUserStatus(true);
				setTimeout(function() {
					rebuildUserBar();
				}, 500);
				if (currentLogButton())
					switchLogButton();
			}
			else {
				setLoginStatus("Invalid Login", "red");
				setUserStatus(false);
			}
			synchronizeWithUser();
		}
	});
	emptyLoginStatus();
}

function logout() {
	Thread.KillAll();
	deploy('dcontent.jsf?action=defaultGreeting')
	justLogout();
	if (!currentLogButton())
		switchLogButton();
	new Effect.SlideUp("userbar_Sh", {duration: 0.5});
	setTimeout(function() {
		buildUserBar();
	}, 500);
}

function justLogout() {
	if (!isLoggedIn())
		return;
		
	utility("logout");
	setUserStatus(false);
}

var userStatus = false;

function setUserStatus(isKnown) {
	userStatus = isKnown;
}

function getUserStatus() {
	return userStatus;
}

function synchronizeWithUser() {
	Thread.KillAll();
	if (isLoggedIn()) {
		requestUser();
		displayUserBarInstantly();
		if (currentLogButton())
			switchLogButtonInstantly();
	} 
}

function isLoggedIn() {
	return userStatus;
}

function updateUserStatus() {
	new Ajax.Request('util.jsf?function=userKnown', {
		onComplete: function(transport) {
			setUserStatus(transport.responseText.match('t') != null);
			synchronizeWithUser();
		}
	});
}

function redirectCheck() {
	var p = JSAL.param("purchase");
	if (!p)
		return;
	
	deploy('booking.jsf' + window.location.search);
}

function deploy(page) {
	var thisDep = function() {
		new Ajax.Updater("content_content", page, {
			evalScripts: true
		});
	};
	deployCallback.finish.add(thisDep.bind(this), true);
	deployCallback.callback();
	
}
function inject(page) {
	new Ajax.Request(page, {
		evalScripts: true
	});
}
updateUserStatus();

var currentUser;

function getCurrentUser() {
	return currentUser;
}

function setCurrentUser(user) {
	currentUser = user;
}

function requestUser() {
	new Ajax.Request("util.jsf?function=currentSessUser", {
		onComplete: function(transport) {
			rtarr = transport.responseText.split("~");
			rtarr[0].trim();
			setCurrentUser(new User(rtarr[0], rtarr[1], rtarr[2], rtarr[3],
				rtarr[4], rtarr[5], rtarr[6], rtarr[7], rtarr[8]));
		}
	});
}



/******************************************************************************
 REGISTRATION / UPDATE USER DETAILS HANDLERS
******************************************************************************/

function ensureInt() {
	if ($('postCode').value * 1 < 10000 && $('postCode').value * 1 > 0) {
		resolveIfError($('postCode'));
		return true;
	}
		
	errorFire('postCode', 'Invalid Post Code');
	return false;
}

function checkEmailMatch() {
	if ($('email').value != $('email1').value)
		errorFire('email', 'Emails do not match');
	else resolveIfError($('email'));
}

function checkPWMatch() {
	if ($('password').value != $('password1').value)
		errorFire('password', 'Passwords do not match');
	else resolveIfError($('password'));
}

function handleNullException(el) {
	el = $(el);
	
	if (el.id == "email1" && el.value != "")
		emChk();
	
	if (el.value == "") {
		$(el.id + "_err").style.color = "red";
		$(el.id + "_err").innerHTML = "This field cannot be empty";
	}
	else if ($(el.id + "_err").innerHTML
				.match("This field cannot be empty") != null)
		$(el.id + "_err").innerHTML = "";
	return true;
}

function emChk() {
	em = $('email1');
	if (!isvalidEmail(em.value))
		errOf(em).innerHTML = "Invalid email format";
	else errOf(em).innerHTML = "";
}

function errOf(el) {
	return $(el.id + "_err");
}

function errorFire(element, message) {
	/*var espan;
	if (document.getElementById(element.id + "_err"))
		espan = $(element.id + "_err");
	else espan = document.createElement('span');
	espan.class = "register_errormsg";
	espan.id = element.id + "_err";
	espan.innerHTML = message;
	espan.style.float = "right";
	$(element).insert(espan, {position: 'after'});*/
	$($(element).id + "_err").innerHTML = message;
}
function resolveIfError(element) {
	/*if (document.getElementById(element.id + "_err"))
		$(element.id + "_err").style.display = "none";*/
	$($(element).id + "_err").innerHTML = "";
}

function isvalidEmail(em) {
	ema = em.split("@");
	if (!ema[1])
		return false;
	return ema[1].match(".") != null;
}

function quickMark(field) {
	var nameField = (field) ? $('firstName') : $('lastName');
	var nameErrField = $(nameField.id + "_err");
	nameErrField.innerHTML = "This field cannot be empty";
}

function quickResolve() {
	if ($('firstName').value == "")
		__Qr(true);
	if ($('lastName').value == "")
		__Qr(false);
}
function __Qr(field) {
	var nameField = (field) ? $('firstName') : $('lastName');
	nameErrField = $(nameField.id + "_err");
	nameErrField.innerHTML = "";
}

function checkUNAv() {
	if ($('username').value == "")
		return;
		
	new Ajax.Request("util.jsf?function=unav&un=" + $('username').value, { 
		onComplete: function(transport) {
			if (transport.responseText.match('t') != null) {
				$('username_err').innerHTML = "The username '"+
					$('username').value + "' is available.";
				$('username_err').style.color = "green";
				return;
			}
		
			$('username_err').style.color = "red";
			$('username_err').innerHTML = "The username '"+$('username').value +
				"' is unavailable.";
		}
	});	
}

function a_checkUNAv() {
	if ($('username').value == "" || $('username').value == 
													getCurrentUser().getUser())
		return;
		
	new Ajax.Request("util.jsf?function=unav&un=" + $('username').value, { 
		onComplete: function(transport) {
			if (transport.responseText.match('t') != null) {
				$('username_err').innerHTML = "The username '"+
					$('username').value + "' is available.";
				$('username_err').style.color = "green";
				return;
			}
		
			$('username_err').style.color = "red";
			$('username_err').innerHTML = "The username '"+$('username').value +
				"' is unavailable.";
		}
	});	
}
function a_checkEmailAv() {
	if ($('email1').value == "" || $('email1').value == 
												getCurrentUser().getEmail())
		return;
		
	new Ajax.Request("util.jsf?function=emav&un=" + $('email1').value, { 
		onComplete: function(transport) {
			if (transport.responseText.match('t') != null) {
				$('email1_err').innerHTML = "The email '" + $('email1').value + 
					"' is available.";
				$('email1_err').style.color = "green";
				return;
			}
		
			$('email1_err').style.color = "red";
			$('email1_err').innerHTML = "The email '" + $('email1').value +
				"' is unavailable.";
		}
	});	
}
function checkEmailAv() {
	if ($('email1').value == "")
		return;
		
	new Ajax.Request("util.jsf?function=emav&un=" + $('email1').value, { 
		onComplete: function(transport) {
			if (transport.responseText.match('t') != null) {
				$('email1_err').innerHTML = "The email '" + $('email1').value + 
					"' is available.";
				$('email1_err').style.color = "green";
				return;
			}
		
			$('email1_err').style.color = "red";
			$('email1_err').innerHTML = "The email '" + $('email1').value +
				"' is unavailable.";
		}
	});	
}

function validUsername() {
	handleNullException($('username'));
	return $('username_err').innerHTML.match('is unavailable') == null;
}

function validPassword() {
	handleNullException($('password1'));
	return $('password1').value != "" && $('password').value == 
		$('password1').value;
}

function validEmail() {
	
	handleNullException($('email1'));
	return $('email1_err').innerHTML.match('is unavailable') == null && 
		$('email1').value != "" && $('email').value == $('email1').value &&
		isvalidEmail($('email1').value);
}

function validNames() {
	if ($('firstName').value != "" && $('lastName').value != "") {
		return true;
	}
	
	if ($('firstName').value == "")
		quickMark(true);
	if ($('lastName').value == "")
		quickMark(false);
	
	return false;
}

function reg_dValidation() {
	var valid = true;
	if (!validUsername())
		valid = false;
	if (!validPassword())
		valid = false;
	if (!validEmail())
		valid = false;
	if (!validNames())
		valid = false;
	
	return valid;
}

function doSubmitRegistration() {
	if (!reg_dValidation()) {
		serr = $('submit_err');
		serr.innerHTML = "There are unresolved errors, please resolve them before "+
			"submitting.";
		return;
	}
		
	
	serializeAndSend()
}

function doSubmitAlter() {
	if (!reg_dValidation()) {
		$('submit_err').innerHTML = "There are unresolved errors, please resolve them before "+
			"submitting.";
		return;
	}
	
	a_serializeAndSend();
}

function serializeAndSend() {
	utility("register&" + Form.serialize($('registerform')));
	deploy("dcontent.jsf?action=registeredGreeting");
}

function a_serializeAndSend() {
	utility("alter&" + Form.serialize($('registerform')));
	deploy("dcontent.jsf?action=userDetailsUpdated");
}

/**
 * ALTER ACCOUNT FUNCTIONS
 * this is under the same js file because these two are basically the same page,
 * except with alter you're updating details.
 */
 function a_load() {
 	var user = getCurrentUser();
 	$('username').value = user.getUser();
 	$('password1').value = user.getPass();
 	$('password').value = user.getPass();
 	$('email1').value = user.getEmail();
 	$('email').value = user.getEmail();
 	$('address').value = user.getAddress();
 	$('state').value = user.getState();
 	$('city').value = user.getCity();
 	$('firstName').value = user.getFirstName();
 	$('lastName').value = user.getLastName();
 	$('postCode').value = user.getPostCode();
 }
 
 

/******************************************************************************
 SHOPPING CART HANDLERS
******************************************************************************/

//need a compare method for strings cause JS doesn't have one, making my own.
function strcmp(a, b) {
	aa = a.toLowerCase();
	bb = b.toLowerCase();
	
	var max = Math.min(aa.length, bb.length);
	for (var i = 0; i < max; i++) {
		var res = aa.charCodeAt(i) - bb.charCodeAt(i);
		if (res != 0)
			return res;
	}
	return aa.length - bb.length;
}

var CartItem = Class.create();
CartItem.prototype = {
	initialize: function(interp) {
		this.interp = interp;
		this.interpStr();
	},
	/**
	* String format:
	* event name|event details link|event price
	*/
	interpStr: function() {
		var splits = this.interp.split("|");
		this.eventId = parseInt(splits[0]);
		this.eventName = splits[1];
		this.eventLink = splits[2];
		this.eventPrice = parseFloat(splits[3]);
		this.quantity = parseInt(splits[4]);
		this.timeout = parseInt(splits[5]);
	},
	getEventName: function() {
		return this.eventName;
	},
	getEventLink: function() {
		return "javascript:deploy('"+this.eventLink+"')";
	},
	getEventPrice: function() {
		return this.eventPrice * this.quantity;
	},
	getEventId: function() {
		return this.eventId;
	},
	getQuantity: function() {
		return this.quantity;
	},
	getTimeout: function() {
		return this.timeout;
	}
};

var Cart = Class.create();
Cart.prototype = {
	initialize: function() {
		this.tog = 1;
		this.csv = 0;
	},
	createAndInsertCart: function(parent_id) {
			if ($('cart_final'))
				this.parent.removeChild($('cart_final'));
		this.parent = $(parent_id);
		new Ajax.Request('cart.jsf?function=getData', { 
			onComplete: this.receive.bind(this)
		});
	},
	/**
	* string format: data*data*data see cartitem class for subdata format
	*/
	receive: function(data) {
		//can't split a null str
		if (data.responseText.length < 8) {
			if ($('cart_tab'))
				this.parent.removeChild($('cart_tab'));
			if ($('cart_final'))
				this.parent.removeChild($('cart_final'));
			this.parent.appendChild(this.createNullException());
			return;
		}
		data = data.responseText.trim();
		data = data.split("*");
		if (data[0].length < 8) {
			this.parent.appendChild(this.createNullException());
			return;
		}
		this.cartItems = new Array(data.length);
		for (var i = 0; i < data.length; i++) {
			current_ci = new CartItem(data[i]);
			this.cartItems[i] = current_ci;
		}
		
	//	this.resortIfRequested();
		this.timer_spans = new Array();
		var tab = this.createTable();
		
		if ($('cart_tab'))
			this.parent.removeChild($('cart_tab'));
			if ($('cart_final'))
				this.parent.removeChild($('cart_final'));
		
		this.parent.appendChild(tab);
		this.timer_thread = new Thread(this.updateTimers.bind(this));
		this.timer_thread.recurse(1000);
		this.parent.appendChild(this.createFinalDesc());
	},
	updateTimers: function() {
		for (var i = 0; i < this.timer_spans.length; i++) {
			var THIS_EL = $(this.timer_spans[i]);
			if (!THIS_EL) {
				this.timer_thread.stop();
				return;
			}
			if (THIS_EL.innerHTML == '0')
				return this.refresh();
			THIS_EL.innerHTML = parseInt(THIS_EL.innerHTML) - 1;
		}
	},
	refresh: function() {
		this.createAndInsertCart('cart_list');
	},
	justResort: function() {
		this.csv = this.squeue;
		this.resortIfRequested();
		
		var tab = this.createTable();
		
		if ($('cart_tab'))
			this.parent.removeChild($('cart_tab'));
		
		this.parent.appendChild(tab);
		this.parent.appendChild(this.createFinalDesc());
	},
	remove: function(id) {
		new Ajax.Request('cart.jsf?remove=' + id, {
			onComplete: this.receive.bind(this)
		});
	},
	removeFromPage: function(element) {
		element = $(element);
		$('cart_tab').removeChild(element);
	},
	createCell: function(html, itemIsElement) {
		var element = document.createElement('td');
		if (itemIsElement == true)
			element.appendChild(html);
	    else
			element.innerHTML = html;
		return element;
	},
	createRemoveLink: function(id) {
		var link = document.createElement('a');
		link.href = 'javascript:c_cart.remove(' + id + ');';
		link.innerHTML = "Remove";
		return link;
	},
	createRow: function(cartItem, subTotal) {
		var dcont = e('div');
		var itemNameText = document.createElement('a');
		itemNameText.href = cartItem.getEventLink();
		itemNameText.innerHTML = cartItem.getEventName();
		dcont.appendChild(itemNameText);
		
		//timed events as of 23/05/08
		var timer = e('span', cartItem.getEventId() + '_c_t', 'cart_timer');
		this.timer_spans[this.timer_spans.length] = timer.id;
		timer.innerHTML = cartItem.getTimeout();
		dcont.appendChild(timer);
		
		var itemName = this.createCell(dcont,true);
		var itemPrice = this.createCell("$" + cartItem.getEventPrice()
						.toFixed(2));
		var csubTotal = this.createCell("$" + subTotal.toFixed(2));
		var quantity = this.createCell(cartItem.getQuantity());
		var itemNumber = this.createCell(cartItem.getEventId());
		var reml = this.createCell(this.createRemoveLink(
			cartItem.getEventId()), true);
		
		var row = document.createElement('tr');
		row.appendChild(itemNumber);
		row.appendChild(itemName);
		row.appendChild(quantity);
		row.appendChild(itemPrice);
		row.appendChild(csubTotal);
		row.appendChild(reml);
		
		row.id = "cart_row_" + cartItem.getEventId();
		
		return this.stylizeRow(row);
	},
	stylizeRow: function(row) {
		row.className = this.toggleTrStyle();
		row.childNodes[0].className = "cart_col_item_number";
		row.childNodes[1].className = "cart_col_item_name";
		row.childNodes[2].className = "cart_col_quantity";
		row.childNodes[3].className = "cart_col_price";
		row.childNodes[4].className = "cart_col_subtotal";
		row.childNodes[5].className = "cart_col_remove";
		return row;
	},
	createHeaderRow: function() {
		var row = document.createElement('tr');
		
		var itemNo = this.createCell(
			this.createSortLink('Event ID', 1), true);
		var itemName = this.createCell(
			this.createSortLink('Event Name', 2),true);
		var quantity = this.createCell(
			this.createSortLink('Quantity', 3), true);
		var price = this.createCell(
			this.createSortLink('Price', 4), true);
		var subtotal = this.createCell('Subtotal');
		var etr = this.createCell('');
		
		row.appendChild(itemNo);
		row.appendChild(itemName);
		row.appendChild(quantity);
		row.appendChild(price);
		row.appendChild(subtotal);
		row.appendChild(etr);
		
		row = this.stylizeRow(row);
		row.className = "cart_header";
		return row;
	},
	toggleTrStyle: function() {
		if (this.tog == 1)
			this.tog = 2;
		else if (this.tog == 2)
			this.tog = 1;
		
		if (this.tog == 1)
			return "cart_even";
		else return "cart_odd";
	},
	createTable: function() {
		var tab = document.createElement('table');
		tab.className = "cart";
		tab.cellSpacing = 0;
		tab.id = 'cart_tab';
		var subtotal = 0.0;
		var qty = 0;
		tab.appendChild(this.createHeaderRow());
		for (var i = 0, len = this.cartItems.length; i < len; ++i) {
			var currentItem = this.cartItems[i];
			subtotal += currentItem.getEventPrice();
			tab.appendChild(this.createRow(currentItem, subtotal));
			qty += currentItem.getQuantity();
		}
		this.total = subtotal;
		this.totalqty = qty;
		return tab;
	},
	createFinalDesc: function() {
		var div = document.createElement('div');
		div.className = 'textcontent';
		div.id = 'cart_final';
		div.innerHTML = '<br/>Total items: <b>' + this.getTotalQuantity() 
		+ '</b>' +
						'<br/>Total price: <b>' + this.getTotal() + '</b><br/>'
		+ '<br/> ' +
		'<a href="javascript:deploy(\'booking.jsf?purchase=cart\');">' +
		'Purchase Cart</a>'
		+ '<br/><br/><b class="cross"></b>:'+
		' Time remaining until this reservation expires.';
		return div;
	},
	createNullException: function() {
		if ($('cart_final'))
			JSAL.r('cart_final');
		if ($('cart_tab'))
			JSAL.r('cart_tab');
		var ndiv = document.createElement('div');
		ndiv.className = 'textcontent';
		ndiv.innerHTML = 'You do not currently have any items in your cart';
		return ndiv;
	},
	getTotalQuantity: function() {
		return this.totalqty;
	},
	getTotal: function() {
		return this.total;
	},
	sortByName: function() {
		if (this.csv == 2) {
			this.cartItems.sort(function(a, b) {
				return strcmp(b.getEventName(), a.getEventName());
			});
			this.csv = 0;
		} else this.cartItems.sort(function(a, b) {
			return strcmp(a.getEventName(), b.getEventName());
		});
	},
	sortByItemNo: function() {
		if (this.csv == 1) {
			this.cartItems.sort(function(a, b) {
				return b.getEventId() - a.getEventId();
			});
			this.csv = 0;
		} else this.cartItems.sort(function(a, b) {
			return a.getEventId() - b.getEventId();
		});
	},
	sortByPrice: function() {
		if (this.csv == 4) {
			this.cartItems.sort(function(a, b) {
				return a.getEventPrice() - b.getEventPrice();
			});
			this.csv = 0;
		} else this.cartItems.sort(function(a, b) {
			return a.getEventPrice() - b.getEventPrice();
		});
	},
	sortByQty: function() {
		if (this.csv == 3) {
			this.cartItems.sort(function(a, b) {
				return a.getQuantity() - b.getQuantity();
			});
			this.csv = 0;
		} else this.cartItems.sort(function(a, b) {
			return a.getQuantity() - b.getQuantity();
		});
	},
	/*
	* sort codes:
	* 1 = itemno
	* 2 = name
	* 3 = qty
	* 4 = price
	****/
	resort: function(method) {
		this.squeue = method;
		c_cart.justResort();
	},
	resortIfRequested: function() {
		if (!this.squeue)
			return;
		
		if (this.squeue == 1)
			this.sortByItemNo();
		else if (this.squeue == 2)
			this.sortByName();
		else if (this.squeue == 3)
			this.sortByQty();
		else if (this.squeue == 4)
			this.sortByPrice();
		
		this.squeue = 0;
	},
	createSortLink: function(n, sid) {
		return e('span', 'th_'+sid, '', n);
	}
}
var c_cart = new Cart();
function assertCartDetails() {
	c_cart.createAndInsertCart('cart_list');
}


/******************************************************************************
  JSAL IMPLEMENTATION
******************************************************************************/

var JSAL = {
	element: function(n, id, cc, ih) {
		var item  = document.createElement(n);
		if (id)
			item.id = id;
		if (cc)
			item.className = cc;
		if (ih)
			item.innerHTML = ih;
		return item;
	},
	r: function(eid) {
		this.remove(eid);
	},
	remove: function(eid) {
		$(eid).parent.removeChild($(eid));
	},
	param: function(key) {
		
		key = key.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	    var regexS = "[\\?&]"+key+"=([^&#]*)";
	    var regex = new RegExp( regexS );
	    var results = regex.exec( window.location.href );
	    if (results == null)
	    	return false;
	  	else
	    	return results[1];
	},
	dockImmediately: function(encryptedIntermediary) {
	var mobj = JSAL.Dock.dock(encryptedIntermediary).convertChildrenToMapped(
			JSAL.Domestic.Handler.getExpectedPropertySet());
		JSAL.Domestic.Handler.renderExpectedContent(mobj);
	}
};
Element.prototype.setText = function(text) {
	this.innerHTML = text;
	return this;
};
Element.prototype.Tappend = function(text) {
	this.innerHTML += text;
	return this;
};
function e(name, id, cc, th) {
	return JSAL.element(name, id, cc, th);
}
JSAL.Domestic = {
	outputDivName: 'content_content'
};
JSAL.regurgitate = function(digested) {
	
	var rs = "";
	for (var i = 0; i < digested.length; i += 2)
		rs += String.fromCharCode(parseInt(
						digested.substring(i, i + 2), 16));
	return rs;
};
JSAL.propertySets = new Array();
JSAL.addPropertySet = function(propertySet) {
	JSAL.propertySets[JSAL.propertySets.length] = propertySet;
};
JSAL.getPropertySetByName = function(name) {
	for (var i = 0; i < JSAL.propertySets.length; i++)
		if (JSAL.propertySets[i].getName() == name)
			return JSAL.propertySets[i];
};
JSAL.DockingStation = Class.create();
JSAL.DockingStation.prototype = {
	initialize: function() {},
	dock: function(responseText) {
		responseText = responseText.trim().split("@").slice(1);
		var incomingObjects = new Array();
		for (var i = 0; i < responseText.length; i++) {
			incomingObjects[i] = this.subDock(responseText[i]);
		}
		return incomingObjects[0];
	},
	subDock: function(arg0) {
		var rarr = new Array();
		arg0 = arg0.split('&').slice(1);
		for (var i = 0; i < arg0.length; i++) {
			arr = arg0[i].split(':').slice(1);
			for (var n = 0; n < arr.length; n++)
				arr[n] = JSAL.regurgitate(arr[n]);
			rarr[i] = new JSAL.IncomingObject(arr);
		}
		return new JSAL.IncomingObject(rarr);
	}
};
JSAL.Dock = new JSAL.DockingStation();
JSAL.PropertySet = Class.create();
JSAL.PropertySet.prototype = {
	initialize: function(propertySetName, propertySetArr, toStringOrder) {
		this.properties = propertySetArr;
		this.name = propertySetName;
		JSAL.addPropertySet(this);
		this.toStringOrder = toStringOrder.split('.');
	},
	getName: function() {
		return this.name;
	},
	getProperties: function() {
		return this.properties;
	},
	propertyFor: function(name, pool) {
		for (var i = 0; i < this.properties.length; i++)
			if (this.properties[i] == name)
				return pool[i];
	},
	toString: function(pool) {
		var rs = "";
		for (var i = 0; i < this.toStringOrder.length; i++) {
			rs += this.toStringOrder[i] + ": " +
				this.propertyFor(this.toStringOrder[i], pool) + "; ";
		}
		return rs;
	}
};
Array.prototype.is_array = true;
JSAL.MappedObject = Class.create();
JSAL.MappedObject.prototype = {
	initialize: function(propertySetName, incomingObject) {
		this.incomingObject = incomingObject;
		this.propertySet = JSAL.getPropertySetByName(propertySetName);
	},
	getProperty: function(propertyName) {
		return this.propertySet.propertyFor(propertyName, 
					this.incomingObject.getObjects());
	},
	getString: function(propertyName) {
		return this.getProperty(propertyName);
	},
	getInt: function(propertyName) {
		return parseInt(this.getProperty(propertyName));
	},
	getFloat: function(propertyName) {
		return parseFloat(this.getProperty(propertyName));
	},
	getType: function() {
		return this.propertySet.getName();
	},
	getGenreList: function(propertyName) {
		return new GenreList(this.get(propertyName));
	},
	getEpoch: function(propertyName) {
		return new Epoch(this.getInt(propertyName));
	},
	get: function(propertyName) {
		return this.getProperty(propertyName);
	},
	toString: function() {
		return this.propertySet.toString(this.incomingObject.getObjects());
	}
};
JSAL.IncomingObject = Class.create();
JSAL.IncomingObject.prototype = {
	initialize: function(arr) {
		this.objects = arr;
	},
	getObjects: function() {
		return this.objects;
	},
	getItemByNo: function(itemNo) {
		return this.objects[itemNo];
	},
	toMappedObject: function(propertySetName) {
		return new JSAL.MappedObject(propertySetName, this);
	},
	convertChildrenToMapped: function(propertySetName) {
		if (propertySetName.is_array)
			return this.multiMap(propertySetName);
	
		for (var i = 0; i < this.objects.length; i++)
			this.objects[i] = this.objects[i].toMappedObject(propertySetName);
		return this;
	},
	multiMap: function(sets) {
		for (var i = 0; i < this.objects.length; i++) {
			if (i < sets.length - 1)
				this.objects[i] = this.objects[i].toMappedObject(sets[i]);
			else this.objects[i] 
				= this.objects[i].toMappedObject(sets[sets.length - 1]);
		}
		return this;
	},
	toString: function() {
		str = "";
		for (i = 0; i <  this.objects.length; i++)
			str += this.objects[i] + "\n";
		return str;
	},
	
	/**
	 CHILDREN MUST BE MAPPED FOR THESE METHODS TO WORK!
	 **/
	intSortValue: function(propertyName) {
		this.sv = propertyName;
	},
	sortChildren: function(propertyName) {
		this.iqsort(0, this.objects.length - 1);
	},
	iqsort: function(top, bottom) {
		if (top < bottom) {
			var _mid = this._qspart(top, bottom);
			this.iqsort(top, _mid);
			this.iqsort(_mid + 1, bottom);
		}
	},
	_qspart: function(top, bottom) {
		var _buf = this.objects[top].getInt(this.sv), buf1, i = top - 1, 
			n = bottom + 1;
		do {
			do {
				n--;
			} while (this.objects[n].getInt(this.sv) > _buf);
			do {
				i++;
			} while (this.objects[i].getInt(this.sv) < _buf);
			if (i < n) {
				_buf1 = this.objects[i];
				this.objects[i] = this.objects[n];
				this.objects[n] = _buf1;
			}
		} while (i < n);
		return n;
	},
	floor: function() {
		return this.objects[0].getInt(this.sv);
	},
	ceil: function() {
		return this.objects[this.objects.length - 1].getInt(this.sv);
	},
	getRangeByKeys: function(l, r) {
		//cant use search because keys may not be exact, f.e. epochs
		var range = new Array();
		var n = 0;
		for (var i = 0; i < this.objects.length; i++) {
			var cval = this.objects[i].getInt(this.sv);
			if (cval < l)
				continue;
			if (cval > r)
				return range;
			
			range[n++] = this.objects[i];
		}
		return range;
	},
	getKeySet: function() {
		var keySet = new Array();
		for (var i = 0; i < this.objects.length; i++)
			keySet[i] = this.objects[i].getInt(this.sv);
			
		return keySet;
	}
};
//CUSTOM ASPECT OF JSAL
JSAL.Domestic.ContextualRenderer = {
	//ITEM CODE IDENTIFIERS
	eventListing: 1,
	event: 2,
	purchase: 3,
	splanupd: 4,
	bookingListing: 5,
	booking: 6,
	searchResult: 7,
	venue: 8,
	venueListing: 9,
	speaker: 10,
	speakerListing: 11,
	freshBookingList: 12,
	
	renderEventListing: function(object) {
		JSAL.Domestic.EventRenderer.executeRenderEventList(object);
	},
	propertySetFor: function(itemCode) {
		if (itemCode == this.eventListing)
			return "event";
		if (itemCode == this.event)
			return ['event', 'briefEvent'];
		if (itemCode == this.purchase)
			return ['briefEvent', 'purchase'];
		if (itemCode == this.splanupd)
			return 'purchase';
		if (itemCode == this.bookingListing)
			return 'briefBooking';
		if (itemCode == this.booking)
			return ['briefEvent', 'booking'];
		if (itemCode == this.searchResult)
			return 'briefEvent';
		if (itemCode == this.venue)
			return ['venue', 'briefEvent'];
		if (itemCode == this.speaker)
			return ['speaker', 'briefEvent'];
		if (itemCode == this.speakerListing)
			return 'speaker';
		if (itemCode == this.venueListing)
			return 'briefVenue';
		if (itemCode == this.freshBookingList)
			return 'briefBooking';
	},
	renderContentByItemCode: function(itemCode, object) {
		if (itemCode == this.eventListing)
			this.renderEventListing(object);
		else if (itemCode == this.event)
			JSAL.Domestic.EventRenderer.executeRenderEvent(object);
		else if (itemCode == this.purchase)
			JSAL.Domestic.PurchaseRenderer.executeRenderPurchasable(object);
		else if (itemCode == this.splanupd)
			JSAL.Domestic.PurchaseRenderer.updateTable(object);
		else if (itemCode == this.bookingListing)
			JSAL.Domestic.BookingRenderer.renderBookingListing(object,false);
		else if (itemCode == this.booking)
			JSAL.Domestic.BookingRenderer.renderBooking(object);
		else if (itemCode == this.searchResult)
			JSAL.Domestic.SearchRenderer.renderSearchResult(object);
		else if (itemCode == this.venue)
			JSAL.Domestic.VenueRenderer.renderVenue(object);
		else if (itemCode == this.speaker)
			JSAL.Domestic.SpeakerRenderer.renderSpeaker(object);
		else if (itemCode == this.speakerListing)
			JSAL.Domestic.SpeakerRenderer.renderSpeakerListing(object);
		else if (itemCode == this.venueListing)
			JSAL.Domestic.VenueRenderer.renderVenueListing(object);
		else if (itemCode == this.freshBookingList)
			JSAL.Domestic.BookingRenderer.renderBookingListing(object,true);
	},
	render: function(element) {
		this.clearOutputSpace();
		this.getOutput().appendChild(element);
	},
	clearOutputSpace: function() {
		for (var i = 0; i < this.getOutput().childNodes.length; i++) 
			this.getOutput().removeChild(this.getOutput().childNodes[i]);
	},
	getOutput: function() {
		return $(JSAL.Domestic.outputDivName);
	},
	getHeading: function(header, subheader) {
		var h1 = e('h1');
		h1.innerHTML = header;
		var h2 = e('h2');
		h2.innerHTML = subheader;
		var dv = e('div');
		dv.appendChild(h1);
		dv.appendChild(h2);
		return dv;
	}
};
JSAL.Domestic.BookingRenderer = {
	i: 0,
	renderBooking: function(io) {
		this.io = io.getObjects();
		this.div = e('div', 'b__'+this.UID());
		var h1 = e('h1', '', '', 'Booking - ' + this.io[0].get('eventName'));
		var h2 = e('h2', '', '', 'Here you can print your ticket and see the '+
			'positioning of your seats for this event');
		var detCont = e('div', '', 'booking_details_container');
		var datePurchased = e('div', '', 'booking_field');
		datePurchased.innerHTML = 'Date Purchased: ' + 
			this.io[1].getEpoch('date').toDateStr();
		var qty = e('div', '', 'booking_field');
		qty.innerHTML = 'Ticket Quantity: ' + this.io[1].get('ticketCount');
		var id = e('div', '', 'booking_field');
		id.innerHTML = 'Booking ID: ' + this.io[1].get('bookingId');
		var ven = e('div', '', 'booking_field', 'Venue: ');
		var evn = e('div', '', 'booking_field', 'Event: ');
		var vena = e('a', '', 'booking_link', this.io[0].get('venueName'));
		vena.href = 'javascript:deploy("venue.jsf?vid='
		+this.io[0].get('venueId')+'")';
		var evna = e('a', '', 'booking_link', this.io[0].get('eventName'));
		evna.href = 'javascript:deploy("event.jsf?eid=' 
		+ this.io[0].get('eventId') + '")';
		ven.appendChild(vena);
		evn.appendChild(evna);
		detCont.appendChild(datePurchased);
		detCont.appendChild(qty);
		detCont.appendChild(id);
		detCont.appendChild(evn);
		detCont.appendChild(ven);
		var tlkin = e('a', '', 'booking_ticket_link');
		tlkin.innerHTML = 'Click here to print your tickets';
		tlkin.href = 'ticket.jsf?bid=' + this.io[1].get('bookingId');
		tlkin.target = '_blank';
		
		var img = e('img','','booking_image');
		img.src = "images/" + this.	io[1].get('image');
		this.div.appendChild(h1);
		this.div.appendChild(h2);
		this.div.appendChild(detCont);
		this.div.appendChild(tlkin);
		this.div.innerHTML += "<br/><br/>";
		this.div.appendChild(img);
		JSAL.Domestic.ContextualRenderer.render(this.div);
	},
	renderBookingListing: function(io, isFresh) {
		this.io = io.getObjects();
		this.div = e('div', 'b_l_'+this.UID());
		var h1 = e('h1');
		if (isFresh) {
			h1.innerHTML = 'Thankyou for shopping with Motivational Australia';
		} else {
			h1.innerHTML = 'Your bookings';
		}
		var h2 = e('h2');
		if (isFresh) {
			h2.innerHTML = 'Here is a listing of the items you just purchased.';
		} else {
			h2.innerHTML = 'Here you can see the items that you have '+
			'purchased';
		}
		var t1 = e('div', '', 'textcontent');
		if (isFresh) {
		t1.innerHTML = 'Click on the item to print your tickets, or for '+
		'seat location details. Your receipt(s) can be seen with the tickets.';
		} else {
			
		t1.innerHTML = 'Click on the item to print your tickets, or for '+
		'seat location details.';
		}
		var ldiv = e('div', 'blist__'+this.UID, 'booking_listing');
		for (var i = 0; i < this.io.length; i++) {
			var item = e('div', 'bitem_'+this.UID(), 'booking_listing_item');
			var event = e('a', 'bitem_Ev_'+this.io[i].get('eventId')
				+this.UID(),'booking_listing_eventName', 
				this.io[i].get('eventName'));
			event.href = "javascript:deploy('booking.jsf?bid=" + 
			this.io[i].get('bookingId') + "');";
			var tcount = e('span', 'bitem_tc_'+this.UID(),
				'booking_listing_tcount', '- ' + this.io[i].get('ticketCount')+
				' ticket(s)');
			var vname = e('span', 'bitem_v_'+this.UID(),
				'booking_listing_venue', "(" + this.io[i].get('venueName')
				+")");
			item.appendChild(event);
			item.appendChild(vname);
			item.appendChild(tcount);
			ldiv.appendChild(item);
		}
		this.div.appendChild(h1);
		this.div.appendChild(h2);
		this.div.appendChild(t1);
		this.div.appendChild(ldiv);
		JSAL.Domestic.ContextualRenderer.render(this.div);
	},
	UID: function() {
		return "" + this.i++;
	}
};
JSAL.Domestic.EventRenderer = {
	executeRenderEventList: function(incomingObject) {
		this.io = incomingObject;
		incomingObject.intSortValue('date');
		incomingObject.sortChildren();
		this.createHeader();
		var _fl = Epoch.toDayStart(incomingObject.floor()), 
			_cl = Epoch.toDayStart(incomingObject.ceil());
		for (var i = _fl; i <= _cl; i += Epoch.DAY_VALUE) {
			var day_range = incomingObject
										.getRangeByKeys(i, i + Epoch.DAY_VALUE);
			
			if (day_range.length == 0)
				continue;
			else this.createDay(i, day_range);
		}
		JSAL.Domestic.ContextualRenderer.render(this.div);
	},
	createHeader: function() {
		this.div = e('div', 'edata');
		this.div.appendChild(JSAL.Domestic.ContextualRenderer.getHeading(
			'Upcoming Events', 'This page lists all upcoming events. ' +
			'To view events in your area only, go to the search feature, and ' +
			'search for events in ' + 
			((getCurrentUser() ? getCurrentUser().getStateStr() : null) 
				|| 'your area') + ' .'));
	},
	createDay: function(dayEpoch, mappedObjects) {
		var h3 = e('h3');
		var day = new Epoch(dayEpoch);
		h3.innerHTML = Epoch.monthToStr(day.getMonth()) + " "
			+ day.getDay() + ", " + day.getYear();
		this.div.appendChild(h3);
		
		for (var i = 0; i < mappedObjects.length; i++) {
			var dv = e('div', 'event' + mappedObjects[i].getInt('eventId'), 
				'nestedEvent');
			var time = e('span', dv.id+'date', 'nestedEvent_date');
			var epochfor = mappedObjects[i].getEpoch('date');
			time.innerHTML = epochfor.toTimeStr();
			var name = e('a', dv.id+'name', 'nestedEvent_eventName');
			name.innerHTML += mappedObjects[i].get('eventName');
			name.href = "javascript:deploy('event.jsf?eid=" + 
				mappedObjects[i].getInt('eventId') + "')";
			var speaker = e('a', dv.id+'speaker', 'nestedEvent_speakerName');
			speaker.innerHTML += mappedObjects[i].get('speakerName');
			speaker.href = "javascript:deploy('speaker.jsf?sid=" + 
				mappedObjects[i].getInt('speakerId') + "')";
			var state = e('a', dv.id+'state', 'nestedEvent_state');
			state.href = "javascript:deploy('event.jsf?state=" +
				mappedObjects[i].get('state') + "');";
			state.innerHTML = "(" + toState(mappedObjects[i].getInt('state')) + 
				")";
			var milink = e('a', 'mi_ln' + mappedObjects[i].getInt('eventId'),
				'nestedEvent_moreInfoLink');
			milink.href = "javascript:deploy('event.jsf?eid=" + 
				mappedObjects[i].getInt('eventId') + "')";
			milink.innerHTML = "More Info";
			dv.appendChild(time);
			dv.appendChild(name);
			dv.appendChild(speaker);
			dv.appendChild(state);
			dv.appendChild(milink);
			this.div.appendChild(dv);
		}
	}, 
	executeRenderEvent: function(incomingObject) {
		this.m = incomingObject.getObjects();
		this.div = e('div', 'ev');
		this.div.appendChild(JSAL.Domestic.ContextualRenderer.getHeading(
			incomingObject.getObjects()[0].get('eventName'),
			'Speaker: ' + incomingObject.getObjects()[0].get('speakerName')));
		this.div.appendChild(this.link('Genre: ', this.m[0].get('genreName'),
			"event.jsf?genre=" + this.m[0].get('genreId')));
		this.div.appendChild(this.link('Venue: ', this.m[0].get('venueName'),
			"venue.jsf?vid=" + this.m[0].get('venueId')));
		this.div.appendChild(this.link('Speaker: ',
			this.m[0].get('speakerName'), "speaker.jsf?sid=" + this.m[0].get(
			'speakerId')));
		this.div.appendChild(this.field('Ticket Price: ',
			'$' + this.m[0].getFloat('ticketPrice').toFixed(2)));
		var time =  this.m[0].getEpoch('date');
		this.div.appendChild(this.field('Date: ', time.toDateStr()));
		this.div.appendChild(this.field('Time: ', time.toTimeStr()));
		this.div.appendChild(this.link('State: ', toState(
			this.m[0].getInt('state')),
			"event.jsf?state=" + this.m[0].get('state')));
		this.div.appendChild(this.field('City: ', this.m[0].get('city')));
		this.div.appendChild(this.field('Address: ', this.m[0].get(
			'address')));
		
		var cartl = e('a', 'event_Cart_' +this.i++, 'event_Cartl');
		cartl.innerHTML = 'Purchase Tickets';
		cartl.href = "javascript:deploy('purchase.jsf?eid=" + 
			this.m[0].get('eventId') +"')";
		this.div.appendChild(cartl);

		
		this.addSimilar();
		
		JSAL.Domestic.ContextualRenderer.render(this.div);
	},
	addSimilar: function() {
		var sd = e('div', 'similar_e_' + this.m[0].get('eventId'),
			'event_similar_lab');
		sd.innerHTML = 'Similar events: ';
	
		if (this.m.length <= 1) {
			sd.innerHTML += 'none';
			this.div.appendChild(sd);
			return;
		}
		this.div.appendChild(sd);
		
		for (var i = 1; i < this.m.length; i++) {
			var dv = e('div', 'ev_' + this.m[i].get('eventId') + 'c', 
				'event_sc');
			var sim_ev = e('a', 'ev_' + this.m[i].get('eventId'), 'event_sim');
			sim_ev.style.fontWeight = "bold";
			sim_ev.href = "javascript:deploy('event.jsf?eid=" +
				this.m[i].get('eventId') + "')";
			sim_ev.innerHTML = this.m[i].get('eventName');
			var loc = e('span', 'evloc_' + this.m[i].get('eventId'),
				'event_sim_loc')
			loc.innerHTML = this.m[i].get('venueName') + 
				' (' + toState(this.m[i].getInt('state')) + ")";
			dv.appendChild(sim_ev);
			dv.appendChild(loc);
			this.div.appendChild(dv);
		}
	},
	label: function(text) {
		var l = e('span', 'e_l_' + this.i++, 'event_label');
		l.innerHTML = text;
		return l;
	},
	field: function(fname, fdata) {
		var d = e('div', 'e_f_' + this.i++, "nested_Event_Data");
		var dat = e('span', 'e_d_' + this.i++, "event_data");
		dat.innerHTML = fdata;
		d.appendChild(this.label(fname));
		d.appendChild(dat);
		return d;
	},
	link: function(fname, fdata, flink) {
		var d = e('div', 'e_f_' + this.i++, "nested_Event_Data");
		var dat = e('a', 'e_d_' + this.i++, "event_data");
		dat.innerHTML = fdata;
		dat.href = "javascript:deploy('" + flink +"');";
		d.appendChild(this.label(fname));
		d.appendChild(dat);
		return d;
	},
	i: 0
};
JSAL.Domestic.VenueRenderer = {
	renderVenue: function(io) {
		this.io = io.getObjects();
		var h1 = e('h1', '', '','Venue - ' + this.io[0].get('venueName'));
		var detoutline = e('div', '', 'search_result_innerContainer');
		var state = e('div','', 'search_result_item');
		var city = e('div','', 'search_result_item');
		var addr = e('div','', 'search_result_item');
		state.appendChild(e('span', '', 'venue_fname', 'State: '));
		state.appendChild(e('span', '', 'event_result_location',
			toState(this.io[0].getInt('state'))));
		city.appendChild(e('span', '', 'venue_fname', 'City: '));
		city.appendChild(e('span', '', 'event_result_location',
			this.io[0].get('city')));
		addr.appendChild(e('span', '', 'venue_fname', 'Address: '));
		addr.appendChild(e('span', '', 'event_result_location',
			this.io[0].get('address')));
		detoutline.appendChild(state);
		detoutline.appendChild(city);
		detoutline.appendChild(addr);
		var h32 = e('h3', '', '','Seating Plan');
		var img = e('img', '', 'booking_image');
		img.src = 'images/' + this.io[0].get('image');
		var h3 = e('h3', '', '','Upcoming events');
		var uecont = e('div', '', 'search_result_innerContainer');
		for (var i = 1; i < this.io.length; i++) {
			var itemcont = e('div', '', 'search_result_item');
			var itemName = e('a', '', 'search_result_eventLink',
				this.io[i].get('eventName'));
			itemName.href = 'javascript:deploy("event.jsf?eid=' + 
				this.io[i].get('eventId') + '")';
			var state = e('span', '', 'event_result_location', '(' +
				toState(this.io[i].getInt('state')) + ')');
			itemcont.appendChild(itemName);
			itemcont.appendChild(state);
			uecont.appendChild(itemcont);
		}
		this.div = e('div', 'speaker');
		this.div.appendChild(h1);
		this.div.appendChild(detoutline);
		this.div.appendChild(h32);
		this.div.appendChild(img);
		this.div.appendChild(h3);
		this.div.appendChild(uecont);
		JSAL.Domestic.ContextualRenderer.render(this.div);
	},
	renderVenueListing: function(io) {
		this.io = io.getObjects();
		var h1 = e('h1', '', '', 'Venue Listing');
		var h2 = e('h2', '', '', 'This is a listing of all the venues that we '+
			'sell tickets for. Click one for more info.');
		var datacont = e('div', '', 'search_result_innerContainer');
		for (var i = 0; i < this.io.length; i++) {
			var itemcont = e('div', '', 'search_result_item');
			var itemName = e('a', '', 'search_result_eventLink',
				this.io[i].get('venueName'));
			itemName.href = 'javascript:deploy("venue.jsf?vid=' + 
				this.io[i].get('venueId') + '")';
			var state = e('span', '', 'event_result_location', '(' +
				toState(this.io[i].getInt('state')) + ')');
			itemcont.appendChild(itemName);
			itemcont.appendChild(state);
			datacont.appendChild(itemcont);
		}
		this.div = e('div', 'venlist');
		this.div.appendChild(h1);
		this.div.appendChild(h2);
		this.div.appendChild(datacont);
		JSAL.Domestic.ContextualRenderer.render(this.div);
	}
};
JSAL.Domestic.SpeakerRenderer = {
	renderSpeaker: function(io) {
		this.io = io.getObjects();
		var h1 = e('h1', '', '', 'Speaker - ' + this.io[0].get('firstName') + ' ' +
			this.io[0].get('lastName'));
		var genrelist = e('div', '', 'speaker_genrelist', 'Genres: ' +  
			this.io[0].getGenreList('genreList').concat());
		var h3 = e('h3', '','', 'Upcoming events');
		var uecont = e('div', '', 'search_result_innerContainer');
		for (var i = 1; i < this.io.length; i++) {
			var itemcont = e('div', '', 'search_result_item');
			var itemName = e('a', '', 'search_result_eventLink',
				this.io[i].get('eventName'));
			itemName.href = 'javascript:deploy("event.jsf?eid=' + 
				this.io[i].get('eventId') + '")';
			var state = e('span', '', 'event_result_location', '(' +
				toState(this.io[i].getInt('state')) + ')');
			itemcont.appendChild(itemName);
			itemcont.appendChild(state);
			uecont.appendChild(itemcont);
		}
		this.div = e('div', 'speaker');
		this.div.appendChild(h1);
		this.div.appendChild(genrelist);
		this.div.appendChild(h3);
		this.div.appendChild(uecont);
		JSAL.Domestic.ContextualRenderer.render(this.div);
	},
	renderSpeakerListing: function(io) {
		this.io = io.getObjects();
		var h1 = e('h1', '', '', 'Speaker Listing');
		var h2 = e('h2', '', '', 'This is a listing of all the speakers that ' +
				'we sell tickets for. Click one for more info.');
		var datacont = e('div', '', 'search_result_innerContainer');
		for (var i = 0; i < this.io.length; i++) {
			var itemcont = e('div', '', 'search_result_item');
			var itemName = e('a', '', 'search_result_eventLink',
				this.io[i].get('firstName') + ' ' + this.io[i].get('lastName'));
			itemName.href = 'javascript:deploy("speaker.jsf?sid=' + 
				this.io[i].get('speakerId') + '")';
			itemcont.appendChild(itemName);
			datacont.appendChild(itemcont);
		}
		this.div = e('div', 'slist');
		this.div.appendChild(h1);
		this.div.appendChild(h2);
		this.div.appendChild(datacont);
		JSAL.Domestic.ContextualRenderer.render(this.div);
	}
}
JSAL.Domestic.SearchRenderer = {
	createForm: function() {
		this.sfield = e('input', 'search_in', 'search_field');
		this.sfield.onkeypress = chkssub;
		this.slink = e('a', '', 'search_link', 'Search');
		this.slink.href = "javascript:JSAL.Domestic.SearchRenderer.search();"
		$('search_form').appendChild(this.sfield);
		$('search_form').appendChild(this.slink);
	},
	search: function() {
		new Ajax.Updater('fl_rfr', 'search.jsf?q='
		+ $('search_in').value, {evalScripts:true});
		if ($('sr_a'))
		$('search_results').removeChild($('sr_a'));
	},
	renderSearchResult: function(io) {
		this.io = io.getObjects();
		var parentDiv = e('div', 'sr_a', 'search_result_innerContainer')
		for (var i = 0; i < this.io.length; i++) {
			var thisDiv = e('div', '', 'search_result_item');
			var eventLink = e('a', '', 'search_result_eventLink');
			eventLink.innerHTML = this.io[i].get('eventName');
			eventLink.href = 'javascript:deploy("event.jsf?eid='+
					this.io[i].get('eventId')+'");';
			var eventLoc = e('span',
				'', 'event_result_location', '(' + 
				toState(this.io[i].getInt('state')) + 
				' - ' + this.io[i].get('venueName') + ')');
			thisDiv.appendChild(eventLink);
			thisDiv.appendChild(eventLoc);
			parentDiv.appendChild(thisDiv);
		}
		$('search_results').appendChild(parentDiv);
	}
};
JSAL.Domestic.PurchaseRenderer = {
	MAX_PURCHASE: 15,
	BOOKING_TIMEOUT: 180,
	IS_RENDERED: false,
	updateTable: function(io) {
		this.tab.assert(
			io.getObjects()[0].get('seatingPlan'),
			io.getObjects()[0].get('currentlyReserved')
		);
	},
	executeRenderPurchasable: function(io) {
		this.IS_RENDERED = true;
		this.JUST_CARTED = false;
		this.prevp = new Point();
		this.brief = io.getObjects()[0];
		this.purchase = io.getObjects()[1];
		this.div = e('div', 'purchase_t_' + this.brief.get('eventId'));
		this.CURRENT_EID = this.brief.getInt('eventId');
		this.div.appendChild(this.createEventAndData());
		this.tab = new SeatingPlan(this.purchase.get('seatingPlan'));
		this.tab.assert_ur(this.purchase.get('currentlyReserved'));
		this.tdiv = e('div', 'p_plan_o');
		var timerupd = e('div', 'p_timeout'+this.CURRENT_EID, 'p_timeout');
		var subt = e('span', 'timer'+this.CURRENT_EID, 'p_timetxt');
		timerupd.innerHTML = 'Bookings time left: ';
		timerupd.appendChild(subt);
		timerupd.innerHTML += 's';
		this.tdiv.appendChild(this.tab.getTable());
		this.div.appendChild(timerupd);
		this.div.appendChild(this.tdiv);
		this.div.appendChild(this.createManualFields());
		JSAL.Domestic.ContextualRenderer.render(this.div);
		this.tab.update();
		this.timerBegin();
		deployCallback.add(this.removePageListener.bind(this), true);
	},
	removePageListener: function() {
		this.IS_RENDERED = false;
		
		if (this.JUST_CARTED == true)
			return;
		
		new Ajax.Request('purchase.jsf?eid='+this.CURRENT_EID+'&m=2');
	},
	timerBegin: function() {
		this.count = this.BOOKING_TIMEOUT;
		this.timer_thread = new Thread(this.__timer.bind(this));
		this.timer_thread.onRestart.add(this.timerRestart.bind(this));
		this.timer_thread.recurse(1000);
		deployCallback.add(this.timer_thread.stop.bind(this));
	},
	timerRestart: function() {
		this.count = this.BOOKING_TIMEOUT;
	},
	__timer: function() {
		if (!$('timer'+this.CURRENT_EID)) {
			this.timer_thread.stop();
			return;
		}
		
		if (this.count > 0)
			$('timer'+this.CURRENT_EID).innerHTML = this.count--;
		else {
			$('timer'+this.CURRENT_EID).innerHTML = 0;
			this.haltTimer();
		}
	},
	haltTimer: function() {
		this.timer_thread.stop();
		this.tab.thread.run();
	},
	sig: function() {
		return this.CURRENT_EID + "_" + this.i++;
	},
	createEventAndData: function() {
		var con = e('div', 'dcont_' + this.sig());
		var h1 = e('h1', 'h1_' + this.sig());
		var h2 = e('h2', 'h2_' + this.sig());
		h1.innerHTML = 'Ticket Selection - ' + this.brief.get('eventName');
		h2.innerHTML = 'Here, you can select the exact seats you would like to'+
			' purchase, or let us automatically choose them for you. Read on '+
			'for more information';
		var tc1 = e('div', 'tc1_' + this.sig(), 'textcontent');
		tc1.innerHTML = 'If you would not like to manually select your ' +
		'tickets, please enter the amount of tickets you would like to ' +
		'purchase below and we do our best to find a contiguous group ' +
		'of seats for you.';
		var tc2 = e('div', 'tc2_' + this.sig(), 'textcontent');
		tc2.innerHTML = 'Below is a representation of the seating plan ' +
		'of the particular venue this event is being held in. '+
		'we have already reserved a ticket for you, but this reservation will'+
		' only last for 5 minutes (you can see a counter at the bottom of ' +
		'this page), so please act quickly.<br/><br/>Once you have added '+
		'tickets to your cart, they will be reserved for a further 10 minutes,'+
		' after which we cannot guarantee your spot, and purchasing will ' +
		'select the nearest available seats.';
		con.appendChild(h1);
		con.appendChild(h2);
		con.appendChild(tc1);
		con.appendChild(this.createAutoFields());
		con.appendChild(tc2);
		return con;
	},
	createAutoFields: function() {
		var form = e('form', 'p_f_'+this.CURRENT_EID, 'purchase_aform');
		var ddb = e('select', 'p_ddb_'+this.sig(), 'purchase_ddbox');
		var sub = e('a', 'p_sub_'+this.sig(), 'purchase_sub');
		for (var i = 1; i <= this.MAX_PURCHASE; i++) {
			var o = e('option', 'p_op_'+this.sig(), 'purchase_ddopt');
			o.value = i;
			o.innerHTML = i;
			ddb.appendChild(o);
		}
		sub.innerHTML = 'Add to cart';
		var lab1 = e('span', 'p_f_l_'+this.sig(), 'purchase_f_label');
		lab1.innerHTML = 'Quantity: ';
		ddb.name = "q";
		sub.href = 'javascript:JSAL.Domestic.PurchaseRenderer.fsub();';
		form.appendChild(lab1);
		form.appendChild(ddb);
		form.appendChild(sub);
		return form;
	},
	createManualFields: function() {
		var cont = e('div', 'p_mf_'+this.sig(), 'purchase_aform');
		var bt = e('a', 'p_mansub'+this.sig(), 'purchase_sub');
		bt.innerHTML = 'Add reserved seats to cart';	
		bt.href = 'javascript:JSAL.Domestic.PurchaseRenderer.msub();';
		cont.appendChild(bt);
		return cont;
	},
	fsub: function() {
		this.JUST_CARTED = true;
		var form = $('p_f_'+this.CURRENT_EID);
		var tosend = Form.serialize(form);
												//method
		deploy('purchase.jsf?eid='+this.CURRENT_EID+'&m=0&'+tosend);
	},
	msub: function() {
		this.JUST_CARTED = true;
		deploy('purchase.jsf?eid='+this.CURRENT_EID+'&m=1')
	},
	i: 0,
	reserve: function(x, y) {
		if (this.count == 0)
			this.timerBegin();
		else this.count = this.BOOKING_TIMEOUT;
		this.prevp = new Point(x, y);
		$(x + 'x' + y).style.backgroundColor = "green";
		new Ajax.Updater('fl_rfr', 'purchase.jsf?eid=' + 
			this.brief.get('eventId') + "&reserve=1&x=" + x + "&y=" + y,
			{ evalScripts:true });
	},
	dereserve: function(x, y) {
		this.prevp = new Point(x, y);
		$(x + 'x' + y).style.backgroundColor = "#c4c0b5";
		new Ajax.Updater('fl_rfr', 'purchase.jsf?eid=' + 
			this.brief.get('eventId') + "&deres=1&x=" + x + "&y=" + y,
			{ evalScripts:true });
	},
	reserveMulti: function(fx, fy) {
		var points = this.prevp.rect(fx, fy);
		var xstr = "", ystr = "";
		for (var i = 0; i < points.length; i++) {
			xstr += points[i].x;
			ystr += points[i].y;
			if (i < points.length - 1) {
				xstr += ",";
				ystr += ",";
			}
		}
		new Ajax.Updater('fl_rfr', 'purchase.jsf?eid=' + 
			this.brief.get('eventId') + "&resm=1&x=" + xstr + "&y=" + ystr,
			{ evalScripts:true });
	},
	dereserveMulti: function(fx, fy) {
		var points = this.prevp.rect(fx, fy);
		var xstr = "", ystr = "";
		for (var i = 0; i < points.length; i++) {
			xstr += points[i].x;
			ystr += points[i].y;
			if (i < points.length - 1) {
				xstr += ",";
				ystr += ",";
			}
		}
		new Ajax.Updater('fl_rfr', 'purchase.jsf?eid=' + 
			this.brief.get('eventId') + "&deresm=1&x=" + xstr + "&y=" + ystr,
			{ evalScripts:true });
	},
	CURRENT_EID: 0
};

JSAL.Domestic.Handler = {
	/*
	* see item code identifiers in contextualrenderer for a reference of item
	* codes
	*******/
	expected: 0,
	expecting: function(itemCode) {
		this.expected = itemCode;
	},
	renderExpectedContent: function(object) {
		JSAL.Domestic.ContextualRenderer.renderContentByItemCode(this.expected,
			object);
		this.resolveExpectation;
	},
	isExpectingContent: function() {
		return this.expected != 0;
	},
	resolveExpectation: function() {
		this.expected = 0;
	},
	getExpectedPropertySet: function() {
		return JSAL.Domestic.ContextualRenderer.propertySetFor(this.expected);
	}
};

/* declaration of custom property sets 

this will define the order in which properties should be sent to the JSAL */

JSAL.addPropertySet(new JSAL.PropertySet('event', [
	'venueId', 
	'venueName',
	'speakerId', 
	'speakerName', 
	'eventId', 
	'eventName', 
	'ticketPrice',
	'date', 
	'genreId', 
	'genreName',
	'suburb',
	'city',
	'state',
	'address'
], 'eventName.venueName.speakerName.genreName.ticketPrice.date'));
JSAL.addPropertySet(new JSAL.PropertySet('briefEvent', [
	'venueId',
	'venueName',
	'eventId', 
	'eventName',
	'state',
], 'eventName.venueName'));
JSAL.addPropertySet(new JSAL.PropertySet('venue', [
	'venueId',
	'venueName',
	'state',
	'city',
	'address',
	'image'
], 'venueName.city.state.address'));
JSAL.addPropertySet(new JSAL.PropertySet('briefVenue', [
	'venueId',
	'venueName',
	'state'
], 'venueName.city.state.address'));
JSAL.addPropertySet(new JSAL.PropertySet('speaker', [
	'speakerId',
	'firstName',
	'lastName',
	'genreList'
], 'speakerId.firstName.lastName'));
JSAL.addPropertySet(new JSAL.PropertySet('purchase', [
	'seatingPlan',
	'currentlyReserved'
], 'seatingPlan.currentlyReserved'));
JSAL.addPropertySet(new JSAL.PropertySet('booking', [
	'bookingId',
	'ticketCount',
	'date',
	'image'
], 'bookingId.image'));
JSAL.addPropertySet(new JSAL.PropertySet('briefBooking', [
	'eventId',
	'eventName',
	'venueName',
	'bookingId',
	'ticketCount',
	'date'
], 'bookingId.eventId.eventName'));
/******************************************************************************
 	EPOCH DECRYPTION todo: finish this
******************************************************************************/

var Epoch = Class.create();
Epoch.DAY_VALUE = 1440;
Epoch.toDayStart = function(epoch) {
	var epoch = new Epoch(epoch);
	epoch.setHour(0);
	epoch.setMinute(0);
	return epoch.index();
};
Epoch.monthToStr = function(month) {
	switch (month) {
		case 1: return "January";
		case 2: return "February";
		case 3: return "March";
		case 4: return "April";
		case 5: return "May";
		case 6: return "June";
		case 7: return "July";
		case 8: return "August";
		case 9: return "September";
		case 10: return "October";
		case 11: return "November";
		case 12: return "December";
	}
},
Epoch.prototype = {
	initialize: function(epoch) {
		this.epoch = epoch;
		this.year = 1;
		this.month = 1;
		this.day = 2;
		this.hour = 0;
		this.minute = 0;
		this.calculateTime(epoch);
	},
	calculateTime: function(minutes) {
		var months = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		var y_index = 365 * 24 * 60;
		var l_index = y_index + 24 * 60;
		var m_index = new Array();
		for (var i = 1; i <= 12; i++)
			m_index[i] = months[i] * 24 * 60;
		var d_index = 24 * 60;
		var lycounter = 0;
		while (minutes >= y_index) {
			this.year++;
			minutes -= (lycounter++ % 4 == 0) ? l_index : y_index;
		}
		
		for (var i = this.month; i <= 12; i++) {
			if (minutes - m_index[i] < 0)
				break;
			minutes -= m_index[i];
			this.month++;
		}
		
		while (minutes >= d_index) {
			this.day++;
			minutes -= d_index;
		}
		
		while (minutes >= 60) {
			this.hour++;
			minutes -= 60;
		}
		
		this.minute += minutes;
	},
	index: function() {
		return this.getEpoch();
	},
	getDay: function() {
		return this.day;
	},
	getMonth: function() {
		return this.month;
	},
	getYear: function() {
		return this.year;
	},
	getMinute: function() {
		return this.minute;
	},
	getHour: function() {
		return this.hour;
	},