/*
 * SitePoint IEFix
 * 
 * Compatablity Fixes for Aspire
 * 
 * 17th June, 2011
 */

if(typeof console === "undefined") {
	console = {
		log: function() { },
		error: function() {},
		time: function() {},
		timeEnd: function() {}
	};
}

/*

xmlrpc.js beta version 1
Tool for creating XML-RPC formatted requests in JavaScript

Copyright 2001 Scott Andrew LePera
scott@scottandrew.com
http://www.scottandrew.com/xml-rpc

License:
You are granted the right to use and/or redistribute this
code only if this license and the copyright notice are included
and you accept that no warranty of any kind is made or implied
by the author.

*/

function XMLRPCMessage(methodname){
  this.method = methodname||"system.listMethods";
  this.params = [];
  return this;
}

XMLRPCMessage.prototype.setMethod = function(methodName){
  if (!methodName) return;
  this.method = methodName;
}

XMLRPCMessage.prototype.addParameter = function(data){
  if (arguments.length==0) return;
  this.params[this.params.length] = data;
}

XMLRPCMessage.prototype.xml = function(){

  var method = this.method;

  // assemble the XML message header
  var xml = "";

  xml += "<?xml version=\"1.0\"?>\n";
  xml += "<methodCall>\n";
  xml += "<methodName>" + method+ "</methodName>\n";
  xml += "<params>\n";

  // do individual parameters
  for (var i = 0; i < this.params.length; i++){
	 var data = this.params[i];
	 xml += "<param>\n";

	 xml += "<value>" + XMLRPCMessage.getParamXML(XMLRPCMessage.dataTypeOf(data),data) + "</value>\n";

	 xml += "</param>\n";
  }

  xml += "</params>\n";
  xml += "</methodCall>";

  return xml; // for now
}

XMLRPCMessage.dataTypeOf = function (o){
  // identifies the data type
  var type = typeof(o);
  type = type.toLowerCase();
  switch(type){
	 case "number":
		if (Math.round(o) == o) type = "i4";
		else type = "double";
		break;
	 case "object":
		var con = o.constructor;
		if (con == Date) type = "date";
		else if (con == Array) type = "array";
		else type = "struct";
		break;
  }
  return type;
}

XMLRPCMessage.doValueXML = function(type,data){
  var xml = "<" + type + ">" + data + "</" + type + ">";
  return xml;
}

XMLRPCMessage.doBooleanXML = function(data){
  var value = (data==true)?1:0;
  var xml = "<boolean>" + value + "</boolean>";
  return xml;
}

XMLRPCMessage.doDateXML = function(data){
  var xml = "<dateTime.iso8601>";
  xml += dateToISO8601(data);
  xml += "</dateTime.iso8601>";
  return xml;
}

XMLRPCMessage.doArrayXML = function(data){
  var xml = "<array><data>\n";
  for (var i = 0; i < data.length; i++){
	 xml += "<value>" + XMLRPCMessage.getParamXML(XMLRPCMessage.dataTypeOf(data[i]),data[i]) + "</value>\n";
  }
  xml += "</data></array>\n";
  return xml;
}

XMLRPCMessage.doStructXML = function(data){
  var xml = "<struct>\n";
  for (var i in data){
	 xml += "<member>\n";
	 xml += "<name>" + i + "</name>\n";
	 xml += "<value>" + XMLRPCMessage.getParamXML(XMLRPCMessage.dataTypeOf(data[i]),data[i]) + "</value>\n";
	 xml += "</member>\n";
  }
  xml += "</struct>\n";
  return xml;
}

XMLRPCMessage.getParamXML = function(type,data){
  var xml;
  switch (type){
	 case "date":
		xml = XMLRPCMessage.doDateXML(data);
		break;
	 case "array":
		xml = XMLRPCMessage.doArrayXML(data);
		break;
	 case "struct":
		xml = XMLRPCMessage.doStructXML(data);
		break;
	  case "boolean":
		xml = XMLRPCMessage.doBooleanXML(data);
		break;
	 default:
		xml = XMLRPCMessage.doValueXML(type,data);
		break;
  }
  return xml;
}

function dateToISO8601(date){
  // wow I hate working with the Date object
  var year = new String(date.getYear());
  var month = leadingZero(new String(date.getMonth()));
  var day = leadingZero(new String(date.getDate()));
  var time = leadingZero(new String(date.getHours())) + ":" + leadingZero(new String(date.getMinutes())) + ":" + leadingZero(new String(date.getSeconds()));

  var converted = year+month+day+"T"+time;
  return converted;
}

function leadingZero(n){
  // pads a single number with a leading zero. Heh.
  if (n.length==1) n = "0" + n;
  return n;
}

// fire off an xmlrpc call
jQuery.xmlrpc = function(url,method,params,callback,async) {
	// asynchonous by default
	if (typeof(async) == 'undefined') async = true;

	var msg = new XMLRPCMessage(method);
	for(i=0; i<params.length; i++) msg.addParameter(params[i]);

	$.ajax({
		type: "POST",
		url: url,
		data: msg.xml(),
		dataType: 'xml',
		contentType: 'text/xml',
		processData: false,
		complete: callback,
		async: async
	});
}

// fire off a xmlrpc call that is notify, e.g no return value checked
jQuery.xmlrpcNotify = function(url,method,params) {
	var msg = new XMLRPCMessage(method);
	for(i=0; i<params.length; i++) msg.addParameter(params[i]);
	var http = new XMLHttpRequest();
	var xml = msg.xml();
	http.open('POST', url, true);
	http.setRequestHeader("Content-type","text/xml");
	http.setRequestHeader("Content-length",xml.length);
	http.setRequestHeader("Connection", "close");
	http.send(xml);
}

/**
 * Gazette.Rpc - Remote procedure call interface
 *
 * This interface should be used for all RPCs in Gazette.
 * Currently uses JQuery XMLRPC plugin.
 *
 * @see xmlrpc.js
 * @todo Implement JSON alternative
 * @author Andrew Markham <andrew.markham@sitepoint.com>
 */
var Gazette = Gazette || {};
Gazette.Rpc = Gazette.Rpc || {};
/**
 * Call a remote method and execute 'callback' on completion.
 * @param string    url 		url of RPC endpoint
 * @param string    method 		RPC method
 * @param array     params 		RPC params
 * @param function  callback 	function to execute on completion
 * @param async     boolean 	execute asynchronously (true) or synchronously (false)
 */
Gazette.Rpc.call = function(url, method, params, callback, async)
{
	$.xmlrpc(url, method, params, callback, async || true);
};	
/**
 * Parses the RPC response into a Javascript object
 * @param XMLHttpResponse response;
 * @return object
 */
Gazette.Rpc.parseResponse = function(response)
{
	var o = new Object;
	$(response.responseXML).find('member').each(function(){
		name    = $(this).find('name').text();
		o[name] = $(this).find('value').text();
	});
	return o;
};
/**
 * Call a remote method but don't wait for a response.
 * @param string url    url of RPC server
 * @param string method RPC method
 * @param array  params RPC params
 */
Gazette.Rpc.notify = function(url, method, params)
{
	$.xmlrpcNotify(url, method, params);
};

// requires jQuery
$(document).ready(function(){
	$('a[rel="external"]').each(function(){
		this.target = "_blank";
	});
});

// requires jQuery
$(document).ready(function(){
	$('a[rel="external"]').each(function(){
		this.target = "_blank";
	});
});

/*
 * Thickbox 3.1 - One Box To Rule Them All.
 * By Cody Lindley (http://www.codylindley.com)
 * Copyright (c) 2007 cody lindley
 * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
*/
		  
var tb_pathToImage = "/images/loadingAnimation.gif";

/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/

//on page load call tb_init
$(document).ready(function(){   
	tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
	imgLoader = new Image();// preload image
	imgLoader.src = tb_pathToImage;
});

//add thickbox to href & area elements that have a class of .thickbox
function tb_init(domChunk){
	$(domChunk).click(function(){
	var t = this.title || this.name || null;
	var a = this.href || this.alt;
	var g = this.rel || false;
	tb_show(t,a,g);
	this.blur();
	return false;
	});
}

function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link

	try {
		if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
			$("body","html").css({height: "100%", width: "100%"});
			$("html").css("overflow","hidden");
			if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6
				$("body").append("<iframe id='TB_HideSelect'></iframe><div id='TB_overlay'></div><div id='TB_window'></div>");
				$("#TB_overlay").click(tb_remove);
			}
		}else{//all others
			if(document.getElementById("TB_overlay") === null){
				$("body").append("<div id='TB_overlay'></div><div id='TB_window'></div>");
				$("#TB_overlay").click(tb_remove);
			}
		}
		
		if(tb_detectMacXFF()){
			$("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash
		}else{
			$("#TB_overlay").addClass("TB_overlayBG");//use background and opacity
		}
		
		if(caption===null){caption="";}
		$("body").append("<div id='TB_load'><img src='"+imgLoader.src+"' /></div>");//add loader to the page
		$('#TB_load').show();//show loader
		
		var baseURL;
	   if(url.indexOf("?")!==-1){ //ff there is a query string involved
			baseURL = url.substr(0, url.indexOf("?"));
	   }else{ 
	   		baseURL = url;
	   }
	   
	   var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/;
	   var urlType = baseURL.toLowerCase().match(urlString);

		if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images
				
			TB_PrevCaption = "";
			TB_PrevURL = "";
			TB_PrevHTML = "";
			TB_NextCaption = "";
			TB_NextURL = "";
			TB_NextHTML = "";
			TB_imageCount = "";
			TB_FoundURL = false;
			if(imageGroup){
				TB_TempArray = $("a[rel="+imageGroup+"]").get();
				for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) {
					var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString);
						if (!(TB_TempArray[TB_Counter].href == url)) {						
							if (TB_FoundURL) {
								TB_NextCaption = TB_TempArray[TB_Counter].title;
								TB_NextURL = TB_TempArray[TB_Counter].href;
								TB_NextHTML = "<span id='TB_next'>&nbsp;&nbsp;<a href='#'>Next &gt;</a></span>";
							} else {
								TB_PrevCaption = TB_TempArray[TB_Counter].title;
								TB_PrevURL = TB_TempArray[TB_Counter].href;
								TB_PrevHTML = "<span id='TB_prev'>&nbsp;&nbsp;<a href='#'>&lt; Prev</a></span>";
							}
						} else {
							TB_FoundURL = true;
							TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length);											
						}
				}
			}

			imgPreloader = new Image();
			imgPreloader.onload = function(){		
			imgPreloader.onload = null;
				
			// Resizing large images - orginal by Christian Montoya edited by me.
			var pagesize = tb_getPageSize();
			var x = pagesize[0] - 150;
			var y = pagesize[1] - 150;
			var imageWidth = imgPreloader.width;
			var imageHeight = imgPreloader.height;
			if (imageWidth > x) {
				imageHeight = imageHeight * (x / imageWidth); 
				imageWidth = x; 
				if (imageHeight > y) { 
					imageWidth = imageWidth * (y / imageHeight); 
					imageHeight = y; 
				}
			} else if (imageHeight > y) { 
				imageWidth = imageWidth * (y / imageHeight); 
				imageHeight = y; 
				if (imageWidth > x) { 
					imageHeight = imageHeight * (x / imageWidth); 
					imageWidth = x;
				}
			}
			// End Resizing
			
			TB_WIDTH = imageWidth + 30;
			TB_HEIGHT = imageHeight + 60;
			$("#TB_window").append("<a href='' id='TB_ImageOff' title='Close'><img id='TB_Image' src='"+url+"' width='"+imageWidth+"' height='"+imageHeight+"' alt='"+caption+"'/></a>" + "<div id='TB_caption'>"+caption+"<div id='TB_secondLine'>" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "</div></div><div id='TB_closeWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a> or Esc Key</div>"); 		
			
			$("#TB_closeWindowButton").click(tb_remove);
			
			if (!(TB_PrevHTML === "")) {
				function goPrev(){
					if($(document).unbind("click",goPrev)){$(document).unbind("click",goPrev);}
					$("#TB_window").remove();
					$("body").append("<div id='TB_window'></div>");
					tb_show(TB_PrevCaption, TB_PrevURL, imageGroup);
					return false;	
				}
				$("#TB_prev").click(goPrev);
			}
			
			if (!(TB_NextHTML === "")) {		
				function goNext(){
					$("#TB_window").remove();
					$("body").append("<div id='TB_window'></div>");
					tb_show(TB_NextCaption, TB_NextURL, imageGroup);				
					return false;	
				}
				$("#TB_next").click(goNext);
				
			}

			document.onkeydown = function(e){ 	
				if (e == null) { // ie
					keycode = event.keyCode;
				} else { // mozilla
					keycode = e.which;
				}
				if(keycode == 27){ // close
					tb_remove();
				} else if(keycode == 190){ // display previous image
					if(!(TB_NextHTML == "")){
						document.onkeydown = "";
						goNext();
					}
				} else if(keycode == 188){ // display next image
					if(!(TB_PrevHTML == "")){
						document.onkeydown = "";
						goPrev();
					}
				}	
			};
			
			tb_position();
			$("#TB_load").remove();
			$("#TB_ImageOff").click(tb_remove);
			$("#TB_window").css({display:"block"}); //for safari using css instead of show
			};
			
			imgPreloader.src = url;
		}else{//code to show html
			
			var queryString = url.replace(/^[^\?]+\??/,'');
			var params = tb_parseQuery( queryString );

			TB_WIDTH = (params['width']*1) + 30 || 630; //defaults to 630 if no paramaters were added to URL
			TB_HEIGHT = (params['height']*1) + 40 || 440; //defaults to 440 if no paramaters were added to URL
			ajaxContentW = TB_WIDTH - 30;
			ajaxContentH = TB_HEIGHT - 45;
			
			if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window		
					urlNoQuery = url.split('TB_');
					$("#TB_iframeContent").remove();
					if(params['modal'] != "true"){//iframe no modal
						$("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a> or Esc Key</div></div><iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;' > </iframe>");
					}else{//iframe modal
					$("#TB_overlay").unbind();
						$("#TB_window").append("<iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;'> </iframe>");
					}
			}else{// not an iframe, ajax
					if($("#TB_window").css("display") != "block"){
						if(params['modal'] != "true"){//ajax no modal
						$("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton'>close</a> or Esc Key</div></div><div id='TB_ajaxContent' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px'></div>");
						}else{//ajax modal
						$("#TB_overlay").unbind();
						$("#TB_window").append("<div id='TB_ajaxContent' class='TB_modal' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px;'></div>");	
						}
					}else{//this means the window is already up, we are just loading new content via ajax
						$("#TB_ajaxContent")[0].style.width = ajaxContentW +"px";
						$("#TB_ajaxContent")[0].style.height = ajaxContentH +"px";
						$("#TB_ajaxContent")[0].scrollTop = 0;
						$("#TB_ajaxWindowTitle").html(caption);
					}
			}
					
			$("#TB_closeWindowButton").click(tb_remove);
			
				if(url.indexOf('TB_inline') != -1){	
					$("#TB_ajaxContent").append($('#' + params['inlineId']).children());
					$("#TB_window").unload(function () {
						$('#' + params['inlineId']).append( $("#TB_ajaxContent").children() ); // move elements back when you're finished
					});
					tb_position();
					$("#TB_load").remove();
					$("#TB_window").css({display:"block"}); 
				}else if(url.indexOf('TB_iframe') != -1){
					tb_position();
					if($.browser.safari){//safari needs help because it will not fire iframe onload
						$("#TB_load").remove();
						$("#TB_window").css({display:"block"});
					}
				}else{
					$("#TB_ajaxContent").load(url += "&random=" + (new Date().getTime()),function(){//to do a post change this load method
						tb_position();
						$("#TB_load").remove();
						tb_init("#TB_ajaxContent a.thickbox");
						$("#TB_window").css({display:"block"});
					});
				}
			
		}

		if(!params['modal']){
			document.onkeyup = function(e){ 	
				if (e == null) { // ie
					keycode = event.keyCode;
				} else { // mozilla
					keycode = e.which;
				}
				if(keycode == 27){ // close
					tb_remove();
				}	
			};
		}
		
	} catch(e) {
		//nothing here
	}
}

//helper functions below
function tb_showIframe(){
	$("#TB_load").remove();
	$("#TB_window").css({display:"block"});
}

function tb_remove() {
 	$("#TB_imageOff").unbind("click");
	$("#TB_closeWindowButton").unbind("click");
	$("#TB_window").fadeOut("fast",function(){$('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();});
	$("#TB_load").remove();
	if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
		$("body","html").css({height: "auto", width: "auto"});
		$("html").css("overflow","");
	}
	document.onkeydown = "";
	document.onkeyup = "";
	return false;
}

function tb_position() {
$("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'});
	if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6
		$("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'});
	}
}

function tb_parseQuery ( query ) {
   var Params = {};
   if ( ! query ) {return Params;}// return empty object
   var Pairs = query.split(/[;&]/);
   for ( var i = 0; i < Pairs.length; i++ ) {
      var KeyVal = Pairs[i].split('=');
      if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
      var key = unescape( KeyVal[0] );
      var val = unescape( KeyVal[1] );
      val = val.replace(/\+/g, ' ');
      Params[key] = val;
   }
   return Params;
}

function tb_getPageSize(){
	var de = document.documentElement;
	var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
	var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
	arrayPageSize = [w,h];
	return arrayPageSize;
}

function tb_detectMacXFF() {
  var userAgent = navigator.userAgent.toLowerCase();
  if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
    return true;
  }
}



jQuery.autocomplete = function(input, options) {
	// Create a link to self
	var me = this;

	// Create jQuery object for input element
	var $input = $(input).attr("autocomplete", "off");

	// Apply inputClass if necessary
	if (options.inputClass) $input.addClass(options.inputClass);

	// Create results
	var results = document.createElement("div");
	// Create jQuery object for results
	var $results = $(results);
	$results.hide().addClass(options.resultsClass).css("position", "absolute");
	if( options.width > 0 ) $results.css("width", options.width);

	// Add to body element
	$("body").append(results);

	input.autocompleter = me;

	var timeout = null;
	var prev = "";
	var active = -1;
	var cache = {};
	var keyb = false;
	var hasFocus = false;
	var lastKeyPressCode = null;

	// flush cache
	function flushCache(){
		cache = {};
		cache.data = {};
		cache.length = 0;
	};

	// flush cache
	flushCache();

	// if there is a data array supplied
	if( options.data != null ){
		var sFirstChar = "", stMatchSets = {}, row = [];

		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
		if( typeof options.url != "string" ) options.cacheLength = 1;

		// loop through the array and create a lookup structure
		for( var i=0; i < options.data.length; i++ ){
			// if row is a string, make an array otherwise just reference the array
			row = ((typeof options.data[i] == "string") ? [options.data[i]] : options.data[i]);

			// if the length is zero, don't add to list
			if( row[0].length > 0 ){
				// get the first character
				sFirstChar = row[0].substring(0, 1).toLowerCase();
				// if no lookup array for this character exists, look it up now
				if( !stMatchSets[sFirstChar] ) stMatchSets[sFirstChar] = [];
				// if the match is a string
				stMatchSets[sFirstChar].push(row);
			}
		}

		// add the data items to the cache
		for( var k in stMatchSets ){
			// increase the cache size
			options.cacheLength++;
			// add to the cache
			addToCache(k, stMatchSets[k]);
		}
	}

	$input
	.keydown(function(e) {
		// track last key pressed
		lastKeyPressCode = e.keyCode;
		switch(e.keyCode) {
			case 38: // up
				e.preventDefault();
				moveSelect(-1);
				break;
			case 40: // down
				e.preventDefault();
				moveSelect(1);
				break;
			case 9:  // tab
			case 13: // return
				if( selectCurrent() ){
					// make sure to blur off the current field
					$input.get(0).blur();
					e.preventDefault();
				}
				break;
			default:
				active = -1;
				if (timeout) clearTimeout(timeout);
				timeout = setTimeout(function(){onChange();}, options.delay);
				break;
		}
	})
	.focus(function(){
		// track whether the field has focus, we shouldn't process any results if the field no longer has focus
		hasFocus = true;
	})
	.blur(function() {
		// track whether the field has focus
		hasFocus = false;
		hideResults();
	});

	hideResultsNow();

	function onChange() {
		// ignore if the following keys are pressed: [del] [shift] [capslock]
		if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ) return $results.hide();
		var v = $input.val();
		if (v == prev) return;
		prev = v;
		if (v.length >= options.minChars) {
			$input.addClass(options.loadingClass);
			requestData(v);
		} else {
			$input.removeClass(options.loadingClass);
			$results.hide();
		}
	};

 	function moveSelect(step) {

		var lis = $("li", results);
		if (!lis) return;

		active += step;

		if (active < 0) {
			active = 0;
		} else if (active >= lis.size()) {
			active = lis.size() - 1;
		}

		lis.removeClass("ac_over");

		$(lis[active]).addClass("ac_over");

		// Weird behaviour in IE
		// if (lis[active] && lis[active].scrollIntoView) {
		// 	lis[active].scrollIntoView(false);
		// }

	};

	function selectCurrent() {
		var li = $("li.ac_over", results)[0];
		if (!li) {
			var $li = $("li", results);
			if (options.selectOnly) {
				if ($li.length == 1) li = $li[0];
			} else if (options.selectFirst) {
				li = $li[0];
			}
		}
		if (li) {
			selectItem(li);
			return true;
		} else {
			return false;
		}
	};

	function selectItem(li) {
		if (!li) {
			li = document.createElement("li");
			li.extra = [];
			li.selectValue = "";
		}
		var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML);
		input.lastSelected = v;
		prev = v;
		$results.html("");
		$input.val(v);
		hideResultsNow();
		if (options.onItemSelect) setTimeout(function() { options.onItemSelect(li) }, 1);
	};

	// selects a portion of the input string
	function createSelection(start, end){
		// get a reference to the input element
		var field = $input.get(0);
		if( field.createTextRange ){
			var selRange = field.createTextRange();
			selRange.collapse(true);
			selRange.moveStart("character", start);
			selRange.moveEnd("character", end);
			selRange.select();
		} else if( field.setSelectionRange ){
			field.setSelectionRange(start, end);
		} else {
			if( field.selectionStart ){
				field.selectionStart = start;
				field.selectionEnd = end;
			}
		}
		field.focus();
	};

	// fills in the input box w/the first match (assumed to be the best match)
	function autoFill(sValue){
		// if the last user key pressed was backspace, don't autofill
		if( lastKeyPressCode != 8 ){
			// fill in the value (keep the case the user has typed)
			$input.val($input.val() + sValue.substring(prev.length));
			// select the portion of the value not typed by the user (so the next character will erase)
			createSelection(prev.length, sValue.length);
		}
	};

	function showResults() {
		// get the position of the input field right now (in case the DOM is shifted)
		var pos = findPos(input);
		// either use the specified width, or autocalculate based on form element
		var iWidth = (options.width > 0) ? options.width : $input.width();
		// reposition
		$results.css({
			width: parseInt(iWidth) + "px",
			top: (pos.y + input.offsetHeight) + "px",
			left: pos.x + "px"
		}).show();
	};

	function hideResults() {
		if (timeout) clearTimeout(timeout);
		timeout = setTimeout(hideResultsNow, 200);
	};

	function hideResultsNow() {
		if (timeout) clearTimeout(timeout);
		$input.removeClass(options.loadingClass);
		if ($results.is(":visible")) {
			$results.hide();
		}
		if (options.mustMatch) {
			var v = $input.val();
			if (v != input.lastSelected) {
				selectItem(null);
			}
		}
	};

	function receiveData(q, data) {
		if (data) {
			$input.removeClass(options.loadingClass);
			results.innerHTML = "";

			// if the field no longer has focus or if there are no matches, do not display the drop down
			if( !hasFocus || data.length == 0 ) return hideResultsNow();

			if ($.browser.msie) {
				// we put a styled iframe behind the calendar so HTML SELECT elements don't show through
				$results.append(document.createElement('iframe'));
			}
			results.appendChild(dataToDom(data));
			// autofill in the complete box w/the first match as long as the user hasn't entered in more data
			if( options.autoFill && ($input.val().toLowerCase() == q.toLowerCase()) ) autoFill(data[0][0]);
			showResults();
		} else {
			hideResultsNow();
		}
	};

	function parseData(data) {
		if (!data) return null;
		var parsed = [];
		var rows = data.split(options.lineSeparator);
		for (var i=0; i < rows.length; i++) {
			var row = $.trim(rows[i]);
			if (row) {
				parsed[parsed.length] = row.split(options.cellSeparator);
			}
		}
		return parsed;
	};

	function dataToDom(data) {
		var ul = document.createElement("ul");
		var num = data.length;

		// limited results to a max number
		if( (options.maxItemsToShow > 0) && (options.maxItemsToShow < num) ) num = options.maxItemsToShow;

		for (var i=0; i < num; i++) {
			var row = data[i];
			if (!row) continue;
			var li = document.createElement("li");
			if (options.formatItem) {
				li.innerHTML = options.formatItem(row, i, num);
				li.selectValue = row[0];
			} else {
				li.innerHTML = row[0];
				li.selectValue = row[0];
			}
			var extra = null;
			if (row.length > 1) {
				extra = [];
				for (var j=1; j < row.length; j++) {
					extra[extra.length] = row[j];
				}
			}
			li.extra = extra;
			ul.appendChild(li);
			$(li).hover(
				function() { $("li", ul).removeClass("ac_over"); $(this).addClass("ac_over"); active = $("li", ul).indexOf($(this).get(0)); },
				function() { $(this).removeClass("ac_over"); }
			).click(function(e) { e.preventDefault(); e.stopPropagation(); selectItem(this) });
		}
		return ul;
	};

	function requestData(q) {
		if (!options.matchCase) q = q.toLowerCase();
		var data = options.cacheLength ? loadFromCache(q) : null;
		// recieve the cached data
		if (data) {
			receiveData(q, data);
		// if an AJAX url has been supplied, try loading the data now
		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
			$.get(makeUrl(q), function(data) {
				data = parseData(data);
				addToCache(q, data);
				receiveData(q, data);
			});
		// if there's been no data found, remove the loading class
		} else {
			$input.removeClass(options.loadingClass);
		}
	};

	function makeUrl(q) {
		var url = options.url + "?q=" + encodeURI(q);
		for (var i in options.extraParams) {
			url += "&" + i + "=" + encodeURI(options.extraParams[i]);
		}
		return url;
	};

	function loadFromCache(q) {
		if (!q) return null;
		if (cache.data[q]) return cache.data[q];
		if (options.matchSubset) {
			for (var i = q.length - 1; i >= options.minChars; i--) {
				var qs = q.substr(0, i);
				var c = cache.data[qs];
				if (c) {
					var csub = [];
					for (var j = 0; j < c.length; j++) {
						var x = c[j];
						var x0 = x[0];
						if (matchSubset(x0, q)) {
							csub[csub.length] = x;
						}
					}
					return csub;
				}
			}
		}
		return null;
	};

	function matchSubset(s, sub) {
		if (!options.matchCase) s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	};

	this.flushCache = function() {
		flushCache();
	};

	this.setExtraParams = function(p) {
		options.extraParams = p;
	};

	this.findValue = function(){
		var q = $input.val();

		if (!options.matchCase) q = q.toLowerCase();
		var data = options.cacheLength ? loadFromCache(q) : null;
		if (data) {
			findValueCallback(q, data);
		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
			$.get(makeUrl(q), function(data) {
				data = parseData(data)
				addToCache(q, data);
				findValueCallback(q, data);
			});
		} else {
			// no matches
			findValueCallback(q, null);
		}
	}

	function findValueCallback(q, data){
		if (data) $input.removeClass(options.loadingClass);

		var num = (data) ? data.length : 0;
		var li = null;

		for (var i=0; i < num; i++) {
			var row = data[i];

			if( row[0].toLowerCase() == q.toLowerCase() ){
				li = document.createElement("li");
				if (options.formatItem) {
					li.innerHTML = options.formatItem(row, i, num);
					li.selectValue = row[0];
				} else {
					li.innerHTML = row[0];
					li.selectValue = row[0];
				}
				var extra = null;
				if( row.length > 1 ){
					extra = [];
					for (var j=1; j < row.length; j++) {
						extra[extra.length] = row[j];
					}
				}
				li.extra = extra;
			}
		}

		if( options.onFindValue ) setTimeout(function() { options.onFindValue(li) }, 1);
	}

	function addToCache(q, data) {
		if (!data || !q || !options.cacheLength) return;
		if (!cache.length || cache.length > options.cacheLength) {
			flushCache();
			cache.length++;
		} else if (!cache[q]) {
			cache.length++;
		}
		cache.data[q] = data;
	};

	function findPos(obj) {
		var curleft = obj.offsetLeft || 0;
		var curtop = obj.offsetTop || 0;
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
		return {x:curleft,y:curtop};
	}
}

jQuery.fn.autocomplete = function(url, options, data) {
	// Make sure options exists
	options = options || {};
	// Set url as option
	options.url = url;
	// set some bulk local data
	options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null;

	// Set default values for required options
	options.inputClass = options.inputClass || "ac_input";
	options.resultsClass = options.resultsClass || "ac_results";
	options.lineSeparator = options.lineSeparator || "\n";
	options.cellSeparator = options.cellSeparator || "|";
	options.minChars = options.minChars || 1;
	options.delay = options.delay || 400;
	options.matchCase = options.matchCase || 0;
	options.matchSubset = options.matchSubset || 1;
	options.matchContains = options.matchContains || 0;
	options.cacheLength = options.cacheLength || 1;
	options.mustMatch = options.mustMatch || 0;
	options.extraParams = options.extraParams || {};
	options.loadingClass = options.loadingClass || "ac_loading";
	options.selectFirst = options.selectFirst || false;
	options.selectOnly = options.selectOnly || false;
	options.maxItemsToShow = options.maxItemsToShow || -1;
	options.autoFill = options.autoFill || false;
	options.width = parseInt(options.width, 10) || 0;

	this.each(function() {
		var input = this;
		new jQuery.autocomplete(input, options);
	});

	// Don't break the chain
	return this;
}

jQuery.fn.autocompleteArray = function(data, options) {
	return this.autocomplete(null, options, data);
}

jQuery.fn.indexOf = function(e){
	for( var i=0; i<this.length; i++ ){
		if( this[i] == e ) return i;
	}
	return -1;
};
/**
 *	SitePoint Store Javascript
 */
var SitePoint = SitePoint || {};

$(function(){
	SitePoint.Store.init();
});

/**
 * class SitePoint.Store
 */
SitePoint.Store = (function()
{
	// Private
	var rpcUrl 					= '/rpc/xmlrpc';
	var minicartUrl				= '/store/minicart';
	var addToCartUrl			= '/store/addtocartform';
	var editCartUrl				= '/checkout';
	var cartUrl					= '/store/cart';
	var minicartContainer		= '#gz_minicartcontainer';
	var productImages			= '.gz_productimage';
	var minicartDiv				= '#gz_minicart';
	var cartContainer			= '#gz_editcart';
	var relatedProductClass		= 'gz_relatedproduct';
	var relatedProductsContainer= '#gz_relatedproducts';
	var minicartFlashOn			= '#afa';
	var minicartFlashOff		= '#fff';
	var asyncMethod				= 'Ajax';
	
	generateAsyncMethod=function() {
 		if (asyncMethod=="Ajax") {
			return function(url,data,callback,method) {
				method="post" ? jQuery.post(url,data,callback) : jQuery.get(url,data,callback);
			};
		};
	};

	return {
		init:function() {
			console.time('SitePoint.Store.init');
			// Decorate our newly created application with the asynchronous
			// method we are going to use.
			this.asyncRequest=generateAsyncMethod();
			
			// Set the submit functionality for all addToCartForms
			SitePoint.Store.applyBehaviours();

			console.timeEnd('SitePoint.Store.init');
		},
		applyBehaviours:function() {
			console.time('SitePoint.Store.applyBehaviours');
			// All form submits
			// unbind any submits first
			$(".gz_addtocartform").unbind();
			$(".gz_addtocartform").submit(function(e) 
			{
					e.preventDefault();
					productId = parseInt(this.productid.value);
					quantity  = parseInt(this.quantity.value);
					
					// Is this a related product?
					// $(this).hasClass(relatedProductClass) ? relatedProduct=true : relatedProduct=false;			
					$(this.quantity).addClass('gz_inputloading');	
					
					SitePoint.Store.addProductToCart(productId, quantity);
					return false;
				}
			);
			$("#gz_cartform").submit(
				function() {
					return false;
				}
			);
			// Set the click value for the submit buttons in this form
			$(".gz_updatecart").click(
				function() {
					SitePoint.Store.updateCart();
					return false;
				}
			);
			// Set the remove behaviours
			$(".gz_removecart").click(
				function() {
					SitePoint.Store.removeProductFromCart(this);
					return false;
				}
			);
			// Set the checkout
			$("#gz_checkoutbutton").click(
				function() {
					$("#gz_cartform").unbind();
					$("#gz_cartform").submit();
				}
			);
			// Show / hide options when delivery location changed.
			$('#ss_regular, #ss_express, #ss_outsideaustralia').click(
				SitePoint.Store.updateDeliveryLocation
				);
			SitePoint.Store.updateDeliveryLocation();
			
			// Blank totals when a cart option is changed
			$('input.cartoption').click(function(){
				$('td.total').html('-');
			});
			console.timeEnd('SitePoint.Store.applyBehaviours');
		},
		
		addProductToCart: function(productid, quantity)
		{
			Gazette.Rpc.call(rpcUrl, 'cart.addProduct', [productid, quantity], SitePoint.Store.addProductToCartComplete);
		},
		
		addProductToCartComplete: function(response) 
		{
			
			r = Gazette.Rpc.parseResponse(response);
		
			if ( r.message )
			{
				alert(r.message);
			}
			
			$('#quantity_'+r.productid).removeClass('gz_inputloading');
			
			relatedProduct = false;
			if ( relatedProduct ) 
			{
				SitePoint.Store.updateRelatedProductsDiv();
			} 
			else 
			{
				SitePoint.Store.updateAddToCartDiv(r.productid);
			}
			
			// load minicart into page.
			$('#gz_minicartcontainer').html("<img src='/images/loading.gif' />");
			$.ajax({
				url: '/minicart',
				async:false,
				success: function(data) {
				  $('#gz_minicartcontainer').html(data);
				
				},
				failed: function(data){
					alert("Failed to update minicart.");
				}
			});
		},

		flashMinicart:function() {
			$(minicartDiv).animate(
				{backgroundColor:minicartFlashOn},
				400,
				"swing",
				function() {
					$(minicartDiv).animate({backgroundColor:minicartFlashOff}, 400);
				}
			);
		},
		addThrobber:function(parentDiv,text) {
			if (!arguments[1]) text="Loading...";
			// Adds a throbber to the given parent div
			$(parentDiv).addClass('gz_loading');
			$(parentDiv).fadeTo(0.1,0.5, function() {
				$(parentDiv).before('<div class="gz_throbber"><strong>'+text+'</strong></div>');
				// Position the throbber
				$(parentDiv).prev().css("height",$(parentDiv).height());
				$(parentDiv).prev().css("width",$(parentDiv).width());
				//Move the strong element down into the middle of the div we are about to load
				$(parentDiv).prev().find("strong").css("top",$(parentDiv).height()/2);
				// Then display it
				$(parentDiv).prev().css("display","block");
			});
		},
		removeThrobber:function(parentDiv) {
			// Search through the given parentDiv for any throbbers, then
			// remove them
			$(parentDiv).prev().css("display","none");
			$(parentDiv).prev().remove();
			$(parentDiv).fadeTo(0.1,1);
			$(parentDiv).removeClass('gz_loading');
		},
		updateCartDiv:function(returnedHtml) {
			if(arguments[0]) {
				$(cartContainer).html(returnedHtml);
				SitePoint.Store.cartUpdated();
				SitePoint.Store.removeThrobber(cartContainer);
			} else {
				$(cartContainer).each(function() {
					$(this).load(
						editCartUrl,
						{'editcartform':1},
						function(){
							SitePoint.Store.cartUpdated();
							SitePoint.Store.removeThrobber(cartContainer);							
						}
					);
				});
			}
			SitePoint.Store.updateMinicartDiv();
		},
		updateMinicartDiv:function() {
			// This should be done via an asyncRequest
			$(minicartContainer).each(function() {
				$(this).load(
					minicartUrl,
					'',
					function() { 
						SitePoint.Store.flashMinicart();
					}
				);
			});
		},
		updateAddToCartDiv:function(productId) {
			div = $('#gz_addtocartform_'+productId).parent('div').get(0);
			$(div).each(function() {
				$(this).load(
					addToCartUrl,
					{productid:productId},
					function(){
						SitePoint.Store.applyBehaviours();
						SitePoint.Store.updateMinicartDiv();
					}
				);
			});
		},
		updateRelatedProductsDiv:function() {
			// @TODO - load the related products div
			/*$(this).load(
				addToCartUrl,
				{productid:productId},
				SitePoint.Store.applySubmitBehaviours
			);*/
			SitePoint.Store.addThrobber(cartContainer,"Adding Product...");
			SitePoint.Store.updateCartDiv();
		},


		
		removeProductFromCart:function(anchor)
		{
			// Extract the get string from the link, removing the ?
			if (confirm("You are about to remove a product from your cart. Are you sure?")) 
			{
				// Simple submit the delete button name, server will take care of the rest.
				name = $(anchor).attr('name');
		
				// Introduce our throbber here...
				SitePoint.Store.addThrobber(cartContainer, "Removing Product...");
	
				SitePoint.Store.asyncRequest(
					cartUrl,
					name+'=remove',
					function() {
						SitePoint.Store.updateCartDiv();
					},
					'post'
				);
			}
		},

		updateDeliveryLocation:function() {			
			$('#ss_regular').each(function(){
				if ( this.checked )
				{
					$('tr#ss_postage').hide();
					$('tr#ss_insuranceline').hide();
				}
				else
				{
					$('tr#ss_postage').hide();
					$('tr#ss_insuranceline').hide();
				}
			});
		},
		
		updateCart:function() {	
			// TODO: Validate cart - don't update if there are errors 
			
			$('input.gz_quantity').each(function(){
				// Check quantity is valid int
				re = /^\d+$/;
				if ( !re.test(this.value) )
				{
					// Give some feedback to user, maybe display an alert?
					$(this).css('border', 'solid 2px #f00');
				}
			});
		
			// Introduce our throbber here...
			SitePoint.Store.addThrobber(cartContainer,"Updating...");
		
			// Create an async request to POST it into the cart					
			var post=$('#gz_cartform').find('input').serialize();

			if (post!="") {
				
				SitePoint.Store.asyncRequest(
					editCartUrl,
					post,
					function(returnedHtml){
						SitePoint.Store.updateCartDiv();
					},
					"post"
				);
			}
		},
		cartUpdated:function() {
			// Re-apply our button behaviours
			SitePoint.Store.applyBehaviours();
		},
		getMiniCartDiv:function() {
			return minicartDiv;
		}
	};
})();


/*$preload=new Image();
$preload.src="/images/minicart_anim.gif";*/

Aspire=(function() {
	var loginUrl="/checkout";
	var loginForm="#gz_loginform";
	var loginFormContainer="#gz_loginformcontainer";
	var stubsDiv="#gz_stubs";
	var customerDetailsUrl="/checkout";
	var customerDetailsForm="#gz_customerdetailsform";
	var customerFormContainer="#gz_customerformcontainer";
	var minicartAnimationClass="ss_cartanim";
	var previousConflict=false;
	var searchForm="#ss_searchform";
	var searchResultContainerDiv="#ss_searchresults";
	var searchUrl="/search";
	var keypressUpdateTimer;
	var keypressUpdateDelay=3000;
	var minicartContainer = '#gz_minicartcontainer';
	var calcUrl='http://www.commbank.com.au/Today/ForeignExchange/TBC-FxCalc.htm';
	var officeLocator='http://www.nowwhere.com.au/austpost/postofficelocator/default.aspx';
	var cscLink="/what-is-a-csc";
	
	var togglesMap={
			"gz_personaldetailsok":"gz_personalfields",
			"gz_contactdetailsok":"gz_contactfields",
			"gz_unchangedsubscriptions":"gz_subscriptionfields",
			"gz_shiptocustomer":"gz_shipfields"
		}
		
	return {
	init:function() {
		console.time("Aspire.init");
		// Override completely the flashminicart animation for Aspire
		SitePoint.Store.flashMinicart=function() {
			var minicartDiv=SitePoint.Store.getMiniCartDiv();
			var minicartAnimClass=Aspire.getMinicartAnimClass();
			$(minicartDiv).addClass(minicartAnimClass);
			var minicartTimeout=setTimeout(function() {
				$(minicartDiv).removeClass(minicartAnimClass);
				clearTimeout(minicartTimeout);
			},4500);
		}
		
		/*Aspire.that=SitePoint.Store.updateCartDiv;
		SitePoint.Store.updateCartDiv=function() {
			// Is there a keypress timer already started?
			if(typeof(Aspire.keypressUpdateTimer)=='number') {
				// Clear it...
				clearTimeout(Aspire.keypressUpdateTimer);
				Aspire.keypressUpdateTimer=null;
			}
			
			// Call the original method
			SitePoint.Store.updateCartDiv();
			
			// Check to see what the users contact detail country is
			var customerLocation=$("select#gz_country").val();
			var deliveryLocation=$("input[name=deliverylocation]:checked").val();
			if (deliveryLocation=="outsideaustralia" && customerLocation=="AUS" && !Aspire.previousConflict) {
				// There was a conflict so lets change the interface a bit
				$('#gz_shiptocustomer').removeAttr("checked");
				Aspire.updateToggles();
			}
			
			Aspire.applyBehaviours();
		}*/
		
		jQuery(document).ready(function($) {
		$('a[rel*=facebox]').live("mousedown", function() { 
		  $(this).facebox({
			  loadingImage : '/images/loading.gif',
			  closeImage   : '/images/closelabel.png'
		  });
		})
	      })
	      
	      $(document).bind('beforeReveal.facebox', function() {
		  $("#facebox .content").empty();
	      });
		
		Aspire.storeCartUpdated = SitePoint.Store.cartUpdated;
		SitePoint.Store.cartUpdated=function() {
			Aspire.storeCartUpdated(); // Call original method
			Aspire.applyBehaviours();
		}
		
		// Product Magnify behaviour
		$('#ss_productmagnify').click(function() {
			var t = this.title || this.name || null;
			// 'a' is the larger image src location
			var a = this.href || this.alt;
					
			smallerImageSrcOriginal=$('#ss_productsmallimage').attr('src');
			// Need to remove the height and width tag
			
			smallerImageSrc=smallerImageSrcOriginal.substring(0,smallerImageSrcOriginal.indexOf('?'));
			
			$('#ss_magnifycontainer').html('<div style="position:relative"><img id="gz_smallimage" style="position:static;border-style:none;margin:0;width:640px;height:480px;" src="' + smallerImageSrc + '?width=640&height=480&method=pad" \/><div style="clear:both"><\/div></div>');
			
			smallerImageSrcAppended=smallerImageSrc+'#TB_inline?inlineId=ss_magnifycontainer&width=645&height=485';
			
			var g = this.rel || false;
			tb_show(t,smallerImageSrcAppended,g);
			SitePoint.Zoomer.Init('#gz_smallimage', smallerImageSrc + '?width=1024&height=768&method=pad&z=100');
			this.blur();
			return false;
		});
		
		/*$("a[href$='#electiveSelector']").click(function() {
			
			var id = this.id.replace("electives_", "");
			
			id = id.split('_');
			
			theId = parseInt(id[0]);
			theQty = parseInt(1);
			//SitePoint.Store.addProductToCart(theId, theQty);
			
			// Create a new hidden div
			$('body').append('<div id="electiveSelector" style="display:none"><h1>Select Electives</h1></div>');
			
			var loadMe = '/electives?id=' + id[0] + "&qty=" + id[1] + " #gz_maincontent";
		
			// Ajax the content into a div
			$('#electiveSelector').load(loadMe, function() {	
				// Manually call the thickbox
				tb_show("Add Electives", "#TB_inline?inlineId=electiveSelector&height=300&width=550", false);
			});
					
			return false;
		});*/

		// Look for any calculator links and apply our openCalc function...
		$("a[href$='/currency-converter']").click(function() {
			Aspire.openCalc();
			return false;
		});
		
		// Post office locator links too...
		$("a[href$='/post-office-locator']").click(function() {
			newWin = window.open(officeLocator, "Aspire", 'height=672,width=812,resizeable=1');
			if (window.focus) {newWin.focus()};
			return false;
		});
		
		$("a#ss_csclink").click(function() {				
			// Create a new hidden div
						$('body').append('<div id="ss_cscajax" style="display:none"><p>CSC (Card Security Code) is a new authentication scheme established by credit card companies to reduce the risk of credit card fraud for online transactions. It consists of requiring a card holder to enter the CSC number in at transaction time to verify that the card is on hand. Most banks have upgraded their card holders card using this new system.</p><p>The location of the CSC number depends on the type of credit card you are using. The graphics below will help you find the location of your CSC number based on the type of credit card you wish to use</p><img src="/images/csc.gif" alt="" /><img src="/images/csc2.png" alt="" /><p>Please <a href="/contact-us">contact us</a> if you have any queries.</div>');
	
			// Ajax the content into a div
			$('#ss_cscajax').load('/what-is-a-csc #gz_maincontent', function() {	
				// Manually call the thickbox
				tb_show("What is a CSC?", "#TB_inline?inlineId=ss_cscajax&height=300&width=550", false);
			});
					
			return false;
		});
		
		$("#singles").change(function() {
			$('#cloneMe').clone().appendTo('#more');
		});
		
		$('#gz_updatecartbutton').hide();
		
		$("#ccGroup").hide();
		$("#completeButton").hide();
		$("#poGroup").hide();
		
		$("input#gz_cc").click(function(e) {
			$("#poGroup").hide('fast');
			$("#ccGroup").show('fast');
			$("#completeButton").show();
		});
		
		$("input#gz_ca").click(function(e) {
			$("#ccGroup").hide('fast');
			$("#poGroup").hide('fast');
			$("#completeButton").show();
		});
		
		$("input#gz_po").click(function(e) {
			$("#ccGroup").hide('fast');
			$("#poGroup").show('fast');
			$("#completeButton").show();
		});
		
		if($('input#gz_po').is(':checked'))
		{
			$("#poGroup").show();
			$("#completeButton").show();
		}
		
		if($('input#gz_cc"').is(':checked'))
		{
			$("#ccGroup").show();
			$("#completeButton").show();
		}
		
		if($('input#gz_ca"').is(':checked'))
		{
			$("#completeButton").show();
		}
		
		// Product thumb/list view button behaviours
		Aspire.applyBehaviours();

		console.timeEnd("Aspire.init");
	},
	hideIt : function(qty)
	{
		var i;
		//qty = parseInt(qty) + 1;
	},
	// Enable auto-suggest on suburb fields (see: http://www.pengoworks.com/workshop/jquery/autocomplete_docs.txt)
	autoSuggestSuburbs : function(enabled, fields) 
	{
	        if ( enabled )
	        {
	        	$(fields.city).each(
	        		function() {
						$(fields.city).autocomplete('/store/suburbs', {
								minChars: 1, 
								autoFill: false, 
								delay: 500, 
								cacheLength: 1000, 
								maxItemsToShow: 6,
								extraParams: fields,
								formatItem: function(row) {
										return row[0] + ' ' + row[1] + ' ' + row[2];
								},
								onItemSelect: function(li) {
										$(this.extraParams.state).attr('value', li.extra[0]).pulse('#afa');
										$(this.extraParams.postcode).attr('value', li.extra[1]).pulse('#afa');
								}	
						});
					}
				);
					
	        }
	        else
	        {
	                $(fields.city).each(function(){
	                        $(this).unbind();
	                });
	        }
	},
	updateCountryRequires:function() {

	        if ($('select#gz_country').val()=='AUS') 
	        {
	                $('#ss_customerstaterequire').show();
	                $('#ss_customerpostcoderequire').show();
	        } 
	        else 
	        {
	                $('#ss_customerstaterequire').hide();
	                $('#ss_customerpostcoderequire').hide();
	        }

	        if ($('select#gz_shipcountry').val()=='AUS') 
	        {
	                $('#ss_shipstaterequire').show();
	                $('#ss_shippostcoderequire').show();
	        } 
	        else 
	        {
	                $('#ss_shipstaterequire').hide();
	                $('#ss_shippostcoderequire').hide();
	        }

	        Aspire.autoSuggestSuburbs($('select#gz_country').val() == 'AUS', { 
	                        city:     '#gz_city', 
	                        state:    '#gz_state', 
	                        postcode: '#gz_postcode' 
	                });

	        Aspire.autoSuggestSuburbs($('select#gz_shipcountry').val() == 'AUS', { 
	                        city:     '#gz_shipcity', 
	                        state:    '#gz_shipstate', 
	                        postcode: '#gz_shippostcode' 
	                });
	},
	checkDeliveryConflict:function() {
		var customerLocation=$("select#gz_country").val();
		var deliveryLocation=$("input[name=deliverylocation]:checked").val();
		if ($('#gz_shiptocustomer').attr("checked") || $('#gz_shipcountry').val()=="AUS") {
			if ( (deliveryLocation=="outsideaustralia" && customerLocation=="AUS")
			|| (deliveryLocation=="outsideaustralia" && $('#gz_shipcountry').val()=="AUS") ) {
				alert("You have selected postage outside of Australia and delivery to an Australian address. Please correct this conflict before proceeding.");
				$('#gz_shiptocustomer').removeAttr("checked");
				$('#gz_shipcountry').val("");
				Aspire.updateToggles();
				return true;
			}
		}
		return false;
	},	
	applyBehaviours:function() {
		console.time("Aspire.applyBehaviours");
		$('#gz_useraccountyes').click(function(){Aspire.updateAccountRadio()});
		$('#gz_useraccountno').click(function(){Aspire.updateAccountRadio()});
		$('#gz_agreement').click(function(){Aspire.updateAgreement()});
		$(loginForm).unbind();
		$(loginForm).submit(function(e) {
			if ((this.username.value!="")&&(this.password.value!="")) {
				SitePoint.Store.addThrobber(loginForm,"Logging In...");
				var post=jQuery.makeArray($(this).find('input'));
				if (post!="") {
					SitePoint.Store.asyncRequest(
						loginUrl,
						post,
						function(returnedHtml) {
							Aspire.loggedIn(jQuery.trim(returnedHtml));
						},
						'post'
					);
				}
			}
			return false;
		});
		
		$(searchForm).unbind();
		$(searchForm).submit(function(e) {
			if (this.keyword.value!="") {
				SitePoint.Store.addThrobber(searchResultContainerDiv,"Searching Products...");
				//var inputField=$(this).find('input');
				inputField.addClass('gz_inputloading');
				var post=jQuery.makeArray(inputField);
				if (post!="")  {
					SitePoint.Store.asyncRequest(
						searchUrl,
						post,
						function(returnedHtml) {
							//inputField.removeClass('gz_inputloading');
							Aspire.updateSearchResultDiv(jQuery.trim(returnedHtml));
						},
						'post'
					);
				}
			}
			return false;
		});
				
		// Apply toggles
		$(".gz_toggle").click(function() {
			if((mapping=togglesMap[this.id])!=null) {
				if($(this).attr("checked")) {
					$('#'+mapping).hide();
					return;
				}
				$('#'+mapping).show();
			}
		});

		// Apply a specific behaviors for the deliver to my current address
		// option
		$('#gz_shiptocustomer').click(function() {
			Aspire.checkDeliveryConflict();
			Aspire.updateCountryRequires();
		});
		
		$('#gz_country').click(function() {
			Aspire.checkDeliveryConflict();
			Aspire.updateCountryRequires();
		});
		
		$('#gz_shipcountry').click(function() {
			Aspire.checkDeliveryConflict();
			Aspire.updateCountryRequires();
		});
		
		//$('#gz_customerdetailsform').unbind();
		$('#gz_customerdetailsform').submit(function() {
			if(!Aspire.checkDeliveryConflict()) {
				// Submit the form if there were no delivery errors
				this.submit();
			}
			return false;
		});
		
		$("#gz_cartform input.quantity").keypress(function(e) {
			if (typeof tempTimer=='number') window.clearTimeout(tempTimer);
			var tempVar=e.target;
			tempTimer=setTimeout(function() {
				Aspire.keypressUpdateCartForm(tempVar);
			},100);
		});
		
		// All changes to postage and handling options should fire off
		// A cart update for javascript users....
		$('input.cartoption').click(function() {
			SitePoint.Store.updateCart();
		});
		
		Aspire.updateAgreement();
		Aspire.updateToggles();
		Aspire.updateAccountRadio();
		Aspire.updateCountryRequires();
		
		$('#gz_updatecartbutton').hide();
		console.timeEnd("Aspire.applyBehaviours");
	},
	keypressUpdateCartForm:function(e) {
		if (Aspire.isNumeric($(e).val())) {
			// Is there a timer already started?
			if(typeof(Aspire.keypressUpdateTimer)=='number') {
				// Clear it...
				clearTimeout(Aspire.keypressUpdateTimer);
			}
			// Start a new timer
			Aspire.keypressUpdateTimer=setTimeout(function(){
				SitePoint.Store.updateCart();
				Aspire.keypressUpdateTimer=null;
			}, keypressUpdateDelay);
		}
	},
	loggedIn:function(returnedHtml) {
		// remove throbber
		SitePoint.Store.removeThrobber(loginForm);
		if (returnedHtml==="1") {
			Aspire.updateCustomerDetailsDiv();
		} else {
			// Replace the existing loginform with the returnedHtml
			// there must have been an error
			$(loginFormContainer).html(returnedHtml);
			Aspire.applyBehaviours();
		}
	},
	updateCustomerDetailsDiv:function() {
		SitePoint.Store.addThrobber(customerDetailsForm, "Loading Details...");
		$(customerFormContainer).load(
			customerDetailsUrl+'?customerdetailsform=1',
			null,
			function() {
				$(customerFormContainer).show();
				Aspire.customerDetailsUpdated()
			}
		);
	},
	updateSearchResultDiv:function(returnedHtml) {
		SitePoint.Store.removeThrobber(searchResultContainerDiv);
		$(searchResultContainerDiv).html(returnedHtml);
		Aspire.applyBehaviours();
	},
	customerDetailsUpdated:function() {
		$(loginForm).remove();
		Aspire.applyBehaviours();
	},
	updateToggles:function() {
		$('.gz_toggle').each(function() {
			if((mapping=togglesMap[this.id])!=null) {
				if($(this).attr("checked")) {
					$('#'+mapping).hide();
				} else {
					$('#'+mapping).show();
				}
			}
		});
	},
	updateAccountRadio:function() {
		$('#gz_useraccountyes').each(function(){
			if ($('#gz_useraccountyes').attr("checked")) {
				$('#gz_accountfields').hide();
				$('#gz_customerformcontainer').hide();
				$('#gz_loginfields').show();
			} else {
				$('#gz_accountfields').show();
				$('#gz_customerformcontainer').show();				
				$('#gz_loginfields').hide();
			}
		});
	},
	updateAgreement:function() {
		$('#gz_agreement').each(function(){
			if($('#gz_agreement').attr("checked")) {
				//$('#gz_proceed').removeAttr("disabled");
				$('#gz_proceed').unbind('click');
			} else {
				//$('#gz_proceedpayment').attr("disabled","disabled");
				$('#gz_proceed').click(function() {
					alert("You must agree to the Terms and Conditions before proceeding.");
					return false;
				});
			}
		});
	},
	openCalc:function() {
		alert("Note: The foreign currency exchange rates should be used as a guide only.");	
		newWin = window.open(calcUrl,"Aspire","toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,resizable=0,width=510,height=350");
		if (window.focus) {newWin.focus()};
		return false;
	},
	getMinicartAnimClass:function() {
		return minicartAnimationClass;
	},
	isNumeric:function (value) {
		if (value == null || !value.toString().match(/^\d+$/)) return false;
  		return true;
	}

	};// End returned object
})();

// Run on page load
$(function() {
	Aspire.init();

	$("form#gz_paymentform input#gz_proceed").click(function(e){
		$(this).attr('disabled', 'disabled');
		$(this).val("Processing, please wait...");
		$("form#gz_paymentform").submit();
		return false;
	});
	
	// load minicart into page.
	$('#gz_minicartcontainer').html("<img src='/images/loading.gif' />");
	$.ajax({
		url: '/minicart',
		async:false,
		success: function(data) {
		  $('#gz_minicartcontainer').html(data);
		
		},
		failed: function(data){
			alert("Failed to load minicart.");
		}
	});
	
	// load minicart into page.
        $.ajax({
                url: '/userstatus',
                async:false,
                success: function(data) {
                  $('#loginButton').html(data);

                },
                failed: function(data){
                        alert("Failed to load userstatus.");
                }
        });
	
	$("input.tailoredpackqty").bind('keyup', function() {
		
		// gets new qty entered by user.
		userqty = $("input.tailoredpackqty").val();
		
		// gets product id
		productId = $(this).attr('id').split('_');
		productId = productId[1];
		
		// get aspire required qty.
		inputClass = $("a.pack_"+productId).parent();
		nodes = inputClass.attr('class').split('_');
		requiredQty = nodes[2];
		
		// rebuild the link like "/electives?id={X}&qty={X}&userQty={X}
		var rebuiltLink = "/electives?id="+productId+"&qty="+requiredQty+"&userQty="+userqty;
		$("a.pack_"+productId).attr('rel', rebuiltLink);
	});
});

/*
 * Facebox (for jQuery)
 * version: 1.2 (05/05/2008)
 * @requires jQuery v1.2 or later
 *
 * Examples at http://famspam.com/facebox/
 *
 * Licensed under the MIT:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ]
 *
 * Usage:
 *
 *  jQuery(document).ready(function() {
 *    jQuery('a[rel*=facebox]').facebox()
 *  })
 *
 *  <a href="#terms" rel="facebox">Terms</a>
 *    Loads the #terms div in the box
 *
 *  <a href="terms.html" rel="facebox">Terms</a>
 *    Loads the terms.html page in the box
 *
 *  <a href="terms.png" rel="facebox">Terms</a>
 *    Loads the terms.png image in the box
 *
 *
 *  You can also use it programmatically:
 *
 *    jQuery.facebox('some html')
 *    jQuery.facebox('some html', 'my-groovy-style')
 *
 *  The above will open a facebox with "some html" as the content.
 *
 *    jQuery.facebox(function($) {
 *      $.get('blah.html', function(data) { $.facebox(data) })
 *    })
 *
 *  The above will show a loading screen before the passed function is called,
 *  allowing for a better ajaxy experience.
 *
 *  The facebox function can also display an ajax page, an image, or the contents of a div:
 *
 *    jQuery.facebox({ ajax: 'remote.html' })
 *    jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')
 *    jQuery.facebox({ image: 'stairs.jpg' })
 *    jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')
 *    jQuery.facebox({ div: '#box' })
 *    jQuery.facebox({ div: '#box' }, 'my-groovy-style')
 *
 *  Want to close the facebox?  Trigger the 'close.facebox' document event:
 *
 *    jQuery(document).trigger('close.facebox')
 *
 *  Facebox also has a bunch of other hooks:
 *
 *    loading.facebox
 *    beforeReveal.facebox
 *    reveal.facebox (aliased as 'afterReveal.facebox')
 *    init.facebox
 *
 *  Simply bind a function to any of these hooks:
 *
 *   $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })
 *
 */
(function($) {
  $.facebox = function(data, klass) {
    $.facebox.loading()

    if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)
    else if (data.image) fillFaceboxFromImage(data.image, klass)
    else if (data.div) fillFaceboxFromHref(data.div, klass)
    else if ($.isFunction(data)) data.call($)
    else $.facebox.reveal(data, klass)
  }

  /*
   * Public, $.facebox methods
   */

  $.extend($.facebox, {
    settings: {
      opacity      : 0.2,
      overlay      : true,
      loadingImage : '/images/loading.gif',
      closeImage   : '/images/closelabel.png',
      imageTypes   : [ 'png', 'jpg', 'jpeg', 'gif' ],
      faceboxHtml  : '\
    <div id="facebox" style="display:none;"> \
      <div class="popup"> \
        <div class="content body"> \
        </div> \
        <a href="javascript:;" class="close"><img src="/images/closelabel.png" title="close" class="close_image" /></a> \
      </div> \
    </div>'
    },

    loading: function() {
      init()
      if ($('#facebox .loading').length == 1) return true
      showOverlay()

      $('#facebox .content').empty()
      $('#facebox .body').children().hide().end().
        append('<div class="loading"><img src="'+$.facebox.settings.loadingImage+'"/></div>')

      $('#facebox').css({
        top:	getPageScroll()[1] + (getPageHeight() / 10),
        left:	$(window).width() / 2 - 205
      }).show()

      $(document).bind('keydown.facebox', function(e) {
        if (e.keyCode == 27) $.facebox.close()
        return true
      })
      $(document).trigger('loading.facebox')
    },

    reveal: function(data, klass) {
      $(document).trigger('beforeReveal.facebox')
      if (klass) $('#facebox .content').addClass(klass)
      $('#facebox .content').append(data)
      $('#facebox .loading').remove()
      $('#facebox .body').children().fadeIn('normal')
      $('#facebox').css('left', $(window).width() / 2 - ($('#facebox .popup').width() / 2))
      $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')
    },

    close: function() {
      $(document).trigger('close.facebox')
      return false
    }
  })

  /*
   * Public, $.fn methods
   */

  $.fn.facebox = function(settings) {
    if ($(this).length == 0) return

    init(settings)

    function clickHandler() {
      $.facebox.loading(true)

      // support for rel="facebox.inline_popup" syntax, to add a class
      // also supports deprecated "facebox[.inline_popup]" syntax
      var klass = this.rel.match(/facebox\[?\.(\w+)\]?/)
      if (klass) klass = klass[1]

      fillFaceboxFromHref(this.href, klass)
      return false
    }

    return this.bind('click.facebox', clickHandler)
  }

  /*
   * Private methods
   */

  // called one time to setup facebox on this page
  function init(settings) {
    if ($.facebox.settings.inited) return true
    else $.facebox.settings.inited = true

    $(document).trigger('init.facebox')
    makeCompatible()

    var imageTypes = $.facebox.settings.imageTypes.join('|')
    $.facebox.settings.imageTypesRegexp = new RegExp('\.(' + imageTypes + ')$', 'i')

    if (settings) $.extend($.facebox.settings, settings)
    $('body').append($.facebox.settings.faceboxHtml)

    var preload = [ new Image(), new Image() ]
    preload[0].src = $.facebox.settings.closeImage
    preload[1].src = $.facebox.settings.loadingImage

    $('#facebox').find('.b:first, .bl').each(function() {
      preload.push(new Image())
      preload.slice(-1).src = $(this).css('background-image').replace(/url\((.+)\)/, '$1')
    })

    $('#facebox .close').click($.facebox.close)
    $('#facebox .close_image').attr('src', $.facebox.settings.closeImage)
  }

  // getPageScroll() by quirksmode.com
  function getPageScroll() {
    var xScroll, yScroll;
    if (self.pageYOffset) {
      yScroll = self.pageYOffset;
      xScroll = self.pageXOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {	 // Explorer 6 Strict
      yScroll = document.documentElement.scrollTop;
      xScroll = document.documentElement.scrollLeft;
    } else if (document.body) {// all other Explorers
      yScroll = document.body.scrollTop;
      xScroll = document.body.scrollLeft;
    }
    return new Array(xScroll,yScroll)
  }

  // Adapted from getPageSize() by quirksmode.com
  function getPageHeight() {
    var windowHeight
    if (self.innerHeight) {	// all except Explorer
      windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
      windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
      windowHeight = document.body.clientHeight;
    }
    return windowHeight
  }

  // Backwards compatibility
  function makeCompatible() {
    var $s = $.facebox.settings

    $s.loadingImage = $s.loading_image || $s.loadingImage
    $s.closeImage = $s.close_image || $s.closeImage
    $s.imageTypes = $s.image_types || $s.imageTypes
    $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml
  }

  // Figures out what you want to display and displays it
  // formats are:
  //     div: #id
  //   image: blah.extension
  //    ajax: anything else
  function fillFaceboxFromHref(href, klass) {
    // div
    if (href.match(/#/)) {
      var url    = window.location.href.split('#')[0]
      var target = href.replace(url,'')
      if (target == '#') return
      $.facebox.reveal($(target).html(), klass)

    // image
    } else if (href.match($.facebox.settings.imageTypesRegexp)) {
      fillFaceboxFromImage(href, klass)
    // ajax
    } else {
      fillFaceboxFromAjax(href, klass)
    }
  }

  function fillFaceboxFromImage(href, klass) {
    var image = new Image()
    image.onload = function() {
      $.facebox.reveal('<div class="image"><img src="' + image.src + '" /></div>', klass)
    }
    image.src = href
  }

  function fillFaceboxFromAjax(href, klass) {
    $.get(href, function(data) { $.facebox.reveal(data, klass) })
  }

  function skipOverlay() {
    return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null
  }

  function showOverlay() {
    if (skipOverlay()) return

    if ($('#facebox_overlay').length == 0)
      $("body").append('<div id="facebox_overlay" class="facebox_hide"></div>')

    $('#facebox_overlay').hide().addClass("facebox_overlayBG")
      .css('opacity', $.facebox.settings.opacity)
      .click(function() { $(document).trigger('close.facebox') })
      .fadeIn(200)
    return false
  }

  function hideOverlay() {
    if (skipOverlay()) return false

    $('#facebox_overlay').fadeOut(200, function(){
      $("#facebox_overlay").removeClass("facebox_overlayBG")
      $("#facebox_overlay").addClass("facebox_hide")
      $("#facebox_overlay").remove()
    })

    return true
  }

  /*
   * Bindings
   */

  $(document).bind('close.facebox', function() {
    $(document).unbind('keydown.facebox')
    $('#facebox').fadeOut(function() {
      $('#facebox .content').removeClass().addClass('content')
      hideOverlay()
      $('#facebox .loading').remove()
	$(document).trigger('afterClose.facebox');
    })
  })

})(jQuery);
/**
 *	Aspire Product Lookup
 *
 * Requires Aspire.js to be included first
 *
 * Looks for a div with "productLookup" class,
 *
 * Should have style "display: none" to accomodate non-JS users
 *
 * Contents of div should be a <form> with an <input id="searchProducts">
 *
 * The form can be created by including "/aspire/_autocomplete"
 *
 * Call the following code to init:
 *
 * $(function(){
 * 	SitePoint.ProductLookup.init();
 * });
 */

if (typeof Aspire === "undefined") {
	Aspire = {}
}

/**
 * class Aspire.ProductLookup
 */
Aspire.ProductLookup = {
	init:function(autoCompleteUrl) {
		console.time('Aspire.ProductLookup.init');
		$('.productLookup').fadeIn('fast'); // Turn "on" the Product Lookup Section

		// Uses AutoSuggest Plugin found at: http://code.drewwilson.com/entry/autosuggest-jquery-plugin
		$(".productLookup input#searchProducts").autoSuggest(autoCompleteUrl, {
			minChars: 1,
			matchCase: false,
			neverSubmit: true, // The form should never be submitted
			retrieveLimit: 10,
			selectedItemProp: "name",
			searchObjProps: "name",
			startText: "Enter Product Code",
			resultClick: function(elem) {
				try {
					id = elem.attributes.value;
					if (id) {
						// this is a tailored pack, show tailored pack selection form.
						if(elem.attributes.tailoredpack)
						{
							tailoredPackQty = elem.attributes.tpQty;
							formAction = elem.attributes.url;
							$.facebox({ ajax: "/electives?id="+id+"&qty="+tailoredPackQty+"&userQty=1&action="+formAction })
						}
						else
						{
							// add product to cart.
							Aspire.ProductLookup.addProductToCart(id);
						}					}
				}
				catch(e) {
					console.error("Unable to update cart: " + e);
				}
			},
			selectionAdded: function(elem) {
				elem.hide('slow');
			}
		});
		console.timeEnd('Aspire.ProductLookup.init');
	},
	addProductToCart: function(productId) {
		console.time("Aspire.ProductLookup.addProductToCart(" + productId + ")");
		SitePoint.Store.addThrobber('#gz_editcart', "Updating...");
		$.ajax({
			type: 'POST',
			url: '/store/cart',
			data: { productid: id, quantity: 1, submit: 'Add to your cart' },
			success: function(e) { },
			error: function() { console.error("Unable to post results"); },
			complete: function() {
				SitePoint.Store.updateCartDiv();
				console.timeEnd("Aspire.ProductLookup.addProductToCart(" + productId + ")");
			}
//				dataType: dataType
		});
	}
};

