<!--;
/**
*
* Westdean onling booking JavaScript
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Lots of work still outstanding. Do a search for "TODO"
* for more info. See also ../README.txt
* gianfranco@keymedia.co.uk
*
* TODO: skip first night dinner date node
* and add in dinner discount product
*/

/**
*
* Global constants
*
*/
var _FORCEDEBUG = 0;
var _UGLYSESSION = '1215022269:81.106.127.81';
if(_UGLYSESSION == getCookie('sessionid')){
	_FORCEDEBUG = 10;
};

var _NOBOOKING = false;
if(document.cookie.indexOf('pleaseallowbooking') != -1){
	_NOBOOKING = false;
};

var _HTTPMODE = 'http';
if(document.location.toString().indexOf('https://') != -1){
	_HTTPMODE = 'https';
};
var _HOST = _HTTPMODE + '://' + document.location.host;
var _HTTPS_HOST = 'https://' + document.location.host;
if(document.location.host.indexOf('wesmirror') != -1){ _HTTPS_HOST = _HOST; };
var req = new Array();	// An array of request objects
var moz = false;		// A flag to say if we should try to get UniversalBrowserRead
var allowedActions = 'readsession|writesession|login|waitinglist|pay|readcosts|recover|logout|getplaces|doaddtobasket|updatedelegate'.split('|');
var oneDayCourseCodes = '1D|DJ|1M|1L|TD|DS|GL|KL1|BM1'.split('|');
var _CANCOOKIE = -1;
var _SESSIONXML;
var _SESSIONXML_LOADED = false;
var _TERMURL = _HTTPS_HOST + '/cgi-bin/postdatatohtml.cgi';
// These 3 are now defined in a separate file.s
// var _COSTSHEADERS = new Array();
// var _COSTSXML_LOADED = false;
// var _COSTSARRAY = new Array();
var _POST_SAVE = '';		/* This will instruct browser to do something after a writesession */
var _DELEGATECOSTCACHE	= new Array();
var _ITEMISEDCOSTS		= new Array();

/**
*
* Misc messages: these can be overriden by a local redefinition
*
*/

var _CROSS_DOMAIN_AJAX		= 'Error: cross-domain AJAX calls will not work.';
var _COOKIE_ERROR			= 'Error: please enable cookies';
var _ERROR_12029			= 'Error: your computer is temporarily unable to connect to the internet. Please try again.';
var _EMPTY_wishlist			= 'Your wishlist is currently empty.<br /><br />While you are looking around the short courses, feel free to add any courses that you are interested in to your wishlist.  You can then review your favourites here before choosing which ones to book.';
var _EMPTY_basket			= 'Please choose a course to book before visiting this page.';
var _COURSE_FULL_TEXT		= 'This course is currently full.  Your email address has been added to the waiting list for this course and we will let you know if a place becomes available.';
var _ALL_DETAILS_REQUIRED	= 'Note that you cannot proceed to checkout until you have specified all the people attending the course and their accommodation requirements.';
var _READY_FOR_CHECKOUT		= 'Students and accomodation now entered, ready to check out.  You will be able to finally confirm students as part of the checkout process.';
var _RECOVERY_WAIT			= 'Please wait while your details are retrieved. This can take up to a minute.';
var _WISHLIST_INFO			= 'Your wishlist is an area where you can collect courses that may be of interest.<br /><br />You can book courses from here, and any courses you have booked during this session will be indicated.';
var _INCOMPLETE_DELEGEATES	= 'Sorry, we do not have all the required details for one of the students. We cannot complete your booking. Please edit each student and add the necessary information. Thank you.';
var _LONG_WAIT_MESSAGE		= 'Please wait for this page to reload. This may take up to 90 seconds.<br />While you are waiting we will check availability, reserve your place, save your accommodation preferences,<br />take payment for the course and return a booking reference.';
var _PLEASE_EDIT			= 'Click edit to add the following details:<ul><li>Room accommodation options</li><li>Additional nights</li><li>Additional meals</li><li>Special and dietary requirements</li></ul>Then click Finished to continue your booking'
var _subheading_step1_html	= '<a name="basket.htm" class="leader">&#160;&#160;1: Students</a> <a name="summary.htm">2: Summary</a> <a name="checkout.htm">3: Your details</a> <a name="card.htm">4: Payment</a> <a name="confirmation.htm">5: Confirmation</a>';
var _subheading_step1b_html	= '<a href="basket.htm" class="leader">&#160;&#160;1: Students</a> <a name="summary.htm">2: Summary</a> <a name="checkout.htm">3: Your details</a> <a name="card.htm">4: Payment</a> <a name="confirmation.htm">5: Confirmation</a>';
var _subheading_step2_html	= '<a href="basket.htm" class="leader">&#160;&#160;1: Students</a> <a name="summary.htm">2: Summary</a> <a name="checkout.htm">3: Your details</a> <a name="card.htm">4: Payment</a> <a name="confirmation.htm">5: Confirmation</a>';
var _subheading_step3_html	= '<a href="basket.htm" class="leader">&#160;&#160;1: Students</a> <a href="summary.htm">2: Summary</a> <a name="checkout.htm">3: Your details</a> <a name="card.htm">4: Payment</a> <a name="confirmation.htm">5: Confirmation</a>';
var _subheading_step4_html	= '<a href="basket.htm" class="leader">&#160;&#160;1: Students</a> <a href="summary.htm">2: Summary</a> <a href="checkout.htm">3: Your details</a> <a name="card.htm">4: Payment</a> <a name="confirmation.htm">5: Confirmation</a>';
var _subheading_step5_html	= '<a name="basket.htm" class="leader">&#160;&#160;1: Students</a> <a name="summary.htm">2: Summary</a> <a name="checkout.htm">3: Your details</a> <a name="card.htm">4: Payment</a> <a name="confirmation.htm">5: Confirmation</a>';
var _autoFormHTML = '<script language="Javascript" ' 
			+ 'type="text/javascript">function OnLoadEvent() { document.form.submit(); '
			+ '};</' 
			+ 'script>' + '<html><head><title>3D Secure Verification</title></head><body onload="OnLoadEvent();"><form name="form" action="_ACSURL" method="POST"><input type="hidden" name="PaReq" value="_PAREQ" /><input type="hidden" name="TermUrl" value="_TERMURL" /><input type="hidden" name="MD" value="_MD" /><noscript><input type="submit" value="Procede to your bank for 3D Authentication" /></noscript></form>';
var _NEWSTUDENT_FIRSTNAME	= 'New';
var _NEWSTUDENT_SURNAME		= 'Student';
var _VATTEXT				= 'This booking includes VAT of £_VATAMOUNT_ in respect of accommodation and meals outside of the course duration and also in respect of any costs relating to non-students.  A VAT invoice can be obtained by contacting the Admissions team on 0844 4994408.';
var _BOOK_ONLINE			= 'book online';
if(_NOBOOKING){
	_BOOK_ONLINE			= 'online booking will be unavailable until further notice for essential maintenance, please download a booking form and return via post';
};

/**
*
* Work out what "project" we're on
*
*/
var _PROJECT = "site";
if(document.location.href.match("/devsite/")){
	_PROJECT = "devsite";
};

/**
*
* AJAX request and response handlers
*
*/
function doRequest(someXML,somePath,reqIndex){
	if (! someXML){
		_myDebug("Error: null XML request");
		return '';
	};
	if(document.location && document.location.host && _HTTPMODE + '://' + document.location.host != _HOST){
		// alert('http://' + document.location.host + '  !=  ' + _HOST);
		_tellUser(_CROSS_DOMAIN_AJAX); return '';
		_myDebug(_CROSS_DOMAIN_AJAX); return '';
	};

	if(_CANCOOKIE != 1){
		if(! _testCookies()) {
			return false;
		};
	};

	/* check that the request has an action attibute */
	var requestaction = allowedActions[reqIndex];
	if (! requestaction || reqIndex == -1) {
		return _tellUser('Error: request needs an allowed action attribute (you said <b>'+ requestaction +'</b>)');
	};

	/* now set the handler on the basis of the request id */
	handlerName = eval('handle_'+ requestaction);
	_myDebug('handler: '+ 'handle_' + requestaction);

	_myDebug('function doRequest('+ requestaction +')\n--\n'+someXML);
	var _URL = _HOST + '/' + somePath;
	if (window.XMLHttpRequest) {
		moz = true;
		try {
			netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
		} catch (e) {
			/* Harmless if it's Safari */
			// alert("Permission UniversalBrowserRead denied.");
		};
		req[reqIndex] = new XMLHttpRequest();
		req[reqIndex].onreadystatechange = handlerName; // processReqChange;
		req[reqIndex].open("POST",_URL, true);
		req[reqIndex].setRequestHeader('Content-Type', 'text/xml');
		req[reqIndex].send(someXML);

	// Or, for IE/Windows ActiveX:
	} else if (window.ActiveXObject) {
		req[reqIndex] = new ActiveXObject("Microsoft.XMLHTTP");
		if (req[reqIndex]) {
			req[reqIndex].onreadystatechange = handlerName; // processReqChange;
			req[reqIndex].open("POST",_URL, true);
			req[reqIndex].setRequestHeader('Content-Type', 'text/xml');
			req[reqIndex].send(someXML);
		};
	};
	_myDebug("Done sending...");
	return true;
};

/**
*
* START of process_ACTION response handlers.
* You *MUST* have one of these for each action.
*
*/
function handlerTemplate(someInt) {
	myreq = req[someInt];
	if(moz){try { netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");} catch (e) {};};
	// _myDebug('myreq.readyState: ' + myreq.readyState);
    if (myreq.readyState == 4) {
        if (typeof(myreq.status) != "undefined" && myreq.status == 200) {
			_myDebug('responseText:\n'+myreq.responseText);
			setTimeout (_hideWait, 2);
			response = myreq.responseXML.documentElement;
			if(myreq.responseXML.getElementsByTagName('page')[0]){
				_dropins('','waittime','waittime: ' + myreq.responseXML.getElementsByTagName('page')[0].getAttribute('waittime'));
			};
			if(_nodeData(response,'message')){
				_tellUser(_nodeData(response,'message'));
				if(_nodeData(response,'message').toUpperCase().match('ERROR')
				&& ! _nodeData(response,'message').match('3DAuth is required')){
					return false;
				};
			};
			if(myreq.responseXML.getElementsByTagName('page')[0]){
				_myDebug('now do: process_' + allowedActions[someInt]);
				eval('process_' + allowedActions[someInt] + '("'+ someInt +'")');
			} else {
				_hideWait();
				_tellUser('Error: there was a problem with the server response. Please try again later');
				_myDebug('no page in responseText:\n'+myreq.responseText);
				// alert(myreq.responseText);
			};
		} else {
			_hideWait();
			if(myreq.status && myreq.status == 12029){
				_tellUser(_ERROR_12029);
	        };
			if(myreq.status && myreq.status != 12029){ /* for otherwise you're just being impatient, probably */
				_tellUser("Error: there was a problem with the submission:\nreq[0].status: " + myreq.status + ' - ' + myreq.statusText);
	        };
        };
    };
};

for(j=0;j<allowedActions.length;j++){
	// alert(allowedActions[j] + ':' + j);
	eval('function handle_' + allowedActions[j] + '() { handlerTemplate('+j+'); };');
};


/**
*
* What do we do with the server response?
*
* Much will depend on what page we're looking at.
* So, this function is going to look very long,
* but it is essentially one clause per page.
*/
function process_readsession(someInt,doNotReparse){
	if(doNotReparse){
		_myDebug('process_readsession NOT re-parsing');
	} else {
		_myDebug('process_readsession re-parsing');
		_SESSIONXML = req[someInt].responseXML;
	};
	_SESSIONXML_LOADED = true;
	someResponse  = _SESSIONXML.documentElement;
	_myDebug('SessionId:' + someResponse.getAttribute('sessionid'));
	_dropins('div','session_id','SESSION: ' + someResponse.getAttribute('sessionid'));
	_myDebug('Session loaded successfully.');
	_hideOrShow('','','message','none');

	/* What action have we just performed ? */
	var performedAction = allowedActions[someInt];
	_myDebug('performedAction:' + performedAction);


	// TODO: remove the 4 == 5 .... temporary, to prevent display of payment summary
	if(someResponse.getElementsByTagName('payment') &&
		someResponse.getElementsByTagName('payment')[0] &&
		document.getElementById('payer') && 4 == 5) {
		_myDebug('Payment node and payer div exist, so do process_pay');
		return process_pay(someInt);
	};

	/* show/hide the logout link */
	var _sensitive_data_exists = false;
	for (var q=0; q<someResponse.getElementsByTagName('delegate').length;q++){
		var tmpD = someResponse.getElementsByTagName('delegate')[q];
		if(_nodeData(tmpD,'email') && _nodeData(tmpD,'password')){
			_sensitive_data_exists = true;
		};
	};
	if(_sensitive_data_exists){
		_myDebug('sensistive data exists');
		_dropins('a','togglelog','Log Out');
	} else {
		_myDebug('NO sensistive data exists');
		_dropins('a','togglelog','Log In');
	};

	/* listType will be basket|wishlist|summary */
	var listType = '';
	if(document.getElementById('courselist')){
		listType = document.getElementById('courselist').getAttribute('class') || document.getElementById('courselist').className;
	};
	_myDebug('listType:' + listType);

	var listHTML = '';

	/*
	* In case of basket|wishlist we'll have
	*
	* <p>
	* <span class="date">February 25 - February 27 2007</span>
	* <span class="cost">£166.00 to £297.00</span>
	* <span class="buttons">
	* <span class="addbasket"><a		href="#top" onclick="addToBasket('basket','COURSEID'); return false;">book online</a></span>
	* <span class="addwishlist"><a		href="#top" onclick="addToBasket('wishlist','COURSEID'); return false;">add to wishlist</a></span>
	* <span class="removeFromBasket"><a	href="#top" onclick="removeFromBasket('wishlist','COURSEID'); return false;">remove</a></span>
	* <span class="editcourse"><a		href="#top" onclick="editCourse('COURSEID'); return false;">edit</a></span>
	* </span>
	* <b class="name">Planning and planting - a two-day workshop</b>
	* <i class="tutor">Jasmine Hart</i>
	* <span class="reference">Reference: course code</span>
	* <span class="ability">Ability: a/b</span>
	* <span class="dbid">dbid</span>
	* </p>
	*
	* for each course.
	*
	* In case of summary we'll have
	*
	* <p>
	* <b class="name">Planning and planting - a two-day workshop</b>
	* <span class="date">February 25 - February 27 2007</span>
	* <span class="reference">Reference: course code</span>
	* <span class="numberofstudents">
	*	X Student places
	*	<span class="cost">&pound; 780.00</span>
	* </span>
	* <span class="rooms">
	*	Joe Bloggs: room type
	*	<span class="cost">&pound; 120.00</span>
	* </span>
	* <span class="rooms">
	*	Fred Bloggs: room type
	*	<span class="cost">&pound; 160.00</span>
	* </span>
	* <span class="rooms">
	*	Total for course
	*	<span class="cost">&pound; 380.00</span>
	* </span>
	* </p>
	*
	* <!-- for each course, followed by -->
	*
	* <p>
	* <span class="rooms">
	*	(Grand) Total
	*	<span class="cost">&pound; 3000.00</span>
	* </span>
	* </p>
	*
	* 06/07/2007: - actually, I'll change the "add to whatever" buttons slightly
	* so that they reflect the presence of the course in wishlist/basket. gianfranco
	*/

	var grandTotal = 0;
	if(listType){
		for(i=0; i<someResponse.getElementsByTagName('course').length ;i++){
			tmpCourse = someResponse.getElementsByTagName('course')[i];
			var courseCost = _costCourse(tmpCourse);
			if (tmpCourse.getAttribute('basket') == 'basket'){
				grandTotal += parseFloat(courseCost);
			};
			var courseCostEstimate = '';
			if(courseCost){
				courseCostEstimate = '&pound;' + courseCost;
			} else {
				var courseCode = tmpCourse.getAttribute('id')
				courseCode = courseCode.substr(0,courseCode.indexOf('_')).toUpperCase();
				courseCostEstimate = 'from &pound;' + tmpCourse.getAttribute('cost');
				// courseCostEstimate = 'from &pound;' + _codeToCost(courseCode,'nonres',tmpCourse.getAttribute('start'));
			};
			_myDebug('going to study basket attribute');
			if(tmpCourse.getAttribute('basket') == listType ||
				(listType == 'wishlist' && tmpCourse.getAttribute('basket') == 'basket_paid')){
				_myDebug('basket_paid and wishlist or basket=listType. listType:' + listType);
				var paraId = _sanitise(tmpCourse.getAttribute('id'));
				var completeClass = 'complete';
				var basketCourseListComplete = true;
				var completeProblem = '';
				if (listType == 'basket' && ! tmpCourse.getElementsByTagName('delegate').length){
					completeClass = 'incomplete';
					completeProblem = 'No students specified';
					_myDebug('incomplete:' + completeProblem);
				};
				for (var v=0; v < tmpCourse.getElementsByTagName('delegate').length;v++){
					if(! completeProblem && listType == 'basket'){
						var localValidityProblems = _validateDelegate(tmpCourse.getElementsByTagName('delegate')[v]);
						if(localValidityProblems[0]) {
							completeClass = 'incomplete';
							completeProblem = 'Details for one or more students on this course are missing';
							_myDebug('incomplete:' + completeProblem);
						};
					};
				};
				if(tmpCourse.getAttribute('basket') == listType + '_paid'){
					_myDebug('basket_paid');
					completeClass = 'paid';
				};
				if(listType != 'basket'){ completeClass = ''; };

				// 06/07/2007: no link if this is already in the basket
				var alreadyBasketed = '';
				for (var t=0;t<someResponse.getElementsByTagName('course').length;t++){
					if(someResponse.getElementsByTagName('course')[t].getAttribute('id') == tmpCourse.getAttribute('id')
						&& someResponse.getElementsByTagName('course')[t].getAttribute('basket') != tmpCourse.getAttribute('basket')){
						alreadyBasketed = someResponse.getElementsByTagName('course')[t].getAttribute('basket');
					};
				};

				listHTML +=  "<p class=\""+ completeClass +"\" id=\""+ paraId +"\">\n";
				if(completeProblem){
					listHTML += '<a class="status" href="javascript:null;" onclick="return false;">&nbsp;<span>';
					listHTML += '<b>'+ completeProblem + '</b>';
					listHTML += '</span></a>';
					basketCourseListComplete = false;
				};
				listHTML +=  '<span class="date">' + _unixtimetodate(tmpCourse.getAttribute('start'),0) + ' - ' + _unixtimetodate(tmpCourse.getAttribute('end'),1) + "</span>\n";
				listHTML +=  '<span class="cost">' + _2dp(courseCostEstimate) +'</span>' + "\n";
				listHTML +=  '<span class="buttons">' + "\n";
				linkstyle = '';
				if(
					tmpCourse.getAttribute('basket') == 'basket' ||
					tmpCourse.getAttribute('basket') == 'basket_paid'
				) {
					_myDebug('basket_paid');
					linkstyle = ' style="display: none;" ';
				};

				// 06/07/2007: no link if this is already in the basket
				/*
				var alreadyBasketed = '';
				for (var t=0;t<someResponse.getElementsByTagName('course').length;t++){
					if(someResponse.getElementsByTagName('course')[t].getAttribute('id') == tmpCourse.getAttribute('id')
						&& someResponse.getElementsByTagName('course')[t].getAttribute('basket') != tmpCourse.getAttribute('basket')){
						alreadyBasketed = someResponse.getElementsByTagName('course')[t].getAttribute('basket');
					};
				};
				*/

				if(alreadyBasketed == 'basket'){
					listHTML +=  '<span class="addbasket"'+ linkstyle +'><a href="#top" onclick="addToBasket(\'basket\',\''+ tmpCourse.getAttribute('id') +'\'); return false;">booking in progress, click to continue</a></span>'+ "\n";
				} else {
					listHTML +=  '<span class="addbasket"'+ linkstyle +'><a href="#top" onclick="addToBasket(\'basket\',\''+ tmpCourse.getAttribute('id') +'\'); return false;">'+ _BOOK_ONLINE + '</a></span>'+ "\n";
				};
				linkstyle = '';
				if(
					tmpCourse.getAttribute('basket') == 'wishlist' ||
					tmpCourse.getAttribute('basket') == 'basket_paid'
				) {
					_myDebug('basket_paid');
					linkstyle = ' style="display: none;" ';
				};
				// 06/07/2007: no link if this is already in the wishlist
				if(alreadyBasketed){
					listHTML +=  '<span class="addwishlist"'+ linkstyle +'><a name="wishlistlink">In your wishlist</a></span>'+ "\n";
				} else {
					listHTML +=  '<span class="addwishlist"'+ linkstyle +'><a href="#top" onclick="addToBasket(\'wishlist\',\''+ tmpCourse.getAttribute('id') +'\'); return false;">add to wishlist</a></span>'+ "\n";
				};
				if(tmpCourse.getAttribute('basket') == 'basket_paid'){
					_myDebug('basket_paid');
					// listHTML +=  '<span>You have already paid for this item</span>'+ "\n";
					listHTML +=  '<span class="addbasket"><a href="#top" onclick="addToBasket(\'basket\',\''+ tmpCourse.getAttribute('id') +'\'); return false;">course already booked, click to book again</a></span>'+ "\n";
				};
				listHTML +=  '<span class="removeFromBasket"><a href="#top" onclick="removeFromBasket(\''+ tmpCourse.getAttribute('basket') + '\',\''+ tmpCourse.getAttribute('id') +'\'); return false;">remove</a></span>'+ "\n";
				listHTML +=  '</span>' + "\n";
				listHTML +=  '<b class="name">' + tmpCourse.getAttribute('name') + "</b>\n";
				listHTML +=  '<i class="tutor">' + _nodeData(tmpCourse,'tutorstring') + "</i>\n";
				listHTML +=  '<span class="reference">Reference: ' + tmpCourse.getAttribute('id').replace('_',' ').replace('_',' ').replace('.htm','') + "</span>\n";
				listHTML +=  '<span class="ability">Ability: ' + tmpCourse.getAttribute('ability') + "</span>\n";
				listHTML +=  '<span class="dbid">' + tmpCourse.getAttribute('dbid') + "</span>\n";
				if(tmpCourse.getAttribute('basket') == 'basket') {
					listHTML +=  '<span class="editcourse"><a href="#top" onclick="editCourse(\''+ tmpCourse.getAttribute('id') +'\'); return false;">Confirm students and accommodation</a></span>\n';
				};
				listHTML +=  "\n</p><hr />\n";
			} else {
				_myDebug('should hide this course:' + tmpCourse.getAttribute('name'));
			};

			if(listType == 'summary' && tmpCourse.getAttribute('basket') == 'basket'){

				var studentCount = 0;
				for(p=0; p<tmpCourse.getElementsByTagName('delegate').length; p++){
					var tmpDelegate = tmpCourse.getElementsByTagName('delegate')[p];
					studentCount++;
				};

				/* only show summary for courses with at least one delegate */
				if(studentCount){
					/**
					* This array will hold a list of delegate IDS that refer to
					* delegates that are guests of a delegate already mentioned
					*/
					var ignoreDelegatesArray = new Array();

					listHTML +=  "<p>\n";
					listHTML +=  '<b class="name">' + tmpCourse.getAttribute('name') + "</b>\n";
					listHTML +=  '<span class="date">' + _unixtimetodate(tmpCourse.getAttribute('start'),0) + ' - ' + _unixtimetodate(tmpCourse.getAttribute('end'),1) + "</span>\n";
					listHTML +=  '<span class="reference">Reference: ' + tmpCourse.getAttribute('id').replace('_',' ').replace('_',' ').replace('.htm','') + "</span>\n";


					listHTML +=  '<span class="numberofstudents">\n';
					if(studentCount > 1){
						listHTML +=  studentCount + ' Student places\n';
					} else {
						listHTML +=  studentCount + ' Student place\n';
					};
					// listHTML +=  '<span class="cost">&pound; ' + studentCost + '</span>\n';
					listHTML +=  '</span>\n';

					for (var q=0;q<tmpCourse.getElementsByTagName('delegate').length;q++){
						var tmpDelegate = tmpCourse.getElementsByTagName('delegate')[q];
						var tmpDelegateName = _capText(_nodeData(tmpDelegate,'firstname')) + ' ' + _capText(_nodeData(tmpDelegate,'surname'));
						var tmpAcc = tmpDelegate.getElementsByTagName('accommodation')[0];
						var delegateCostsArray = _delegateCost(tmpDelegate);
						listHTML += '<span class="rooms">\n';
						listHTML += tmpDelegateName;
						if(tmpAcc.getAttribute('type') == 'nonres'){
							listHTML += ': ' + _lookupAccommodationType(tmpAcc.getAttribute('type')) + ':\n';
						} else {
							listHTML += ': ' + _lookupAccommodationType(tmpAcc.getAttribute('type')) + ', ' + delegateCostsArray[1] + ' nights:\n';
							if(tmpAcc.getAttribute('type').indexOf('_2') != -1){
								listHTML += ' sharing with ' + (_getGuestName(tmpDelegate)  || 'unnamed guest');
							};
						};
						if(_nodeData(tmpDelegate,'specialrequirements')){
							listHTML += '<i>'+ _nodeData(tmpDelegate,'specialrequirements') +'</i>:' + "\n";
						};
						if(_nodeData(tmpDelegate,'dietaryrequirements')){
							listHTML += '<i>'+ _nodeData(tmpDelegate,'dietaryrequirements') +'</i>:' + "\n";
						};
						var tmpTotCost = parseFloat(delegateCostsArray[0]);
						if(tmpDelegate.getAttribute('protection') == 'true') {
							tmpTotCost += parseFloat(delegateCostsArray[2]);
						};
						/**
						* Add the guest's protection cost, if guest is a genuine guest
						* AND
						* if they have requested it
						*/
						if(tmpAcc.getAttribute('type').indexOf('_2') != -1
							&& tmpDelegate.getAttribute('guest') == 'guest'
							&& tmpDelegate.getAttribute('guestprotection') == 'true'){
							tmpTotCost += parseFloat(delegateCostsArray[3]);
						};
						listHTML +=  '<span class="cost">&pound;' + _2dp(tmpTotCost) + '</span>\n';
						listHTML += '</span>\n';
					};

					listHTML += '<span class="rooms">\n';
					// listHTML += '<b>Total for this course:</b>';
					// listHTML += '<br /><b>Total:</b>';
					// listHTML +=  '<span class="cost">&pound;' + courseCost + '</span>\n';
					listHTML += '</span>\n';
					listHTML +=  "\n</p>\n";
					listHTML += '<hr /><p class="basket_bold_heading">Total cost:';
					listHTML +=  '<span class="cost">&pound;' + _2dp(courseCost) + '</span>\n';
					// '<span style="font-size: 8pt; font-weight: normal;">including VAT</span>\n';
					listHTML += '</p>\n';
				};

				// listHTML += '<p><span class="rooms">\n';
				// listHTML += '<b>Total:</b>';
				// listHTML +=  '<span class="cost">&pound;' + grandTotal + '</span>\n';
				// listHTML += '</span></p>\n';

			};
		};
	};
	if(! listHTML) {
		listHTML = '<p>'  + window['_EMPTY_' + listType]  + '</p>';
	} else {
		if(listType == 'basket') {
			if(basketCourseListComplete) {
				listHTML +=  '<p class="butt_large"><span class="checkout"><a href="checkout.htm" onclick="checkCompleteClass(this,\'courselist\'); return false;" title="Checkout">Checkout</a></span></p>\n';
				listHTML +=  '<p>' + _READY_FOR_CHECKOUT + '</p>\n';
			} else {
				listHTML +=  '<p>' + _ALL_DETAILS_REQUIRED + '</p>\n';
			};
		};
	};
	if(document.getElementById('courselist')) {
		document.getElementById('courselist').innerHTML = listHTML;
	};
	/**
	* If we're on a basket page, show the correct icon
	*
	*/
	if(document.getElementById('bookerform') && document.getElementById('bookerform').style.display != 'none'){
		/*
		*
		* The element document.getElementById('bookerform') now has a class
		* attribute set to either '' or 'update'. In the case of the latter,
		* we want to do a user update, and we want to force a login first.
		*
		*/
		var checkouttype = document.getElementById('bookerform').className || document.getElementById('bookerform').getAttribute('class');
		// _dropins('','subheading','3: Your details');
		if(checkouttype == 'update'){
			if(! _sensitive_data_exists){
				_hideOrShow('','','loginform','block');
			};
		} else {
			_dropins('','subheading',_subheading_step3_html);
			_setClass('subheading','subheading_step3');
			_setClass('subheading2','subheading_basket');
		};
	} else if(document.getElementById('payerform')){
		// _dropins('','subheading','4: Payment');
		_dropins('','subheading',_subheading_step4_html);
		_setClass('subheading','subheading_step4');
		_setClass('subheading2','subheading_basket');
	} else if(document.getElementById('courselist') && document.getElementById('courselist').style.display != 'none'){
		// _dropins('','subheading','2: Summary');
		if(listType == 'basket' || listType == 'summary'){
			_dropins('','subheading',_subheading_step2_html);
			_setClass('subheading','subheading_step2');
			_setClass('subheading2','subheading_basket');
		} else {
			_setClass('subheading','subheading_info');
			_dropins('','subheading',_WISHLIST_INFO);
		};
	};


	/**
	* If we're on the checkout page - ie, if there is a form id="bookerform",
	* then we'd best populate it if we can.
	*/
	if(document.getElementById('bookerform')){
		_hideOrShow('','','booker','block');
		editBooker();
	};

	/**
	* If we're on the card details page - ie, if there is a form id="payerform",
	* perform no prefilling.
	*/
	if(document.getElementById('payerform')){
		_setClass('subheading2','subheading_checkout');
		// _dropins('','subheading','4: Payment');
		_dropins('','subheading',_subheading_step4_html);
		_setClass('subheading','subheading_step4');
		// do nothing in particular
	};

	/* V2: interface - go straight to editCourse if this is MyBasket */
	/* V3: interface - go straight to editDelegate if this is MyBasket and we have no course -> delegates defined */
	if(! listType  && document.getElementById('delegate') && document.getElementById('delegate').style.display != 'block'){
		_myDebug('Checking for course in basket');
		var focusCourse = getFocusNode('course');
		if(focusCourse){
			if(! focusCourse.getElementsByTagName('delegate').length) {
				_myDebug('straight to editDelegate');
				var delegateNode = _newDelegateNode('','');
				if (! focusCourse.getElementsByTagName('delegates').length){
					_myDebug('Adding delegates node');
					var tmpDelegatesNode = _SESSIONXML.createElement('delegates');
					focusCourse.appendChild(tmpDelegatesNode);
				};
				var delegatesNode = focusCourse.getElementsByTagName('delegates')[0];
				delegatesNode.appendChild(delegateNode);
				editDelegate(delegateNode.getAttribute('id'));
			} else {
				_myDebug('straight to editCourse');
				editCourse();
			};
		} else {
			_myDebug(_EMPTY_basket);
			_dropins('','delegates','&nbsp;');
			_tellUser(_EMPTY_basket);
		};
	};
};

/**
* For now, this does exactly the same thing.
* We may adjust this later, based on the action just performed.
* Note: we'll need to add code for each possible value of _POST_SAVE
*/
function process_writesession(someInt){
	if(_POST_SAVE){
		var tmpAction = _POST_SAVE; _POST_SAVE = '';
		if(tmpAction == 'editCourse'){ editCourse(); };
		if(tmpAction == 'editDelegate'){ editDelegate(); };
		if(tmpAction.match('link:')){
			var newLocation = tmpAction.substring(tmpAction.indexOf('link:') + 5);
			document.location.href=newLocation;
		};
		return;
	};
	process_readsession(someInt);
};

function process_updatedelegate(someInt){
	if(_POST_SAVE){
		var tmpAction = _POST_SAVE; _POST_SAVE = '';
		if(tmpAction == 'editCourse'){ editCourse(); };
		if(tmpAction == 'editDelegate'){ editDelegate(); };
		if(tmpAction.match('link:')){
			var newLocation = tmpAction.substring(tmpAction.indexOf('link:') + 5);
			document.location.href=newLocation;
		};
		return;
	};
	_tellUser("Your details have been updated");
	// process_readsession(someInt);
};
function process_doaddtobasket(someInt){
	_showWait();
	document.location.href= _HTTPS_HOST + "/" +  _PROJECT + "/basket/basket.htm";
};
function process_login(someInt){
	_myDebug('process_login');
	/* first, save the session XML */
	_SESSIONXML = req[someInt].responseXML;
	_SESSIONXML_LOADED = true;
	someResponse  = _SESSIONXML.documentElement;
	var focusBooker = _getBooker();


	var someResponse = _SESSIONXML.documentElement;
	if (! someResponse.getElementsByTagName('courses') || ! someResponse.getElementsByTagName('courses')[0]) {
		var coursesNode = _SESSIONXML.createElement('courses');
		someResponse.appendChild(coursesNode);
	};
	coursesNode = someResponse.getElementsByTagName('courses')[0];

	/**
	* for each course in the basket without a delegate, add a new delegate node
	* with ID similar to the booker - that way, when I call
	* _syncDelegatesFrom(focusBooker) I'll update them to be clones
	*
	* 14/01/2008: if any of those nodes have name "", update 
	* them too.
	*/
	var saveRequired = 0;
	for (var j = 0; j < coursesNode.getElementsByTagName('course').length; j++){
		var basketItem = coursesNode.getElementsByTagName('course')[j];
		if (basketItem.getAttribute('basket') == 'basket'){
			if (! basketItem.getElementsByTagName('delegates').length){
				_myDebug('Adding delegates node');
				var delegatesNode = _SESSIONXML.createElement('delegates');
				basketItem.appendChild(delegatesNode);
			};
			var tmpDelegatesNode = basketItem.getElementsByTagName('delegates')[0];
			for (var d=0; d < tmpDelegatesNode.getElementsByTagName('delegate').length;d++) {
				var mayBeNullDelegate = tmpDelegatesNode.getElementsByTagName('delegate')[d];
				if(! _nodeData(mayBeNullDelegate,'firstname') && ! _nodeData(mayBeNullDelegate,'surname')){
					mayBeNullDelegate.setAttribute('id', _newDelegateId(focusBooker.getAttribute('id')));
				};
			};
			if (! tmpDelegatesNode.getElementsByTagName('delegate').length){
				saveRequired = 1;
				_myDebug('Adding clone of booker');
				var delegateNode = _SESSIONXML.createElement('delegate');
				delegateNode.setAttribute('id', _newDelegateId(focusBooker.getAttribute('id')));
				tmpDelegatesNode.appendChild(delegateNode);
			};
		};
	};
	_syncDelegatesFrom(focusBooker);
	process_readsession(someInt,1); // the 1 tells process_readsession not to reparse the response
	_hideOrShow('','','loginform','none');

	/* what view shall we update? */
	var looks_like_were_editing_a_delegate = 0;
	if(document.getElementById('delegate') && document.getElementById('delegate').style && document.getElementById('delegate').style.display == 'block'){
		looks_like_were_editing_a_delegate = 1;
	};
	if (looks_like_were_editing_a_delegate) {
		_myDebug("looks like we're editing a delegate");
		editDelegate();
	} else {
		_myDebug("looks like we're editing a course");
		editCourse();
	};
};
function process_logout(someInt){
	_myDebug('process_login');
	/* first, save the session XML */
	_SESSIONXML = req[someInt].responseXML;
	_SESSIONXML_LOADED = true;
	document.location.href = '/' + _PROJECT + '/basket/logout.htm';
};

function process_pay(someInt){
	/* first, save the session XML */
	_myDebug('process_pay');

	_SESSIONXML = req[someInt].responseXML;
	_SESSIONXML_LOADED = true;
	someResponse = _SESSIONXML.documentElement;
	_myDebug('Session loaded successfully.');
	_hideOrShow('','','message','none');

	var respMessage = _nodeData(someResponse,'message');
	var paymentNode = '';
	for (var n=0;n<someResponse.getElementsByTagName('payment').length;n++){
		paymentNode = someResponse.getElementsByTagName('payment')[n];
	};

	// alert('respMessage:' + respMessage);
	// if(! confirm('Continue?')){
	// 	return false;
	// };
	// alert(_mySerialize(_SESSIONXML));
	if(respMessage.match('3DAuth is required')){
		_myDebug(respMessage);
		var protXReply = someResponse.getElementsByTagName('response')[0];
		_3DAuth(_nodeData(paymentNode,'response'));
		return false;
	};

	if(! _nodeData(someResponse,'message').match('Error')){
		_hideOrShow('','','payerform_input','none');
		_hideOrShow('','','savecard_button','none');
		_hideOrShow('','','payment_ref','block');
		_hideOrShow('','','payment_info','block');
		_dropins('','subheading',_subheading_step5_html);
		_dropins('span','basket_bold_heading',"STEP 5: Confirmation");
		document.title = "STEP 5: Confirmation";
		_setClass('subheading','subheading_step5');
		_hideOrShow('','','required_field_tag','none');

		var focusBooker = _getBooker();
		var bookerNode = focusBooker.parentNode;
		var payment_ref_details = '';
		if(paymentNode){
			payment_ref_details += 'Your payment reference is: '+ _nodeData(paymentNode,'reference') +'<br />';
			payment_ref_details += 'Amount: &pound;'+ _nodeData(paymentNode,'amount') +'<br />';
			payment_ref_details += 'Description: '+ _nodeData(paymentNode,'description') +'<br />';
			if(paymentNode.getAttribute('bookingid')){
				payment_ref_details += 'Booking ID:'+ paymentNode.getAttribute('bookingid') +'<br />';
				payment_ref_details += '<br />Thank you for booking.<br />';
				payment_ref_details += '<p>';
				payment_ref_details += 'To make another booking <a href="/' + _PROJECT + '/arts/" onclick="return fileBooking();">click here</a>.';
				payment_ref_details += 'Alternatively, <a href="#" onclick="logout(); return false;">log out</a>.';
				payment_ref_details += '</p>';
				// payment_ref_details += '<p class="butt_large"><a href="/' + _PROJECT + '/arts/" onclick="return fileBooking();">Continue</a></p>';
			} else {
				payment_ref_details += 'Error: your booking has failed<br />';
			};
		} else {
			payment_ref_details += 'Error: Your payment has failed<br />';
		};
		_dropins('','payment_ref',payment_ref_details);
	};
};

/**
*
* What to do after sending a waitinglist request
*/
function process_waitinglist(someInt){
	/* first, save the session XML */
	_myDebug('process_waitinglist');
	_SESSIONXML = req[someInt].responseXML;
	_SESSIONXML_LOADED = true;
	someResponse = _SESSIONXML.documentElement;
	_myDebug('Session loaded successfully.');
	/* do nothing for now */
};

/**
*
* What to do after sending a password recover request
*/
function process_recover(someInt){
	/* first, save the session XML */
	_myDebug('process_recover');
	_SESSIONXML = req[someInt].responseXML;
	_SESSIONXML_LOADED = true;
	someResponse = _SESSIONXML.documentElement;
	_myDebug('Session loaded successfully.');
	/* do nothing for now */
};

/**
* This one's a bit different, in that the XML isn't anything to do with the
* user's session.
*/
function process_readcosts(someInt){
	_myDebug('process_readcosts, defining _COSTSXML');
	var _COSTSXML = req[someInt].responseXML;
	_COSTSXML_LOADED = true;
	var costResponse = _COSTSXML.documentElement;
	/* First row defines the headers */
	if(costResponse.getElementsByTagName('product').length){
		_myDebug('defining costs headers');
		var rowData = costResponse.getElementsByTagName('product')[0].firstChild.data;
		_COSTSHEADERS = rowData.split("|");
	} else {
		_myDebug('Error: course costs cannot be loaded');
		_tellUser('Error: course costs cannot be loaded. Please use an alternative form of booking');
		return false;
	};
	_myDebug('Start loading cost rows');
	for (r=1;r<costResponse.getElementsByTagName('product').length;r++){
		// _myDebug('load: ' + costResponse.getElementsByTagName('product')[r].firstChild.data);
		var rowData = costResponse.getElementsByTagName('product')[r].firstChild.data;
		var ci = new _newCostItem(rowData);
		_COSTSARRAY.push(ci);
		// accommodationtype
		var briefType = ci.scenario_code;
		if(briefType.indexOf(':') > -1){
			briefType = briefType.substr(0,briefType.indexOf(':'));
		};
		_dropins('span','acctype_' + briefType,ci.scenario);
		// _myDebug('defined product ' + ci.scenario_code + ' ('+ ci.product_type +')');
	};
};


function _newCostItem(someLine){
	var myParts = someLine.split("|");
	for (var p=0;p<_COSTSHEADERS.length;p++){ this[_COSTSHEADERS[p]]=myParts[p]; };
};

function process_getplaces(someInt){
	_myDebug('process_getplaces');
	/* first, save the session XML */
	_SESSIONXML = req[someInt].responseXML;
	_SESSIONXML_LOADED = true;
	someResponse  = _SESSIONXML.documentElement;
	// TODO: complete this, if we need it
};


/**
*
* START of ACTION request functions.
*
*/

/**
* We may want to readsession even if there is nowhere to
* show the results, eg, on a course listing or view page.
*/
function readsession(){
	var sessionID = getCookie('sessionid');
	_myDebug('readsession:' + sessionID);
	var reqXML = '<page title="Show Session" sessionid="'+ sessionID +'" />\n';
	doRequest(reqXML,'/cgi-bin/onlinebooking.cgi?action=read',0);
};
function writesession(noWait){
	if(! noWait){ _showWait(); };
	return doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi',1);
};
function updatedelegate(){
	_showWait();
	return doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi?action=updatedelegate',10);
};
/* an alias for writesession, so we can capture whenever we'vejust added to basket */
function doaddtobasket(noWait){
	_showWait();
	doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi',9);
};
function toggleLog(someString){
	if (someString == 'Log Out'){
		logout();
	} else {
		loginForm(1);
		// window.scroll(0,300);
		return false;
	};
};

function login(loginXML){
	_showWait();
	if(loginXML){
		doRequest(loginXML,'/cgi-bin/onlinebooking.cgi?action=login',2);
	} else {
		doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi?action=login',2);
	};
};
function logout(confirmation){
	if(! confirmation) {
		var myConfirm = confirm('Are you sure you want to logout?');
		if(myConfirm){ logout(1); };
		return false;
	};
	_showWait();
	someResponse = _SESSIONXML.documentElement;
	var sensitiveNodes = new Array('delegate','course','payment','message');
	for (var s=0;s<sensitiveNodes.length;s++){
		var sNode = sensitiveNodes[s];
		var tmpNodeCount = someResponse.getElementsByTagName(sNode).length;
		for (var c=0;c<tmpNodeCount;c++){
			try{
				var sNodeEle = someResponse.getElementsByTagName(sNode)[0]; // always get the first one - as the list is updated dynamically
				var sNodeParent = sNodeEle.parentNode;
				sNodeParent.removeChild(sNodeEle);
			} catch (e){
				// probably already removed
			};
		};
	};
	doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi?action=logout',7);
};
function waitinglist(someCourseId){
	if(! someCourseId){
		_myDebug('no course ID, so not adding to waiting list');
		return false;
	};
	doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi?action=waitinglist;id=' + someCourseId ,3);
};
function recover(){
	doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi?action=recover',6);
};

function readcosts(){
	_myDebug('readcosts');
	var reqXML = '<page />\n';
	doRequest(reqXML,'/cgi-bin/onlinebooking.cgi?action=js_costs',5);
};
/**
*
* END actions
*
*/

function doLogin(courseOrDelegate){
	/* START: Validation */
	_clearFlags();
	var fieldIDs = new Array('login_email','login_password','login_firstname','login_surname');
	for (var a=0;a<fieldIDs.length;a++){
		// _dropins('span','tmp',show_props(document.getElementById('login_email'),'myele'));
		if(document.getElementById(fieldIDs[a]) && ! _getVal(fieldIDs[a])){
			var ufriendly = fieldIDs[a];
			re = eval('/_/g'); ufriendly = ufriendly.replace(re,' ');
			_tellUser('Error: invalid ' + fieldIDs[a]);
			_flagField(document.getElementById(fieldIDs[a]));
			return false;
		};
	};

	if(document.getElementById('login_password_check')){
		if(_getVal('login_password') != _getVal('login_password_check')){
			_tellUser('Error: passwords do not match');
			_flagField(document.getElementById('login_password'));
			_flagField(document.getElementById('login_password_check'));
			return false;
		};
	};
	var tmpE = _getVal('login_email');
	if(! tmpE || ! tmpE.match(/.*@.*\..*/) ){
		_tellUser('Error: invalid email address');
		_flagField(document.getElementById('login_email'));
		return false;
	};
	/* END: Validation */

	if(! _SESSIONXML_LOADED){
		_myDebug('XML not loaded yet: attempt log in in anyway');
		var loginXML = '';
		loginXML += '<page><booker><delegate>';
		if(_getVal('login_firstname')) { loginXML += '<firstname>'+ _getVal('login_firstname') +'</firstname>'; };
		if(_getVal('login_surname')) { loginXML += '<surname>'+ _getVal('login_surname') +'</surname>'; };
		loginXML += '<email>'+ _getVal('login_email') +'</email>';
		loginXML += '<password>'+ _getVal('login_password') +'</password>';
		loginXML += '</delegate></booker></page>';
		login(loginXML);
	} else {
		someResponse  = _SESSIONXML.documentElement;
		var focusBooker = _getBooker();
		var myCDATANodes = new Array('email','password');
		for (var a=0;a<myCDATANodes.length;a++){
			_myDebug('Getting from form:' + myCDATANodes[a] +'=' + _getVal('login_' + myCDATANodes[a]));

			var tmp = _SESSIONXML.createCDATASection(_getVal('login_' + myCDATANodes[a]));
			_replaceNamedNode(focusBooker,myCDATANodes[a],tmp);
		};
		login();
	};
	return true;
};

/**
*
* This is overloaded to accept either a course ID OR a courseObject
* (as initilised by wesCourse() below) as second arg.
*
* 05/10/2007: now revised so that if basketName == 'basket'
* then we add to the basket AND go straight to checkout.
*/
function addToBasket(basketName,courseObj) {
	if(_NOBOOKING){ 
		_tellUser(_BOOK_ONLINE);
		window.scroll(0,150);
		return false;
	};
	if(_SESSIONXML_LOADED){
		if(! courseObj){
			_myDebug('Error: courseObj not defined');
			return false;
		};
		_myDebug('courseObj.id:' + courseObj.id);
		if(! courseObj.id) {
			_myDebug('courseObj is probably a course ID, try to create courseObj...');
			var myParaId = _sanitise(courseObj);
			if(document.getElementById(myParaId)) {
				_myDebug('Found a candidate paragraph');
				myCoursePara = document.getElementById(myParaId);
				/* bearing in mind the model from process_readsession above */
				var courseId = courseObj;
				var courseDBId = _findTagClass(myCoursePara,'dbid');
				var courseName = _findTagClass(myCoursePara,'name');
				var courseCost = _myParseInt(_findTagClass(myCoursePara,'cost'));
				var courseTutor = _findTagClass(myCoursePara,'tutor');
				var courseAbility = _findTagClass(myCoursePara,'ability');
				courseAbility = courseAbility.replace('Ability:','').replace('(new)','').replace(' ','');
				var courseStart = _findTagClass(myCoursePara,'start');
				var courseEnd = _findTagClass(myCoursePara,'end');
				var courseAvailability = _findTagClass(myCoursePara,'availability');
				var tmpCourse = wesCourse(courseName,courseId,courseDBId,courseStart,courseEnd,courseAbility,courseCost,courseTutor,courseAvailability);
				_myDebug('Finished defining course from paragraph');
				courseObj = tmpCourse;
				var addButtonParent = _findTagClass(myCoursePara,'add' + basketName,1);
				var addButton = addButtonParent.getElementsByTagName('a')[0];

				if(basketName == 'basket'){
					// append a "proceed to checkout" button, but only if required
					/*
					if(! document.getElementById('proceedtocheckout_new')){
						var newButtonSpan = document.createElement('span');
						newButtonSpan.setAttribute('id','proceedtocheckout_new');
						newButtonSpan.setAttribute('class','proceedtocheckout');
						newButtonSpan.className = 'proceedtocheckout';
						var newButtonAnchor = document.createElement('a');
						newButtonAnchor.setAttribute('href','/site/basket/basket.htm');
						var newButtonText = document.createTextNode('proceed to checkout');
						newButtonAnchor.appendChild(newButtonText);
						newButtonSpan.appendChild(newButtonAnchor);
						var addButtonParentSpan = addButtonParent.parentNode;
						addButtonParentSpan.insertBefore(newButtonSpan, addButtonParent.nextSibling);
					};
					*/
				} else {
					addButton.innerHTML = 'added to ' + basketName;
				};
			} else {
				_tellUser("Error: I can't find that course on this page ("+ courseObj +")");
				return false;
			};
		};

		var someResponse = _SESSIONXML.documentElement;
		if (! someResponse.getElementsByTagName('courses') || ! someResponse.getElementsByTagName('courses')[0]) {
			var coursesNode = _SESSIONXML.createElement('courses');
			someResponse.appendChild(coursesNode);
		};
		coursesNode = someResponse.getElementsByTagName('courses')[0];
		alreadyInBasket = 0;
		var alreadyInOtherBasket = '';
		var currentBasketCourse = ''; // to store the course node with attribute basket="basket", if such exists
		for (var j = 0; j < coursesNode.getElementsByTagName('course').length; j++){
			basketItem = coursesNode.getElementsByTagName('course')[j];
			if (basketItem.getAttribute('id') == courseObj.id){
				alreadyInOtherBasket = basketItem;
				if (basketItem.getAttribute('basket') == basketName){
					alreadyInBasket = 1;
				};
			};
			if(basketItem.getAttribute("basket") == 'basket'){
				currentBasketCourse = basketItem;
			};
		};
		if(! alreadyInBasket) {

			if(alreadyInOtherBasket){
				// clone it from the course with basket attribute [something else].
				var newCourseNode = alreadyInOtherBasket.cloneNode(true);
				newCourseNode.setAttribute('basket',basketName);

			} else {
				// create a new course node and append it
				var newCourseNode = _SESSIONXML.createElement('course');
				for (var i=0; i<courseObj.attribs.split(',').length;i++) {
					var attribName = courseObj.attribs.split(',')[i];
					newCourseNode.setAttribute(attribName,courseObj[attribName]);
				};
				newCourseNode.setAttribute('basket',basketName);
				var newTutorString = _SESSIONXML.createElement('tutorstring');
				var newTutorStringText = _SESSIONXML.createCDATASection(courseObj['tutor']);
				newTutorString.appendChild(newTutorStringText);
				newCourseNode.appendChild(newTutorString);
			};
			/**
			* 05/10/2007: now force overwrite for basketName == 'basket'
			* IE - there should now be at most one item in your basket at
			* any one time.
			*
			* 12/01/2008: now add a dummy delegate, then go edit them.
			*
			* START: empty the basket
			*/
			if(basketName == 'basket'){
				newCourseNode.setAttribute("editing","true");
				/* If we have previously defined delegates under a basket course, clone them */
				if(currentBasketCourse){
					if(currentBasketCourse.getElementsByTagName('delegates').length){
						var basketDelegatesClone = currentBasketCourse.getElementsByTagName('delegates')[0].cloneNode(true);
						/* delete any costs on the delegate nodes */
						for (var c=0;c<basketDelegatesClone.getElementsByTagName("delegate").length;c++){
							basketDelegatesClone.getElementsByTagName("delegate")[c].removeAttribute("cost");
							_DELEGATECOSTCACHE[basketDelegatesClone.getElementsByTagName("delegate")[c].getAttribute('id')] = '';
							_ITEMISEDCOSTS = new Array();
						};
						newCourseNode.appendChild(basketDelegatesClone);
					};
					var fosterParent = currentBasketCourse.parentNode;
					fosterParent.removeChild(currentBasketCourse);
				};
				/* Any delegates yet? If not, add a dummy */

			};
			/**
			* END: empty the basket
			*/
			coursesNode.appendChild(newCourseNode);
		};
		_myDebug('addToBasket - writesession');
		if(basketName == 'basket'){
			doaddtobasket();
		} else {
			writesession(1); /* the 1 stops the wait page showing */
		};
	} else {
		_tellUser('Error: XML not loaded yet, please wait....');
		_myDebug('addToBasket - readsession');
		readsession();
	};
};

function addToWaiting(courseObj) {
	if(_SESSIONXML_LOADED){
		if(! courseObj){
			_myDebug('Error: courseObj not defined');
			return false;
		};
		_myDebug('courseObj.id:' + courseObj.id);
		if(! courseObj.id) {
			_myDebug('courseObj is probably a course ID, try to create courseObj...');
			var myParaId = _sanitise(courseObj);
			if(document.getElementById(myParaId)) {
				_myDebug('Found a candidate paragraph');
				myCoursePara = document.getElementById(myParaId);
				/* bearing in mind the model from process_readsession above */
				var courseId = courseObj;
				var courseDBId = _findTagClass(myCoursePara,'dbid');
				var courseName = _findTagClass(myCoursePara,'name');
				var courseCost = _myParseInt(_findTagClass(myCoursePara,'cost'));

				var courseTutor = _findTagClass(myCoursePara,'tutor');
				var courseAbility = _findTagClass(myCoursePara,'ability');
				courseAbility = courseAbility.replace('Ability:','').replace('(new)','').replace(' ','');
				var courseStart = _findTagClass(myCoursePara,'start');
				var courseEnd = _findTagClass(myCoursePara,'end');
				var courseAvailability = _findTagClass(myCoursePara,'availability');
				var tmpCourse = wesCourse(courseName,courseId,courseDBId,courseStart,courseEnd,courseAbility,courseCost,courseTutor,courseAvailability);
				_myDebug('Finished defining course from paragraph');
				courseObj = tmpCourse;

			} else {
				_tellUser("Error: I can't find that course on this page ("+ courseObj +")");
				return false;
			};
		};

		// email the office about this...
		var focusBooker = _getBooker();
		if(! _nodeData(focusBooker,'email')) {
			// prompt for email address, or read it from the prompt and close the prompt
			var fieldNames = 'email|firstname|surname|telephone'.split('|');
			if(! document.getElementById('user_prompt')) {
				var promptDiv = document.createElement('div');
					promptDiv.setAttribute('id','user_prompt');
				_myDebug('Adding user_prompt');
				document.getElementsByTagName('body')[0].appendChild(promptDiv);
				var formHtml = '';
				formHtml += '<form id="p_delegateform">';
				formHtml += '<p><b>Join waiting list</b><br />Please give us your email address and we will contact you if any places become available before the course starts.</p>';
				for (var f=0;f<fieldNames.length;f++){
					formHtml += '<p><label for="p_'+ fieldNames[f] +'">'+ _capText(fieldNames[f]) +'</label><input type="text" id="p_'+ fieldNames[f] +'" /></p>';
					formHtml += '<br clear="all" />';
				};
				formHtml += '<p class="butt_large" style="float: left; width: 170px;"><a href="#top" onclick="addToWaiting(\''+ courseObj.id +'\'); return false;">add to waiting list</a></p>\n';
				formHtml += '<p class="butt_large" style="float: left; width: 170px;"><a href="#top" class="p_cancel" onclick="deleteDiv(\'user_prompt\'); return false;">cancel</a></p>\n';
				formHtml += '</form>';
				promptDiv.innerHTML = formHtml;
				document.getElementById('p_email').focus();
				return false;
			} else {
				if(! document.getElementById('p_email')) {
					_myDebug('Error: no p_email input');
					return false;
				};
				for (var f=0;f<fieldNames.length;f++){
					tmpE = document.getElementById('p_' + fieldNames[f]).value;
					if(! tmpE || (fieldNames[f] == 'email' && ! tmpE.match(/.*@.*\..*/) )){
						_tellUser('Error: invalid ' + fieldNames[f]);
						_flagField(document.getElementById('p_' + fieldNames[f]));
						return false;
					};
				};
				for (var f=0;f<fieldNames.length;f++){
					var tmpE = document.getElementById('p_' + fieldNames[f]).value;
					var tmp = _SESSIONXML.createCDATASection(tmpE);
					var targetTag = fieldNames[f];
					if (targetTag == 'telephone'){ targetTag = 'tel'; };
					_replaceNamedNode(focusBooker,targetTag,tmp);
				};
				_myDebug('Removing user_prompt');
				var promptDiv = document.getElementById('user_prompt');
				document.getElementsByTagName('body')[0].removeChild(promptDiv);
			};
		};
		// So, by now we should have a valid focusBooker email:
		_myDebug('waitinglist, courseid' + _nodeData(focusBooker,'email'));
		waitinglist(courseObj.id);
		var addButton = _findTagClass(myCoursePara,'addwaitlist',1);
		addButton.innerHTML = _COURSE_FULL_TEXT;

	} else {
		_tellUser('Error: XML not loaded yet, please wait....');
		_myDebug('addToWaiting - readsession');
		readsession();
	};
};


/*
*
* Assumes that a login form is showing
*
**/
function recoverPass() {
	if(_SESSIONXML_LOADED){

		var focusBooker = _getBooker();
		if(! _nodeData(focusBooker,'email')) {
			// prompt for email address, or read it from the prompt and close the prompt
			if(! document.getElementById('loginform')) {
				_myDebug('ERROR: no loginform, so recoverPass will now exit');
				return false;
			} else {
				if(! document.getElementById('login_email')) {
					_myDebug('Error: no login_email input');
					return false;
				};
				tmpE = document.getElementById('login_email').value;
				if(! tmpE ){
					_hideOrShow('','','recovery_instructions','block');
					return false;
				} else if(! tmpE.match(/.*@.*\..*/) ){
					_tellUser('Error: invalid email address');
					_flagField(document.getElementById('login_email'));
					return false;
				};

			var tmp = _SESSIONXML.createCDATASection(tmpE);
			_replaceNamedNode(focusBooker,'email',tmp);
			};
		};
		// So, by now we should have a valid focusBooker email:
		_myDebug('recover password for ' + _nodeData(focusBooker,'email'));
		recover();
		_tellUser(_RECOVERY_WAIT);
	} else {
		_tellUser('Error: XML not loaded yet, please wait....');
		_myDebug('recover - readsession');
		readsession();
	};
};

/**
*
* Remove a course from basket/wishlist
*
* NB: now checks to see that the booker isn't a subnode of the
* thing to be removed. If it is, it's moved to the booker node.
* It does this by recursively calling removeDelegate for each
* delegate subnode.
*
*/
function removeFromBasket(basketName,someCourseId) {
	_myDebug('removeFromBasket:' + basketName + ':' + someCourseId);
	var someResponse = _SESSIONXML.documentElement;
	var confirmed = false;
	for(i=0; i<someResponse.getElementsByTagName('course').length ;i++){
		tmpCourse = someResponse.getElementsByTagName('course')[i];
		if(tmpCourse.getAttribute('id') == someCourseId && tmpCourse.getAttribute('basket') == basketName){
			confirmed = confirm('Are you sure you want to remove course\n\t'+ tmpCourse.getAttribute('name') +'\nfrom your list?')
			if(confirmed) {
				_myDebug('Confirmed deletion of course...');
				var courseParaId = _sanitise(tmpCourse.getAttribute('id'));
				if(document.getElementById(courseParaId)){
					var paraParent = document.getElementById(courseParaId).parentNode;
					paraParent.removeChild(document.getElementById(courseParaId));
				};
				_myDebug('Preparing to delete delegates under course...');
				// remove the sub-delegates
				for (var d=0;d<tmpCourse.getElementsByTagName('delegate').length;d++){
					_myDebug('Deleting delegates under course...');
					removeDelegate(tmpCourse.getElementsByTagName('delegate')[d].getAttribute('id'),1); // The 1 supresses confirmation prompt
				};

				// and now cut it from the XML
				courseParent = tmpCourse.parentNode;
				courseParent.removeChild(tmpCourse);
			};
		};
	};
	if(confirmed) {
		_myDebug('removeFromBasket - writesession');
		writesession(1);
	};
};

function removeDelegate(someDelegateId,force) {
	var someResponse = _SESSIONXML.documentElement;

	var focusCourse = getFocusNode('course');
	if(! focusCourse) {
		_myDebug('Error: no course is focused');
		return false;
	};

	var confirmed = false;
	for(var i=0; i<focusCourse.getElementsByTagName('delegate').length ;i++){
		_myDebug('Looking for delegate in focusCourse');
		tmpDelegate = focusCourse.getElementsByTagName('delegate')[i];
		if(tmpDelegate.getAttribute('id') == someDelegateId){
			var delegateName = _nodeData(tmpDelegate,'firstname') + ' ' + _nodeData(tmpDelegate,'surname');
			if(! force) { confirmed = confirm('Are you sure you want to remove delegate "'+ delegateName +'" from your list?'); };
			if(force || confirmed) {
				var delegateParaId = _sanitise(tmpDelegate.getAttribute('id'));
				if(document.getElementById(delegateParaId)){
					var deleP = document.getElementById(delegateParaId).parentNode;
					deleP.removeChild(document.getElementById(delegateParaId));
					/* Remove its HR too */
					if(document.getElementById('hr_' + delegateParaId)) {
						var hrP = document.getElementById('hr_' + delegateParaId).parentNode;
						hrP.removeChild(document.getElementById('hr_' + delegateParaId));
					};
				};

				/**
				* Now cut it from the XML.
				*/
				var delegateParent = tmpDelegate.parentNode;
				delegateParent.removeChild(tmpDelegate);
			};
		};
	};
	if(confirmed) {
		_myDebug('removeDelegate - writesession');
		writesession(1);
	};
};

/**
*
*/
function editCourse(someCourseId){
	var focusCourse;
	if(someCourseId) {
		focusCourse = getFocusNode('course',someCourseId);
		if(! focusCourse) {
			_myDebug('Error: course ' + (someCourseId || '') + ' not found in basket');
			return false;
		};
	} else {
		focusCourse = getFocusNode('course');
		if(! focusCourse){
			_myDebug('Error: editCourse called without someCourseId and no course is in focus');
			return false;
		};
		someCourseId = focusCourse.getAttribute('id');
	};

	var basketType = focusCourse.getAttribute('basket');
	if(basketType != 'basket'){
		_myDebug('Error: focusCourse is not in basket. basketType:' + basketType);
		_dropins('','delegates','&nbsp;');
		_tellUser(_EMPTY_basket);
		return false;
	};

	_myDebug("editCourse('"+ (someCourseId || '') +"')");
	if(! document.getElementById("delegates")) {
		_myDebug('Error: cannot edit course as there is no delegates div');
		return false;
	};

	/* and now hide the shopping basket and show an editing pane for defining students and accommodation */
	_hideOrShow('','','courselist','none');
	_hideOrShow('','','delegates','block');
	_hideOrShow('','','loginform','none');
	_setClass('loginform','float_left');
	_hideOrShow('','','delegate','none');
	_setClass('subheading2','subheading_delegates');

	/* now define the HTML for the delegates div */
	var delegatesHtml = '';

	delegatesHtml += '<h1>'+ focusCourse.getAttribute('name') +'<br />\n';
	delegatesHtml += _unixtimetodate(focusCourse.getAttribute('start'),0);
	if(focusCourse.getAttribute('start') != focusCourse.getAttribute('end')){
		delegatesHtml += ' to ' + _unixtimetodate(focusCourse.getAttribute('end'),0);
	};
	delegatesHtml += ' ' + _unixtimetodate(focusCourse.getAttribute('end'),5) +'</h1>\n';

	// _dropins('','subheading','1: Students');
	_dropins('','subheading',_subheading_step1_html);
	_setClass('subheading','subheading_step1');

	/* if there is no delegates node yet, let's create one now */
	if (! focusCourse.getElementsByTagName('delegates') || ! focusCourse.getElementsByTagName('delegates')[0]) {
		var delegatesNode = _SESSIONXML.createElement('delegates');
		focusCourse.appendChild(delegatesNode);
	};
	delegatesNode = focusCourse.getElementsByTagName('delegates')[0];

	for(var d=0;d<delegatesNode.getElementsByTagName('delegate').length;d++){
		var tmpDelegate = delegatesNode.getElementsByTagName('delegate')[d];

		var completeClass = 'complete';
		var validityProblems = new Array();
		_myDebug('completeClass defaulting to incomplete');
		if (basketType == 'basket'){
			validityProblems = _validateDelegate(tmpDelegate);
			if(validityProblems[0]) { completeClass = 'incomplete'; };
		} else {
			completeClass = '';
		};

		delegatesHtml += '<p class="'+ completeClass +'" id="'+ tmpDelegate.getAttribute('id') +'">';

		if(validityProblems[0]){
			delegatesHtml += '<a class="status" href="javascript:null;" onclick="return false;">&nbsp;<span>';
			delegatesHtml += '<b>Please edit this student, the following details have not been provided:<br /></b>';
			delegatesHtml += '<br />\n - ' + validityProblems.join('<br />\n - ') + '\n\n';
			delegatesHtml += '</span></a>';
		};

		/* p inner-wrapper */
		delegatesHtml += '<span class="p_inner">';
		/* name */
		delegatesHtml += '<span class="delename">';
		delegatesHtml += (_nodeData(tmpDelegate,'firstname') || 'Unknown');
		delegatesHtml += ' ';
		delegatesHtml += (_nodeData(tmpDelegate,'surname') || 'Unknown');
		delegatesHtml += ',</span>\n';

		/* accommodation type */
		delegatesHtml += '<span class="accommodationtype">';
		var commaNeeded = 0; /* just a flag to say if we need another comma or not */
		if(tmpDelegate.getElementsByTagName('accommodation')[0] && tmpDelegate.getElementsByTagName('accommodation')[0].getAttribute('type')) {
			delegatesHtml += _lookupAccommodationType(tmpDelegate.getElementsByTagName('accommodation')[0].getAttribute('type'));
			commaNeeded = 1;
		};
		if(tmpDelegate.getAttribute('guest')){
			if(tmpDelegate.getAttribute('guest') == 'guest'){
				if (commaNeeded) { delegatesHtml += ', '; };
				delegatesHtml += 'sharing with ' + ( _getGuestName(tmpDelegate) || 'unnamed guest');
				// _nodeData(possibleSharer,'firstname') + ' ' + _nodeData(possibleSharer,'surname')
			} else {
				var sharerDelegate;
				for (var g=0;g<focusCourse.getElementsByTagName('delegate').length;g++){
					if(focusCourse.getElementsByTagName('delegate')[g].getAttribute('id') == tmpDelegate.getAttribute('guest')){
						sharerDelegate = focusCourse.getElementsByTagName('delegate')[g];
					};
				};
				if (commaNeeded) { delegatesHtml += ', '; };
				delegatesHtml += 'sharing with ' + (_getGuestName(tmpDelegate) || 'unnamed guest');
			};
		};
		delegatesHtml += '</span>\n';

		/* open buttons div - cost and edit will float right */
		delegatesHtml += '<span class="delegatebuttons">';
			/* cost of accommodation and course */
			// delegatesHtml += '<span class="delecost">';
			// delegatesHtml += '</span>\n';

			/* edit button */
			delegatesHtml += '<span class="edit"><a href="#top" onclick="editDelegate(\''+ tmpDelegate.getAttribute('id') +'\'); return false;">edit</a></span>\n';

			/* remove button */
			delegatesHtml += '<span class="remove"><a href="#top" onclick="removeDelegate(\''+ tmpDelegate.getAttribute('id') +'\'); return false;">remove</a></span>\n';

		/* close buttons div */
		delegatesHtml += '</span>\n';

		/* close p-inner-wrapper */
		delegatesHtml += '</span>\n';

		// delegatesHtml += '</p>\n<hr id="hr_'+ tmpDelegate.getAttribute('id') +'" />\n';
		delegatesHtml += '</p><br clear="all" />\n';
	};

	/**
	* TODO: If there are no delegates, but there is a booker,
	* then add the booker as the first delegate?
	*/
	if(! delegatesNode.getElementsByTagName('delegate').length) {
		delegatesHtml += '<p class="incomplete">Please use the button below to add a student to this course</p>\n<br clear="all" />\n';
	};

	delegatesHtml += '<p class="add_delegate" style="float: left;">';
	delegatesHtml += '<a href="#top" onclick="addDelegate(1); return false;">Add additional student</a>';
	delegatesHtml += '</p>';
	var focusBooker = _getBooker();
	if(_nodeData(focusBooker,'email') && _nodeData(focusBooker,'password')){
		// no need for this button here
	} else {
		// delegatesHtml += '<p class="add_delegate" style="float: left;">';
		// delegatesHtml += '<a href="#top" onclick="loginForm(1); return false;">Log in</a>';
		// delegatesHtml += '</p>';
	};
	delegatesHtml += '<hr />\n';
	delegatesHtml += '<p>' + _PLEASE_EDIT + '</p>';
	delegatesHtml += '<p class="butt_medium">';
	delegatesHtml += '<a href="summary.htm" onclick="checkCompleteClass(this,\'delegates\'); return false;">Finished</a>';
	delegatesHtml += '</p>\n';
	// delegatesHtml += '<span style="margin-left:130px; float: right; margin-top: -40px;">' + _PLEASE_EDIT + '</span>';
	// delegatesHtml += '<p>' + _PLEASE_EDIT + '</p>';
	document.getElementById("delegates").innerHTML = delegatesHtml;

	// _myDebug('editCourse - writesession');
	// writesession();
};

/**
*
* Now takes an extra param to tell it to either 
* just refresh the current view, or to go edit the
* newly added delegate
*
*/
function addDelegate(goEdit){
	/**
	*
	* Check availability attribute on course - this should be fairly up to date.
	*
	*/
	_myDebug("addDelegate()");
	var someResponse = _SESSIONXML.documentElement;

	var focusCourse = getFocusNode('course');
	if(! focusCourse) {
		_myDebug('Error: no course is focused');
		return false;
	};

	var placesCurrentlyNeeded = 1 + focusCourse.getElementsByTagName('delegate').length;
	var availablePlaces = parseInt(focusCourse.getAttribute('availability'));
	if(placesCurrentlyNeeded > availablePlaces){
		_myDebug('Error: insuffiecient places');
		_tellUser('Error: there are only ' + availablePlaces + ' places available, of which you are currently reserving ' + (placesCurrentlyNeeded - 1));
		return false;
	};

	var firstName = _NEWSTUDENT_FIRSTNAME;
	var surName = _NEWSTUDENT_SURNAME;

	/* if there is no delegates node yet, let's create one now */
	if (! focusCourse.getElementsByTagName('delegates') || ! focusCourse.getElementsByTagName('delegates')[0]) {
		var delegatesNode = _SESSIONXML.createElement('delegates');
		focusCourse.appendChild(delegatesNode);
	};
	delegatesNode = focusCourse.getElementsByTagName('delegates')[0];

	var delegateNode = _newDelegateNode(firstName,surName);
	delegatesNode.appendChild(delegateNode);

	// _myDebug('addDelegate - writesession');
	// writesession(1);

	if(! goEdit) {
		/**
		* just refresh the current view, eg, by adding the
		* newly added delegate to the list of possible room sharers
		*/
		var focusDelegate = getFocusNode('delegate');
		_setPeopleChooser(focusCourse,focusDelegate);
	} else {
		editDelegate(delegateNode.getAttribute('id'));
	};
	return delegateNode.getAttribute('id');
};

/**
* If optionalId IS NOT specified, looks for nodeName with editing
* attribute set to 'true'
*
* If optionalId IS specified, it ovverrides any setting of
* editing attribute, and sets it to the new nodeName specified
* by optionalId, if found.
*
* Problem: with our use of
* <page>
* <courses><course><delegate id="fred" /></course></courses>
* <booker><delegate id="fred" /></booker>
* </page>
*
* we may end up marking the booker delegate as editing="true" rather than
* the real 'fred' in courses. Same goes for <billing><delegate /></billing>
*
* Solution: if there exists an appropriate node within courses, it gets
* preference.
*/
function getFocusNode(nodeName,optionalId){
	var someResponse = _SESSIONXML.documentElement;
	_myDebug("getFocusNode('"+ nodeName+ "','" + (optionalId || '') + "')");
	var foundNode = false;
	var coursesNode = someResponse.getElementsByTagName('courses')[0];
	var rootNodes = new Array(coursesNode,someResponse);
	for (var n=0; n<rootNodes.length;n++){
		var rootNode = someResponse.getElementsByTagName('courses')[0];
		if(! rootNode) {
			_myDebug('Error: no current ' + nodeName);
			return false;
		};
		for(i=0; i<rootNode.getElementsByTagName(nodeName).length ;i++){
			tmpNode = rootNode.getElementsByTagName(nodeName)[i];
			if(! optionalId){
				if(tmpNode.getAttribute('editing') == 'true'){
					// ignore any editing="true" on courses with basket="basket_paid"
					if(nodeName == 'course' && tmpNode.getAttribute('basket') == 'basket_paid'){
						_myDebug('ignore any editing="true" on courses with basket="basket_paid"');
					} else {
						return tmpNode;
					};
				};
			} else {
				var inBasket = 1;
				if(nodeName == 'course'){
					if(tmpNode.getAttribute('basket') == 'basket') {
						inBasket = 1;
					} else {
						inBasket = 0;
					};
				};
				if(tmpNode.getAttribute('id') == optionalId && inBasket){
					tmpNode.setAttribute('editing','true');
					foundNode = tmpNode;
				} else {
					tmpNode.removeAttribute('editing');
				};
			};
		};
	};
	if(foundNode){
		_myDebug('getFocusNode - writesession');
		writesession(1);
	} else {
		_myDebug('Error: no current item');
	};
	return foundNode;
};


function editDelegate(someDelegateId){
	// alert("editDelegate('"+ someDelegateId + "')");
	/* hide the message box - they've digested it and they're doing something about it */
	_showWait();
	_myDebug("editDelegate('"+ someDelegateId + "')");
	if(! document.getElementById("delegate")) {
		_hideWait();
		_myDebug('Error: cannot edit delegate as there is no delegate div');
		return false;
	};

	var focusCourse = getFocusNode('course');
	if(! focusCourse) {
		_hideWait();
		_myDebug('Error: focus course not found in basket');
		return false;
	};

	var focusDelegate = getFocusNode('delegate',someDelegateId);
	if(! focusDelegate) {
		_hideWait();
		_myDebug('Error: delegate ' + someDelegateId + ' not found in booking');
		return false;
	};
	// _dropins('','subheading','1: Students');
	_dropins('','subheading',_subheading_step1b_html);
	_setClass('subheading','subheading_step1');

	/* and now hide the shopping basket and show an editing pane for the delegate*/
	_hideOrShow('','','courselist','none');
	_hideOrShow('','','delegates','none');
	_hideOrShow('','','delegate','block');
	_setClass('subheading2','subheading_delegates');


	/* populate the form */
	/* TODO: clear the form from previous entries! */
	/* first hide all that text Mike invented */
	_setVal('guestname','');
	_setVal('delegate_protection',false);
	_setVal('guest_protection',false);
	_setVal('accomm_extranight_prestart_date',false);
	_hideOrShow('','','extra_lunches','none');
	_setVal('accomm_extranight_end_date',false);
	for (var ck=0; ck<document.getElementsByTagName('input').length;ck++){
		var tmpCK = document.getElementsByTagName('input')[ck];
		if(tmpCK.getAttribute('type') == 'checkbox' && tmpCK.getAttribute('id').indexOf('meals_') > -1){
			// alert('unsetting: ' + _mySerialize(tmpCK));
			if(tmpCK.getAttribute('name') != 'first_night_dinner'){
				_setVal(tmpCK.getAttribute('id'),false);
			};
		};
	};
	_setVal('title',_capText(_nodeData(focusDelegate,'title')));
	_setVal('firstname',_capText(_nodeData(focusDelegate,'firstname')));
	_setVal('surname',_capText(_nodeData(focusDelegate,'surname')));
	_dropins('','delegate_h2','Details for ' + (_capText(_nodeData(focusDelegate,'firstname')) || _NEWSTUDENT_FIRSTNAME) + ' ' + (_capText(_nodeData(focusDelegate,'surname')) || _NEWSTUDENT_SURNAME));

	/**
	* Hide the minibus details unless the course starts Friday or Saturday
	* or ends Saturday or Sunday
	*/

	/*
	var hideMB = true;
	var startDay = _unixtimetodate(focusCourse.getAttribute('start'),8);
	var endDay = _unixtimetodate(focusCourse.getAttribute('end'),8);
	// alert(startDay + ':' + endDay);
	if (startDay == 'Friday' || startDay == 'Saturday' || endDay == 'Saturday' || endDay == 'Sunday'){
		hideMB = false;
	};
	if(hideMB){
		_hideOrShow('','','minibuses','none');
	};
	*/

	/*
	if(focusDelegate.getElementsByTagName('emergencycontact')[0]){
		_setVal('emergencycontact_name',_nodeData(focusDelegate.getElementsByTagName('emergencycontact')[0],'name'));
		_setVal('emergencycontact_tel',_nodeData(focusDelegate.getElementsByTagName('emergencycontact')[0],'emergencytel'));
	} else {
		_setVal('emergencycontact_name','');
		_setVal('emergencycontact_tel','');
	};

	_setVal('carreg',_nodeData(focusDelegate,'carreg'));
	*/

	if(focusDelegate.getElementsByTagName('minibus')[0]){
		var minibus = focusDelegate.getElementsByTagName('minibus')[0];
		if(minibus.getAttribute('arrive') == 'true'){
			_setVal('minibus_arrive',true);
		};
		if(minibus.getAttribute('return') == 'true'){
			_setVal('minibus_return',true);
		};
	};

	_setVal('specialrequirements',_nodeData(focusDelegate,'specialrequirements'));
	_setVal('dietaryrequirements',_nodeData(focusDelegate,'dietaryrequirements'));

	/* If this delegate doesn't yet have an accommodation node, we can stop here */
	if(! focusDelegate.getElementsByTagName('accommodation')[0]){
		_hideWait();
		_myDebug('Error: delegate has no accommodation node:' + _mySerialize(focusDelegate));
		return false;
	};

	var focusAccommodation = focusDelegate.getElementsByTagName('accommodation')[0];
	var noAccommRequired = false;
	// If a 1-day course, disable the select menu 'accommodation_type'
	// For our purposes, a 1-day course is anything lasting less than 25 hours.
	if(parseInt(focusCourse.getAttribute('end')) < parseInt(focusCourse.getAttribute('start')) + 60*60*25){
		_myDebug('Less than 25 hour course');
		focusAccommodation.setAttribute('type','nonres');
		noAccommRequired = true;
	} else {
		_myDebug('More than 25 hour course');
	};

	/* Meals stuff - populating the form - is only applicable if we already have an accomodation node */
	_myDebug('Populate the meals form');
	if(someResponse.getElementsByTagName('accommodation')[0]){
		/* meals */
		if(focusDelegate.getElementsByTagName('meals')[0]){
			var myMeals = focusDelegate.getElementsByTagName('meals')[0];

			/**
			* lunches are only an option for the possible extra day at start of course.
			* Breakfast and dinner are for all.
			*/
			var mealTypes = new Array('lunch','breakfast','dinner');
			// var mealTypes = new Array('breakfast','dinner');

			for (var t=0;t<mealTypes.length;t++){
				var mealtype = mealTypes[t];
				if(myMeals.getElementsByTagName(mealtype)[0]){
					var myRepast = myMeals.getElementsByTagName(mealtype)[0];
					// _myDebug('Found repast:' + _mySerialize(myRepast));
					for (var l=0;l<myRepast.getElementsByTagName('date').length;l++){
						if (myRepast.getElementsByTagName('date')[l].firstChild && myRepast.getElementsByTagName('date')[l].firstChild.data){
							var mealDate = '' + myRepast.getElementsByTagName('date')[l].firstChild.data;
							mealDate = 'meals_'+ mealtype +'_' + mealDate.replace(/\//g,'_');
							// _myDebug('_setVal(' + mealDate + ',true)');
							if(document.getElementById(mealDate)){
								_setVal(mealDate,true);
							} else {
								// meal date is out of date range, so we ought to remove it
								var tmpNode = myRepast.getElementsByTagName('date')[l];
								_myDebug('Delete meal date:' + _mySerialize(tmpNode));
								tmpNode.parentNode.removeChild(tmpNode);
							};
						};
					};
				};
			};
		};
		_myDebug('Done setting meals');
	};

	/* cancellation protection */
	if(! document.getElementById('delegate_protection')){
		_hideWait();
		_myDebug('Error: missing checkbox delegate_protection');
		return false;
	};

	if(focusDelegate.getAttribute('protection') == 'true') {
		_myDebug('delegate_protection:' + focusDelegate.getAttribute('protection'));
		_myDebug('setting delegate_protection.checked = true');
		document.getElementById('delegate_protection').checked = true;
	} else {
		_myDebug('setting delegate_protection.checked = false');
		document.getElementById('delegate_protection').checked = false;
	};

	if(focusDelegate.getAttribute('guestprotection') == 'true') {
		_myDebug('guest_protection:' + focusDelegate.getAttribute('guestprotection'));
		_myDebug('setting guest_protection.checked = true');
		document.getElementById('guest_protection').checked = true;
	} else {
		_myDebug('setting guest_protection.checked = false');
		document.getElementById('guest_protection').checked = false;
	};

	if(focusAccommodation.getAttribute('type')){
		/* Accommodation start and end */
		if(focusAccommodation.getAttribute('start') == 'true'){
			_setVal('accomm_extranight_prestart_date',true);
			_hideOrShow('','','extra_lunches','block');
		};
		if(focusAccommodation.getAttribute('end') == 'true'){
			_setVal('accomm_extranight_end_date',true);
		};
		/**
		* unfortunately, this call will call an _updateCosts
		* which reads the form data and changes the XML accordingly.
		*/
		selectAccommodationType(focusAccommodation.getAttribute('type'));
		_myDebug('Done selectAccommodationType');
	} else {
		selectAccommodationType(111);
	};


	if(noAccommRequired){
		var accommodationSelector = document.getElementById('accommodation_type');
		accommodationSelector.setAttribute('disabled','true');
		accommodationSelector.disabled = true;
	} else {
		var accommodationSelector = document.getElementById('accommodation_type');
		accommodationSelector.removeAttribute('disabled');
		accommodationSelector.disabled = false;
	};

	_myDebug('Getting delegateform');
	var deleForm = document.getElementById('delegateform');
	if(! deleForm){
		_myDebug('Error: no delegate form found - what have you been editing all this time?');
	};

	/* This stuff - populating the form - is only applicable if we already have an accomodation node */
	_myDebug('Now populate the form');
	if(someResponse.getElementsByTagName('accommodation')[0]){
		_myDebug('accommodation defined');
		/* all this trouble just for the preference radio buttons */
		if(someResponse.getElementsByTagName('accommodation')[0].getAttribute('pref')) {
			for (var p=0;p<deleForm.elements.length;p++){
				if(deleForm.elements[p].name == 'accommodation_pref') {
					if(deleForm.elements[p].value == someResponse.getElementsByTagName('accommodation')[0].getAttribute('pref')) {
						deleForm.elements[p].checked = true;
					};
				};
			};
		};
		_myDebug('Done setting pref');

		/* guestname */
		if(document.getElementById('guestname')){

			/* set up the peopleChooser menu */
			_setPeopleChooser(focusCourse,focusDelegate);

			/* genuine guest */
			if(focusDelegate.getElementsByTagName('guestname')[0] && focusDelegate.getElementsByTagName('guestname')[0].firstChild){
				_myDebug('focusDelegate:' + _mySerialize(focusDelegate));
				_myDebug('setting guestname:' + focusDelegate.getElementsByTagName('guestname')[0].firstChild.data);
				document.getElementById('guestname').value = focusDelegate.getElementsByTagName('guestname')[0].firstChild.data;
			};
			/* other delegate */
			if(focusDelegate.getAttribute('guest')){
				_myDebug('focusDelegate->guest:' + focusDelegate.getAttribute('guest'));
				/**
				* Need to make the accomodation of possibleSharer match that of focusDelegate.
				* - This is done in saveDelegate
				*/
				for (var g=0;g<focusCourse.getElementsByTagName('delegate').length;g++){
					var putativeGuestDelegate = focusCourse.getElementsByTagName('delegate')[g];
					if(putativeGuestDelegate.getAttribute('id') == focusDelegate.getAttribute('guest')){
						_myDebug('Found guest delegate:' + _nodeData(putativeGuestDelegate,'firstname'));
						var guestName = _nodeData(putativeGuestDelegate,'firstname') + ' ' + _nodeData(putativeGuestDelegate,'surname');
						_myDebug('editDelegate updating guestname element');
						document.getElementById('guestname').value = guestName;
					};
				};
				peopleChooser(focusDelegate.getAttribute('guest'));
			};
		};
		_myDebug('Done setting guestname');

	};

	/* Show a login box (loginform), if appropriate */
	var focusBooker = _getBooker();
	if(_nodeData(focusBooker,'email') && _nodeData(focusBooker,'password')){
		// then booker is logged in
		_hideOrShow('','','loginform','none');
	} else {
		// TODO: show a NICE login form
		// _hideOrShow('','','loginform','block');
		// _setClass('loginform','float_right');
		// _setClass('delegateform','width_69');
	};

	_hideWait();
};


/**
*
* Configures the people-chooser select menu for editDelegate page.
* This code used to all be within process_readsession, but it became
* lengthy and I needed to use it elsewhere.
*/
function _setPeopleChooser(focusCourse,focusDelegate){
	var myPeopleChooser = document.getElementById('people_chooser');
	if(! myPeopleChooser){
		_hideWait();
		_myDebug('Error: no myPeopleChooser');
		return false;
	};

	/* reset the chooser */
	_myDebug('reset the chooser...');
	myPeopleChooser.innerHTML = '';
	// myPeopleChooser.innerHTML = '<option value="">People in this room:</option>\n<option value="guest">There is a non-student guest to share this room</option>\n';

	var newOption = document.createElement('option');
	var newOptionText = document.createTextNode('People in this room:');
		newOption.appendChild(newOptionText);
		newOption.setAttribute('value','');
	myPeopleChooser.appendChild(newOption);

	newOption = document.createElement('option');
	newOptionText = document.createTextNode('There is a non-student guest to share this room');
		newOption.appendChild(newOptionText);
		newOption.setAttribute('value','guest');
	myPeopleChooser.appendChild(newOption);

	var sharerFound = 0;
	for (var s=0;s<focusCourse.getElementsByTagName('delegate').length;s++){
		var possibleSharer = focusCourse.getElementsByTagName('delegate')[s];
		_myDebug('sharecheck:' + possibleSharer.getAttribute('id'));
		/**
		* If someone already has a claim on me, reciprocate that claim, so
		* long as it's the first such. If it's a second (or later) claim
		* on me, release them from that claim on me.
		*
		* Next, add anyone (not myself) without a claim on anyone else
		* to the peopleChooser select menu.
		*
		* Finally, if there is (a unique) other delegate with a claim on
		* me, add them to the select menu.
		*/
		if(possibleSharer.getAttribute('guest') == focusDelegate.getAttribute('id')){
			if(! sharerFound){
				sharerFound = 1;
				_roomShare(focusDelegate,possibleSharer);
			} else {
				_myDebug('Error: can share with only one other - changing attribute of possibleSharer:' + possibleSharer.getAttribute('id'));
				possibleSharer.setAttribute('guest','');
			};
		};
		if(
			((! possibleSharer.getAttribute('guest')) && (possibleSharer.getAttribute('id') != focusDelegate.getAttribute('id'))) ||
			(possibleSharer.getAttribute('guest') == focusDelegate.getAttribute('id'))
			){
			var newOption = document.createElement('option');
			var newOptionText = document.createTextNode(_nodeData(possibleSharer,'firstname') + ' ' + _nodeData(possibleSharer,'surname'));
				newOption.appendChild(newOptionText);
				newOption.setAttribute('value',possibleSharer.getAttribute('id'));
			_myDebug('Adding option for:' + possibleSharer.getAttribute('id') + ':' + _nodeData(possibleSharer,'firstname'));
			myPeopleChooser.appendChild(newOption);
		};
	};

	/* Add an Add Student option */
	newOption = document.createElement('option');
	newOptionText = document.createTextNode('Sharing with another student');
		newOption.appendChild(newOptionText);
		newOption.setAttribute('value','newstudent');
	myPeopleChooser.appendChild(newOption);


};

/**
*
* Show the bookerform and populate it if possible.
*
* Only one booker per booking
*
*/
function editBooker(){
	_myDebug("editBooker");
	var someResponse = _SESSIONXML.documentElement;

	/* populate the booker_selector menu */
	var bookerSelector = document.getElementById('booker_selector');
	if(! bookerSelector){
		_myDebug('Error: booker_selector select is missing');
		return false;
	};

	var focusBooker = _getBooker();

	var loggedIn = false;
	if(_nodeData(focusBooker,'email') && _nodeData(focusBooker,'password')){
		loggedIn = true;
	};

	_myDebug('focusBooker:' +_mySerialize(focusBooker));
	var focusBookerID = focusBooker.getAttribute('id');
	var bookerPersonID = focusBookerID.split(':')[0];

	/* empty the selector and repopulate each time */
	_myDebug('building the chooser...');

	var optionsArray = new Array();
	optionsArray.push('a new person_MAGICSTRING_');
	var peopleIDs = new Array();
	for (var d=0;d<someResponse.getElementsByTagName('delegate').length;d++){
		var optDelegate = someResponse.getElementsByTagName('delegate')[d];
		var optDelegatePersonID = optDelegate.getAttribute('id').split(':')[0];
		_myDebug('considering person ID:' + optDelegatePersonID + ' - ' + _nodeData(optDelegate,'firstname') + ' - ' + _inArray(optDelegatePersonID,peopleIDs));
		if(optDelegatePersonID && _nodeData(optDelegate,'firstname') && _inArray(optDelegatePersonID,peopleIDs) == -1){
			_myDebug('using person ID:' + optDelegatePersonID + ' - ' + _nodeData(optDelegate,'firstname'));
			peopleIDs.push(optDelegatePersonID);
			_myDebug('peopleIDs:' + peopleIDs.join('; '));
			optionsArray.push(_nodeData(optDelegate,'firstname') + ' '+ _nodeData(optDelegate,'surname') + '_MAGICSTRING_' + optDelegate.getAttribute('id'));
		};
	};
	_myDebug('done populating new persons array, now add them to the select menu');
	_initSelectFromArray(bookerSelector,optionsArray,'_MAGICSTRING_');

	/* set the select menu to the right place and load that persons details */
	if(focusBookerID){
		_selectBooker(focusBookerID);
		if(loggedIn){
			_hideOrShow('','','booker_selectorlabel','none');
			_hideOrShow('','','booker_selector','none');
		};
	};
	_hideOrShow('','','booker','block');

};

function _selectBooker(someOptionalId){
	_myDebug('_selectBooker');
	var someResponse = _SESSIONXML.documentElement;
	var bookerSelector = document.getElementById('booker_selector');
	if(someOptionalId){
		_myDebug('someOptionalId:' + someOptionalId);
		for (var q=0;q<bookerSelector.options.length;q++){
			if(bookerSelector.options[q].value == someOptionalId){
				bookerSelector.options[q].selected = true;
			};
		};
	};

	if (! someResponse.getElementsByTagName('booker')[0] || ! someResponse.getElementsByTagName('booker')[0].getElementsByTagName('delegate')[0]){
		_myDebug('Error: no boooker delegate node - this should have been created by _editDelegate');
		return false;
	};

	_myDebug('boooker delegate node exists');
	var chosenDelegateId = bookerSelector.options[bookerSelector.options.selectedIndex].value || '';
	_myDebug('chosenDelegateId:' + chosenDelegateId);
	var useDelegate = '';
	for (var k=0; k<someResponse.getElementsByTagName('delegate').length;k++){
		if(! useDelegate && someResponse.getElementsByTagName('delegate')[k].getAttribute('id') == chosenDelegateId){
			useDelegate = someResponse.getElementsByTagName('delegate')[k];
			_myDebug('setting useDelegate');
		};
	};

	_myDebug('setting booker delegate ID to a  new variant of ' + chosenDelegateId);
	someResponse.getElementsByTagName('booker')[0].getElementsByTagName('delegate')[0].setAttribute('id',_newDelegateId(chosenDelegateId));

	_syncDelegatesFrom(useDelegate);
	var focusBooker = _getBooker();
	_myDebug('_selectBooker now populating the form');

	/* populate the form */
	var myCDATANodes = new Array('title','firstname','surname','address1','address2','address3','address4','address5','address6','email','postcode','tel','password');
	for (var a=0;a<myCDATANodes.length;a++){
		_myDebug('setting:' + myCDATANodes[a] + '=' + _nodeData(focusBooker,myCDATANodes[a]));
		var myText = _nodeData(focusBooker,myCDATANodes[a]);
		if(a < 8){ myText = _capText(myText); };
		if(myCDATANodes[a] == 'postcode'){ myText = myText.toUpperCase(); };
		_setVal(myCDATANodes[a],myText);
		if(myCDATANodes[a] == 'email'){ _setVal('email2',myText); };
	};
	_setVal('password_check',_nodeData(focusBooker,'password').toLowerCase());
	_setVal('password_old',_nodeData(focusBooker,'password').toLowerCase());

	if(focusBooker.getElementsByTagName('interests') && focusBooker.getElementsByTagName('interests')[0]){
		if(focusBooker.getElementsByTagName('interests')[0].getAttribute('email') == 'false'){
			_setVal('email_no',true);
		} else {
			_setVal('email_no',false);
		};
		var interestsNode = focusBooker.getElementsByTagName('interests')[0];
		for (var i=0;i<interestsNode.getElementsByTagName('cat').length;i++){
			var myinterest = interestsNode.getElementsByTagName('cat')[i];
			if(myinterest.getAttribute('id')){
				_setVal('interests_' + myinterest.getAttribute('id'),true);
			};
		};
	};
	_myDebug('_SESSIONXML:' + _mySerialize(_SESSIONXML));
};

/**
*
* TODO: improve validation in here
*
* If optionalUpdate == 'update' we are just trying to update
* a user's details and we do not need to go to checkout.
*/
function saveBooker(someLink,optionalUpdate){
	_myDebug("saveBooker");
	_uglyTellUser("saveBooker");
	_tellUser(' ');

	var someResponse = _SESSIONXML.documentElement;

	/* START: Validation */
	_myDebug("_clearFlags: before");
	if(! _getVal('password')){
		_tellUser('Error: invalid password');
		_flagField(document.getElementById('password'));
		return false;
	};
	_clearFlags();
	_myDebug("_clearFlags: after");
	if(! _getVal('firstname')){
		_tellUser('Error: invalid firstname');
		_flagField(document.getElementById('firstname'));
		return false;
	};
	if(! _getVal('surname')){
		_tellUser('Error: invalid surname');
		_flagField(document.getElementById('surname'));
		return false;
	};
	if(! _getVal('title')){
		_tellUser('Error: invalid title');
		_flagField(document.getElementById('title'));
		return false;
	};
	if(! _getVal('password')){
		_tellUser('Error: invalid password');
		_flagField(document.getElementById('password'));
		return false;
	};
	if(_getVal('password') != _getVal('password_check')){
		_tellUser('Error: passwords do not match');
		_flagField(document.getElementById('password'));
		_flagField(document.getElementById('password_check'));
		return false;
	};
	var tmpE = _getVal('email');
	if(! tmpE || ! tmpE.match(/.*@.*\..*/) ){
		_tellUser('Error: invalid email address');
		_flagField(document.getElementById('email'));
		return false;
	};
	if(_getVal('email') != _getVal('email2')){
		_tellUser('Error: please check your email address');
		_flagField(document.getElementById('email'));
		_flagField(document.getElementById('email2'));
		return false;
	};

	var testTel = _getVal('tel');
	if(! testTel || ! _isValid(testTel,'0123456789 ()[]+') || ! _myParseInt(testTel)){
		_tellUser("Error: please enter a valid contact telephone number.");
		_flagField(document.getElementById('tel'));
		return false;
	};

	var postCode = _getVal('postcode');
	if(! postCode){
		_tellUser("Error: please enter your post code.");
		_flagField(document.getElementById('postcode'));
		return false;
	};

	if(! _getVal('address1')){
		_tellUser("Error: please enter the first line of your address.");
		_flagField(document.getElementById('address1'));
		return false;
	};
	/*
	if(! _getVal('address2')){
		_tellUser("Error: please enter the second line of your address.");
		_flagField(document.getElementById('address2'));
		return false;
	};
	if(! _getVal('address3')){
		_tellUser("Error: please enter the third line of your address.");
		_flagField(document.getElementById('address3'));
		return false;
	};
	*/
	/* END: Validation */

	var bookerSelector = document.getElementById('booker_selector');
	if(! bookerSelector){
		_myDebug('Error: booker_selector select is missing');
		return false;
	};

	var bookerID = bookerSelector.options[bookerSelector.options.selectedIndex].value;
	_myDebug('bookerID:' + bookerID);

	var focusBooker = _getBooker();

	var myCDATANodes = new Array('title','firstname','surname','address1','address2','address3','address4','address5','address6','email','postcode','tel','password','password_old');
	for (var a=0;a<myCDATANodes.length;a++){
		_myDebug('Getting from form:' + myCDATANodes[a] +'=' + _getVal(myCDATANodes[a]));
		var myText = _getVal(myCDATANodes[a]);
		if(a < 8){ myText = _capText(myText); };
		if(myCDATANodes[a] == 'postcode'){ myText = myText.toUpperCase(); };

		var tmp = _SESSIONXML.createCDATASection(myText);
		if(myCDATANodes[a] == 'password_old'){ 
			if(_getVal(myCDATANodes[a]) != _getVal('password')){
				_replaceNamedNode(focusBooker,myCDATANodes[a],tmp);
			} else {
				for (var p=0;p<_SESSIONXML.getElementsByTagName('password_old').length;p++){
					var tmpNode = _SESSIONXML.getElementsByTagName('password_old')[p];
					tmpNode.parentNode.removeChild(tmpNode);
				};
			};
		} else {
			_replaceNamedNode(focusBooker,myCDATANodes[a],tmp);
		};
	};


	var interestsNode = _SESSIONXML.createElement('interests');
	if(document.getElementById('email_no') && document.getElementById('email_no').checked == true){
		interestsNode.setAttribute('email','false');
	};
	for (var f=0;f<document.getElementById('bookerform').elements.length;f++){
		var testInput = document.getElementById('bookerform').elements[f];
		if(testInput.getAttribute('id').indexOf('interests_') > -1 && testInput.checked == true){
			var interestName = testInput.getAttribute('id').substr(testInput.getAttribute('id').indexOf('interests_') + 10);
			var interestNode = _SESSIONXML.createElement('cat');
				interestNode.setAttribute('id',interestName);
			interestsNode.appendChild(interestNode);
		};
	};

	if(focusBooker.getElementsByTagName('interests')[0]){
		_myDebug('saveBooker - replace interests node');
		focusBooker.replaceChild(interestsNode,focusBooker.getElementsByTagName('interests')[0]);
	} else {
		_myDebug('saveBooker - appending interests node');
		focusBooker.appendChild(interestsNode);
	};

	_syncDelegatesFrom(focusBooker);

	_POST_SAVE = 'link:' + someLink.getAttribute('href');
	if(optionalUpdate == 'update'){
		_myDebug('saveBooker - updatedelegate');
		var successfulWrite = '' + updatedelegate();
		_POST_SAVE = '';
	} else {
		_myDebug('saveBooker - writesession');
		var successfulWrite = '' + writesession();
	};
	return false;
};

/**
*
* Returns the correct booker node
*/
function _getBooker(){
	_myDebug('_getBooker');
	var focusBooker = '';
	var someResponse = _SESSIONXML.documentElement;

	if(someResponse.getElementsByTagName('booker')[0]){
		_myDebug('booker node exists');
		if(someResponse.getElementsByTagName('booker')[0].getElementsByTagName('delegate')[0]){
			_myDebug('booker-delegate node exists');
			focusBooker = someResponse.getElementsByTagName('booker')[0].getElementsByTagName('delegate')[0];
		} else {
			_myDebug('booker-delegate node being created');
			// create a new delegate
			var newBooker = _SESSIONXML.createElement('delegate');
			newBooker.setAttribute('id',_newDelegateId());
			someResponse.getElementsByTagName('booker')[0].appendChild(newBooker);
			focusBooker = someResponse.getElementsByTagName('booker')[0].getElementsByTagName('delegate')[0];
		};
	} else {
		_myDebug('booker and booker-delegate nodes being created');
		// create a new booker node and booker > delegate
		var newBookerNode = _SESSIONXML.createElement('booker');
		var newBooker = _SESSIONXML.createElement('delegate');
		newBooker.setAttribute('id',_newDelegateId());
		newBookerNode.appendChild(newBooker);
		someResponse.appendChild(newBookerNode);
		focusBooker = someResponse.getElementsByTagName('booker')[0].getElementsByTagName('delegate')[0];
		_myDebug('_getBooker - writesession');
		writesession();
	};
	return focusBooker;
};

function saveCard(){
	var someResponse = _SESSIONXML.documentElement;

	/* START: Validation */
	_clearFlags();
	if(! _getVal('cardtype')){
		_tellUser('Error: please select a card type');
		_flagField(document.getElementById('cardtype'));
		return false;
	};
	if(! _getVal('cardname')){
		_tellUser("Error: please enter the cardholder's name exactly as it appears on the card");
		_flagField(document.getElementById('cardname'));
		return false;
	};
	var cardNumber = _myParseInt(_getVal('cardnumber'));
	if(! _mod10(cardNumber)){
		_tellUser('Error: your card number appears to be invalid');
		_flagField(document.getElementById('cardnumber'));
		return false;
	};
	_setVal('cardnumber',cardNumber);
	if(! cardNumber){
		_tellUser('Error: please enter the card number');
		_flagField(document.getElementById('cardnumber'));
		return false;
	};

	// var cardExpiry = _myParseInt(_getVal('cardexpiry'));
	var cardExpiry = _getVal('cardexpiry_m') + '' + _getVal('cardexpiry_y');
	_setVal('cardexpiry_m',_getVal('cardexpiry_m'));
	_setVal('cardexpiry_y',_getVal('cardexpiry_y'));
	if(! cardExpiry){
		_tellUser("Error: please enter the card's expiry date.");
		_flagField(document.getElementById('cardexpiry'));
		return false;
	};

	// var cardStartDate = _myParseInt(_getVal('cardstartdate')) || '';
	var cardStartDate = _getVal('cardstartdate_m') + '' + _getVal('cardstartdate_y');
	_setVal('cardstartdate_m',_getVal('cardstartdate_m'));
	_setVal('cardstartdate_y',_getVal('cardstartdate_y'));

	var cardSecurity = _myParseInt(_getVal('cardsecurity'));
	_setVal('cardsecurity',cardSecurity);
	if(! cardSecurity){
		_tellUser("Error: please enter the card's security code.<br /><br />The security code is the last three digits of the number appearing on the top right hand side of the signature strip of the card.");
		_flagField(document.getElementById('cardsecurity'));
		return false;
	};

	var MD = _getVal('MD');			_setVal('MD',MD);
	var PARes = _getVal('PARes');	_setVal('PARes',PARes);

	/* END: Validation */
	var bookerID = someResponse.getElementsByTagName('booker')[0].getElementsByTagName('delegate')[0].getAttribute('id');
	var focusBooker = _getBooker();
	var myCDATANodes = new Array('cardtype','cardname','cardnumber','cardexpiry','cardstartdate','cardsecurity','cardissue','MD','PARes');
	for (var a=0;a<myCDATANodes.length;a++){
		_myDebug('Getting from form:' + myCDATANodes[a] +'=' + _getVal(myCDATANodes[a]));

		var xmlNodeVal = _getVal(myCDATANodes[a]);
		if(myCDATANodes[a] == 'cardexpiry' || myCDATANodes[a] == 'cardstartdate'){
			xmlNodeVal = _getVal(myCDATANodes[a] + '_m') + '' + _getVal(myCDATANodes[a] + '_y');
			// alert(myCDATANodes[a] + ':' + xmlNodeVal);
		};

		var tmp = _SESSIONXML.createCDATASection(xmlNodeVal);
		_replaceNamedNode(focusBooker,myCDATANodes[a],tmp);
	};
	// return false;

	_showWait(_LONG_WAIT_MESSAGE);

	doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi?action=pay',4);

	return false;
};

/**
*
* Not currently needed, nor implemented in the back end
*
*/
function _getPlaces(someCourseDBID){
	if(! someCourseDBID){ return -1; };
	doRequest(_mySerialize(_SESSIONXML),'/cgi-bin/onlinebooking.cgi?action=getplaces;dbid=' + someCourseDBID,8);
};



/**
* Associate two people in a room.
*
* TODO: perhaps empty the meals nodes, as both delegates
* are resident students and as such must have all their meals.
* NB: If there's a fight, A wins.
*/
function _roomShare(delegateA,delegateB){
	// _FORCEDEBUG = 10;
	_myDebug('_roomShare: with delegateA:' + _mySerialize(delegateA));
	delegateA.setAttribute('guest',delegateB.getAttribute('id'));
	delegateB.setAttribute('guest',delegateA.getAttribute('id'));
	// alert(delegateA.getAttribute('guest') + '==' + delegateB.getAttribute('id') + '\n\n\n' + delegateB.getAttribute('guest') + '==' + delegateA.getAttribute('id'));

	var accommodationA = delegateA.getElementsByTagName('accommodation')[0];
	var accommodationB = delegateB.getElementsByTagName('accommodation')[0];
	if(! accommodationA){ _myDebug('Error: delegateA has no accommodation node'); return false; };
	if(! accommodationB){ _myDebug('Error: delegateB has no accommodation node'); return false; };
	var myAttribs = new Array('type','pref','start','end');
	for (var a=0;a<myAttribs.length;a++){
		var attribName = myAttribs[a];
		accommodationB.setAttribute(attribName,accommodationA.getAttribute(attribName));
	};
};


/**
*
* If arg noSave is set, no save to server is performed, the
* data is merely taken from the current form
*
* 12/01/2008: now we can do a saveDelegate even without a delegate 
* node being in focus! We just add a delegate to the current focus
* course, taking care to compare the new addition to the other existing
* delegates.
*/
function saveDelegate(noSave) {
	// alert('saveDelegate()');
	_myDebug('saveDelegate()');
	var someResponse = _SESSIONXML.documentElement;

	/* first update and save the session */
	var focusDelegate = getFocusNode('delegate');
	if(! focusDelegate) {
		_myDebug('Error: no delegate in focus');
		return false;
	};

	var focusCourse = getFocusNode('course');
	if(! focusCourse) {
		_myDebug('Error: focus course not found in basket');
		return false;
	};

	var deleForm = document.getElementById('delegateform');
	if(! deleForm){
		_myDebug('Error: no delegate form found - what have you been editing all this time?');
	};

	var tmp = _SESSIONXML.createCDATASection(_getVal('title'));
	_replaceNamedNode(focusDelegate,'title',tmp);

	tmp = _SESSIONXML.createCDATASection(_getVal('firstname'));
	_replaceNamedNode(focusDelegate,'firstname',tmp);

	tmp = _SESSIONXML.createCDATASection(_getVal('surname'));
	_replaceNamedNode(focusDelegate,'surname',tmp);

	/* 
	* Does it look like the person we're updating is already defined elsewhere ? 
	* If so, this delegate we're updating will adopt the ID from that other delegate
	* and later we'll synchronise all the delegates from this new updated one.
	*/

	var clonedFrom = _similarlyNamedDelegateSearch(focusDelegate);

	/*
	var focusEmergencyContact = focusDelegate.getElementsByTagName('emergencycontact')[0];
	if(! focusEmergencyContact){
		_myDebug("Missing emergencycontact node... adding it now");
		var emergencycontactNode = _SESSIONXML.createElement('emergencycontact');
		focusDelegate.appendChild(emergencycontactNode);
		focusEmergencyContact = focusDelegate.getElementsByTagName('emergencycontact')[0];
	};
	tmp = _SESSIONXML.createCDATASection(_getVal('emergencycontact_name'));
	_replaceNamedNode(focusEmergencyContact,'name',tmp);

	tmp = _SESSIONXML.createCDATASection(_getVal('emergencycontact_tel'));
	_replaceNamedNode(focusEmergencyContact,'emergencytel',tmp);

	tmp = _SESSIONXML.createCDATASection(_getVal('carreg'));
	_replaceNamedNode(focusDelegate,'carreg',tmp);
	*/

	var focusMinibus = focusDelegate.getElementsByTagName('minibus')[0];
	if(! focusMinibus){
		var minibusNode = _SESSIONXML.createElement('minibus');
			minibusNode.setAttribute('arrive','');
			minibusNode.setAttribute('return','');
		focusDelegate.appendChild(minibusNode);
		focusMinibus = minibusNode;
	};
	if(focusMinibus){
		focusMinibus.setAttribute('arrive',_getVal('minibus_arrive'));
		focusMinibus.setAttribute('return',_getVal('minibus_return'));
	};

	var tmpCopy = _getVal('specialrequirements');
	// if(tmpCopy.match('Error:')){ 
	// 	alert(tmpCopy);
	// 	_flagField(document.getElementById('specialrequirements'));
	// 	return false;
	// };
	tmp = _SESSIONXML.createCDATASection(tmpCopy);
	_replaceNamedNode(focusDelegate,'specialrequirements',tmp);

	tmpCopy = _getVal('dietaryrequirements');
	// if(tmpCopy.match('Error:')){
	// 	alert(tmpCopy);
	// 	_flagField(document.getElementById('dietaryrequirements'));
	// 	return false;
	// };
	tmp = _SESSIONXML.createCDATASection(tmpCopy);
	_replaceNamedNode(focusDelegate,'dietaryrequirements',tmp);

	var accommodationSelector = document.getElementById('accommodation_type');
	var accommodationSelected = accommodationSelector.options[accommodationSelector.options.selectedIndex].value;

	if(accommodationSelected.indexOf('_2') != -1){
		/* twin room */
	} else {
		/* single room - clear any guest details */
		tmp = _SESSIONXML.createCDATASection('');
		_myDebug('saveDelegate updating guestname - 0');
		_replaceNamedNode(focusDelegate,'guestname',tmp);
		_setVal('guestname','')
		var guestId = focusDelegate.getAttribute('guest');
		focusDelegate.setAttribute('guest','');
		if(guestId){
			/* and do same for anyone who thought they were going to be sharing with focusDelegate */
			for (var s=0;s<focusCourse.getElementsByTagName('delegate').length;s++){
				var possibleSharer = focusCourse.getElementsByTagName('delegate')[s];
				if (possibleSharer.getAttribute('id') == guestId) {
					possibleSharer.setAttribute('guest','');
					tmp = _SESSIONXML.createCDATASection('');
					_myDebug('saveDelegate updating guestname - 1');
					_replaceNamedNode(possibleSharer,'guestname',tmp);
				};
			};
		};
	};

	if(! (focusDelegate.getElementsByTagName('accommodation') && focusDelegate.getElementsByTagName('accommodation')[0])){
		_myDebug('XML is missing accommodation... adding it now');
		var accommodationNode = _SESSIONXML.createElement('accommodation');
		var mealsNode = _SESSIONXML.createElement('meals');
		accommodationNode.appendChild(mealsNode);
		_myDebug('adding accommodation and meals node');
		focusDelegate.appendChild(accommodationNode);
	};

	_myDebug('Saving accommodation type to:' + accommodationSelected);
	focusDelegate.getElementsByTagName('accommodation')[0].setAttribute('type',accommodationSelected);

	if(accommodationSelected.indexOf('superior') != -1){
		for (var p=0;p<deleForm.elements.length;p++){
			if(deleForm.elements[p].name == 'accommodation_pref') {
				if(deleForm.elements[p].checked){
					focusDelegate.getElementsByTagName('accommodation')[0].setAttribute('pref',deleForm.elements[p].value);
				};
			};
		};
	};

	if(! document.getElementById('delegate_protection')){
		_myDebug('Error: missing checkbox delegate_protection');
		return false;
	};
	// alert('save:'+document.getElementById('delegate_protection').checked);
	if(document.getElementById('delegate_protection').checked){
		_myDebug('delegate_protection checked');
		focusDelegate.setAttribute('protection','true');
	} else {
		_myDebug('delegate_protection NOT checked');
		focusDelegate.setAttribute('protection','');
	};

	if(document.getElementById('guest_protection').checked){
		_myDebug('guest_protection checked');
		focusDelegate.setAttribute('guestprotection','true');
	} else {
		_myDebug('guest_protection NOT checked');
		focusDelegate.setAttribute('guestprotection','');
	};

	/* Accommodation start and end */
	var focusAccommodation = focusDelegate.getElementsByTagName('accommodation')[0];
	if(_getVal('accomm_extranight_prestart_date')){
		focusAccommodation.setAttribute('start','true');
	} else {
		focusAccommodation.setAttribute('start','false');
	};
	if(_getVal('accomm_extranight_end_date')){
		focusAccommodation.setAttribute('end','true');
	} else {
		focusAccommodation.setAttribute('end','false');
	};

	/* meals */
	if(! focusDelegate.getElementsByTagName('meals')[0]){
		_myDebug('Error: (saveDelegate) this delegate has no meals node - who created him?');
		return false;
	};
	var myMeals = focusDelegate.getElementsByTagName('meals')[0];
	// var dinnerLog = _mySerialize(focusDelegate.getElementsByTagName('meals')[0]);

	/**
	* Problem  - we don't want to add duplicate entries for meal dates.
	* Solution - we first remove all the contents of the meals node...
	* .. but we don't want to do that unless we're sure we're going to
	* be updating that particular meal. Hence the initial pass.
	*/
	_myDebug('Starting meals purge');
	for (var p=0;p<deleForm.getElementsByTagName('input').length;p++){
		var myCheckbox = deleForm.getElementsByTagName('input')[p];
		if(myCheckbox.getAttribute('type') == 'checkbox' && myCheckbox.checked == true && myCheckbox.getAttribute('id').indexOf('meals_') > -1 ) {
			var mealType = myCheckbox.getAttribute('id').substr(6);
			mealType = mealType.substr(0,mealType.indexOf('_'));
			if(mealType){
				_myDebug('Meals purge: ' + mealType);
				/* OK, we're updating mealType - so empty that node */
				var focusRepast = myMeals.getElementsByTagName(mealType)[0];
				if(! focusRepast){
					_myDebug('This delegate has no '+ mealType +' node - adding it now');
					var tmpRepast = _SESSIONXML.createElement(mealType);
					myMeals.appendChild(tmpRepast);
					focusRepast = myMeals.getElementsByTagName(mealType)[0];
				};

				for (var m=0;m<focusRepast.getElementsByTagName('date').length;m++){
					var oldDate = focusRepast.getElementsByTagName('date')[m];
					_myDebug('Removing: ' + _mySerialize(oldDate));
					focusRepast.removeChild(oldDate);
				};
			};
		};
	};
	// dinnerLog += '\n\n' + _mySerialize(focusDelegate.getElementsByTagName('meals')[0]);

	/* OK, so now we can go through the same process, but this time always appending a new child node */
	_myDebug('Starting meals population');
	for (var p=0;p<deleForm.getElementsByTagName('input').length;p++){
		var myCheckbox = deleForm.getElementsByTagName('input')[p];
		if(myCheckbox.getAttribute('type') == 'checkbox' && myCheckbox.getAttribute('id').indexOf('meals_') > -1 ) {
			var mealType = myCheckbox.getAttribute('id').substr(6);
			var mealDate = mealType.substr(mealType.indexOf('_') + 1);
			mealType = mealType.substr(0,mealType.indexOf('_'));
			mealDate = mealDate.replace(/_/g,'\/');

			if(! mealType){
				_myDebug('Error: null meals type from ' + myCheckbox.getAttribute('id'));
				return false;
			};

			var focusRepast = myMeals.getElementsByTagName(mealType)[0];
			if(! focusRepast){
				_myDebug('Error: this delegate has no meal node - add it now');
				// return false;
				var repastNode = _SESSIONXML.createElement(mealType);
				myMeals.appendChild(repastNode);
				focusRepast = repastNode;
			};

			if(myCheckbox.checked == true){

				if(mealType == 'lunch' && ! _getVal('accomm_extranight_prestart_date')) {
					_myDebug('ignoring lunch request as not staying for extra night at start');
					// myCheckbox.checked = false;

				} else {
					if(_inArray(focusCourse.getAttribute('id').substr(0,2),oneDayCourseCodes) == -1){
						_myDebug('Adding meal date:'  + mealType + ' : ' + mealDate);
						var dinnerDate = _SESSIONXML.createElement('date');
						var tmp = _SESSIONXML.createTextNode(mealDate);
						dinnerDate.appendChild(tmp);
						focusRepast.appendChild(dinnerDate);
					} else {
						_myDebug('SKIPPING meal date:'  + mealType + ' : ' + mealDate + ' as this is a one-day course');
					};
				};
			} else {
				// alert('Remove meal date if it exists:' + mealDate + ':' + _mySerialize(myCheckbox));
				_myDebug('Remove meal date if it exists:' + mealType + ':' + mealDate);
				for (var h=0;h<focusRepast.getElementsByTagName('date').length;h++){
					var removeNode = focusRepast.getElementsByTagName('date')[h];
					if(removeNode.firstChild.data == mealDate){
						removeNode.parentNode.removeChild(removeNode);
					};
				};
			};
			// myCheckbox.onclick = function(){ _updateCosts(1); return true; };
		};
	};
	// dinnerLog += '\n\n' + _mySerialize(focusDelegate.getElementsByTagName('meals')[0]);
	// alert(dinnerLog);

	/* guestname */
	var guestId = '';
	if(_getVal('guestname')){
		var myPeopleChooser = document.getElementById('people_chooser');
		guestId = 'guest';
		for(var p=0;p<myPeopleChooser.options.length;p++){
			if (myPeopleChooser.options[p].selected){
				guestId = myPeopleChooser.options[p].value;
			};
		};
		focusDelegate.setAttribute('guest',guestId);
		if(guestId && guestId != 'guest'){
			for (var s=0;s<focusCourse.getElementsByTagName('delegate').length;s++){
				var possibleSharer = focusCourse.getElementsByTagName('delegate')[s];
				if (possibleSharer.getAttribute('id') == guestId) {
					_roomShare(focusDelegate,possibleSharer);
				};
			};
		};

		var tmp = _SESSIONXML.createCDATASection(_getVal('guestname'));
		_myDebug('saveDelegate updating guestname - 2');
		_replaceNamedNode(focusDelegate,'guestname',tmp);

		/**
		* TODO: an integrity check to ensure that if
		* A is has guest="B" then B has guest="A".
		* May not be needed, as we now do associations through
		* function _roomShare()
		*/
	};

	_syncDelegatesFrom(focusDelegate);
	if(noSave) {
		_myDebug('saveDelegate - exit without save');
		return;
	} else {
		var myPeopleChooser = document.getElementById('people_chooser');
		var guestId = 'guest';
		var placeHolderName = _NEWSTUDENT_FIRSTNAME + ' ' + _NEWSTUDENT_SURNAME;
		for(var p=0;p<myPeopleChooser.options.length;p++){
			if (myPeopleChooser.options[p].selected && myPeopleChooser.options[p].text == placeHolderName){
				guestId = myPeopleChooser.options[p].value;
			};
		};
		if(guestId && guestId != 'guest'){
			/* Set this as the focusDelegate and edit it, after a save */
			getFocusNode('delegate',guestId);
			_POST_SAVE = 'editDelegate';
		} else {
			_POST_SAVE = 'editCourse';
		};
		_myDebug('saveDelegate - writesession');
		writesession();
	};
};

function _similarlyNamedDelegateSearch(someDelegateNode){
	var someResponse = _SESSIONXML.documentElement;
	var firstName	= _nodeData(someDelegateNode,'firstname');
	var surName		= _nodeData(someDelegateNode,'surname');
	var clonedFrom = '';
	for (var r=0;r<someResponse.getElementsByTagName('delegate').length;r++){
		if(! clonedFrom){
			var tmpDelegate = someResponse.getElementsByTagName('delegate')[r];
			if(	someDelegateNode.getAttribute('id') != tmpDelegate.getAttribute('id')
				&&
				_similar(_nodeData(tmpDelegate,'firstname') + ':' + _nodeData(tmpDelegate,'surname'), firstName + ':' + surName)){
				_myDebug("Cloning a delegate");
				clonedFrom = tmpDelegate;
				var randId = _newDelegateId(tmpDelegate.getAttribute('id'));
				tmpDelegate.setAttribute('id',randId);
			};
		};
	};
	return clonedFrom;
};

/**
*
* Synchronises changes on someDelegate to
* all other delegate nodes that share the same
* person ID.
*/
function _syncDelegatesFrom(someDelegate){
	_myDebug('_syncDelegatesFrom');
	if(! someDelegate){
		_myDebug('Error: no delegate to sync from - _syncDelegatesFrom will now exit');
		return false;
	};

	var existingId = someDelegate.getAttribute('id');
	var IDPartsArray = existingId.split(':');
	if(! (IDPartsArray[0] && IDPartsArray[1] && IDPartsArray[2])){
		_myDebug('bad existingId:' + existingId + ' - _syncDelegatesFrom will now exit');
		return false;
	};

	var personRole = IDPartsArray[0] + ':' + IDPartsArray[1] + ':';

	var someResponse = _SESSIONXML.documentElement;

	/* loop over all delegates and see if we need to sync */
	for (var d=0; d<someResponse.getElementsByTagName('delegate').length; d++){
		var tmpDelegate = someResponse.getElementsByTagName('delegate')[d];

		var looksSimilar = 0;
		/* decide which delegates look similar to the logged in user */

		/* look at IDs */
		if(tmpDelegate.getAttribute('id') != existingId &&
			tmpDelegate.getAttribute('id').match(personRole)) {
			_myDebug('similar IDs:' + tmpDelegate.getAttribute('id') + ' matches ' + personRole + ' but not identical to ' + existingId);
			looksSimilar = 1;
		};

		/* also look at names */
		if(! looksSimilar &&
			_similar(_nodeData(tmpDelegate,'firstname') + _nodeData(tmpDelegate,'surname'),_nodeData(someDelegate,'firstname') + _nodeData(someDelegate,'surname'))
		) {
			_myDebug('similar names');
			looksSimilar = 1;
		};

		/* only synchronise delegates that look similar */
		if(looksSimilar){
			_myDebug('Synchronising delegate: ' + tmpDelegate.getAttribute('id') + ' from ' + _mySerialize(someDelegate));
			// _myDebug('Synchronising delegate: ' + tmpDelegate.getAttribute('id'));

			// var myCDATANodes = new Array('firstname','surname','address1','address2','address3','address4','address5','email','postcode','tel','password','specialrequirements','dietaryrequirements','carreg');
			var myCDATANodes = new Array('title','firstname','surname','address1','address2','address3','address4','address5','email','postcode','tel','password','specialrequirements','dietaryrequirements');
			for (var a=0;a<myCDATANodes.length;a++){
				var tmpData = _nodeData(someDelegate,myCDATANodes[a]);
				if(myCDATANodes[a] == 'postcode'){ tmpData = tmpData.toUpperCase(); };
				_myDebug('inserting data: ' + tmpData);
				if(tmpData) {
					_replaceNamedNode(tmpDelegate,myCDATANodes[a],_SESSIONXML.createCDATASection(tmpData));
				};
			};
			if(someDelegate.getElementsByTagName('emergencycontact') && someDelegate.getElementsByTagName('emergencycontact')[0]){
				var emergencyContactNode = someDelegate.getElementsByTagName('emergencycontact')[0];
				if(! (tmpDelegate.getElementsByTagName('emergencycontact') && tmpDelegate.getElementsByTagName('emergencycontact')[0])){
					var tmp = _SESSIONXML.createElement('emergencycontact');
					tmpDelegate.appendChild(tmp);
				};

				tmp = _SESSIONXML.createCDATASection(_nodeData(emergencyContactNode,'name'));
				_replaceNamedNode(tmpDelegate.getElementsByTagName('emergencycontact')[0],'name',tmp);

				tmp = _SESSIONXML.createCDATASection(_nodeData(emergencyContactNode,'emergencytel'));
				_replaceNamedNode(tmpDelegate.getElementsByTagName('emergencycontact')[0],'emergencytel',tmp);

			};
		};
	};
};


/**
*
* Fetches the name of the guest
*
*/
function _getGuestName(someDelegateNode){
	if(! someDelegateNode || ! someDelegateNode.getAttribute('guest')){
		_myDebug("_getGuestName returning nothing");
		return '';
	};

	if(someDelegateNode.getAttribute('guest') == 'guest'){
		_myDebug("_getGuestName returning genuine guest");
		return (_nodeData(someDelegateNode,'guestname') || 'unnamed guest');
	};

	// Otherwise we'll have to search for this person
	var tmpCourse = someDelegateNode.parentNode.parentNode;
	for (var g=0;g<tmpCourse.getElementsByTagName('delegate').length;g++){
		var putativeGuest = tmpCourse.getElementsByTagName('delegate')[g];
		if (putativeGuest.getAttribute('id') == someDelegateNode.getAttribute('guest')){
			var tmpDelegateName = _nodeData(putativeGuest,'firstname') + ' ' + _nodeData(putativeGuest,'surname');
			return tmpDelegateName;
		};
	};

	_myDebug("_getGuestName cannot find that guest, sorry");
	return '';
};



/**
* optionalType = 111 will mean reset the menu
*/
function selectAccommodationType(optionalType){

	/* first hide all that text Mike invented */
	var infoParas = 'info_accommodation|info_superiorroom|info_extradays|info_guests|info_specialguests|info_preferences|info_lunches'.split('|');
	for (var ip=0; ip<infoParas.length;ip++){
		_hideOrShow('','',infoParas[ip],'none');
	};

	var focusCourse = getFocusNode('course');
	if(! focusCourse) {
		_myDebug('Error: focus course not found in basket');
		return false;
	};

	var season_letter = 's';

	// number between 1 and 12
	var tmp_month = 1 + _unixtimetodate(focusCourse.getAttribute('start'),6);
	_myDebug('tmpAccommodation start tmp_month:' + tmp_month);
	if(tmp_month > 10 || tmp_month < 6){ season_letter = 'w'; };

	// Drop in some daily rates
	for (var k=2; k< document.getElementById('accommodation_type').options.length;k++){
		if(document.getElementById('accommodation_type').options[k].text.indexOf('£') == -1){
			var tmpAccType = document.getElementById('accommodation_type').options[k].value;
			var tmpAccomPrice = ' (£' + _getProductCostByScenario(tmpAccType + ':coursetime:' + season_letter)[0] + ' - £' + _getProductCostByScenario(tmpAccType + ':noncoursetime:' + season_letter)[0] + ' pppn)';
			document.getElementById('accommodation_type').options[k].text += tmpAccomPrice;
		};
	};

	if(optionalType == 111){
		document.getElementById('accommodation_type').options[0].selected = true;
		return false;
	};
	var someResponse = _SESSIONXML.documentElement;
	_myDebug("selectAccommodationType('"+ (optionalType || '') +"')");
	// saveDelegate();

	var focusDelegate = getFocusNode('delegate');
	if(! focusDelegate) {
		_myDebug('Error: no delegate in focus');
		return false;
	};

	_myDebug('Now look to set the accommodation type');
	var accommodationSelector = document.getElementById('accommodation_type');
	/* optionalType ovverrides anything else */
	if(optionalType){
		_myDebug('Type defined already');
		for (var s=0;s<accommodationSelector.options.length;s++){
			if(accommodationSelector.options[s].value == optionalType){
				accommodationSelector.options[s].selected = true;
			};
		};
	};
	var accommodationSelected = accommodationSelector.options[accommodationSelector.options.selectedIndex].value;
	optionalType = accommodationSelected;
	_myDebug('accommodationSelected:' + accommodationSelected);

	if(! accommodationSelected){
		_tellUser('Error: please use the select menu to specify accommodation requirements');
		return false;
	};

	_hideOrShow('','','accommodation_details','block');

	if(accommodationSelected != 'nonres'){
		_hideOrShow('','','info_accommodation','block');
		_hideOrShow('','','info_lunches','none');
		_hideOrShow('','','info_extradays','block');
		_hideOrShow('','','accommodation_nonresident','none');
		_hideOrShow('','','accommodation_resident','block');
		if(accommodationSelected.indexOf('superior') != -1){
			_hideOrShow('','','accommodation_details_superior','block');
			_hideOrShow('','','info_superiorroom','block');
			_hideOrShow('','','info_preferences','block');
		} else {
			_hideOrShow('','','accommodation_details_superior','none');
			_hideOrShow('','','info_superiorroom','none');
			_hideOrShow('','','info_preferences','none');
		};
		if(accommodationSelected.indexOf('_2') != -1){
			/* twin room */
			_hideOrShow('','','info_guests','block');
			_hideOrShow('','','info_specialguests','block');
			_hideOrShow('','','accommodation_twin','block');

		} else {
			/* single room */
			_hideOrShow('','','info_guests','none');
			_hideOrShow('','','info_specialguests','none');
			_hideOrShow('','','accommodation_twin','none');
		};

		/* and show the checkbox for lunch for you and guest for extra day at start */
		var lunchesDiv = document.getElementById('lunches');
		if (! lunchesDiv) {
			_myDebug('Error: lunch option is missing');
			return false;
		};
		/* Only do this the first time - else we end up with duplicate inputs */
		/* Empty this before refilling it - in case we edit two separate courses */
		for (var l=0;l<lunchesDiv.getElementsByTagName('input').length;l++){
			var tmpNode = lunchesDiv.getElementsByTagName('input')[l];
			tmpNode.parentNode.removeChild(tmpNode);
		};
		// if(! lunchesDiv.getElementsByTagName('input').length){
		var startTime = parseInt(focusCourse.getAttribute('start'));
		// var l = (startTime - 60*60*24);
		var l = startTime; // lunch is actually not on extra day at start, but on the day after that.
		var mealDate = new Date(l*1000);
		var mealDateFormat = _unixtimetodate(mealDate.getTime()/1000,3);
		var newLunchDateInput = document.createElement('input');
			newLunchDateInput.setAttribute('type','checkbox');
			newLunchDateInput.setAttribute('class','checkbox');
			newLunchDateInput.className = 'checkbox';
			newLunchDateInput.setAttribute('id','meals_lunch_' + mealDateFormat);
		lunchesDiv.appendChild(newLunchDateInput);
		newLunchDateInput.onclick = function(){ _updateCosts(1); return true; };

		// };

	} else {
		_myDebug('Non-resident form');
		_hideOrShow('','','info_extradays','none');
		_hideOrShow('','','info_lunches','block');
		_hideOrShow('','','accommodation_resident','none');
		_hideOrShow('','','accommodation_nonresident','block');


		var mealDatesRow		= document.getElementById('meal_dates');
		var breakfastDatesRow	= document.getElementById('breakfast_dates');
		var dinnerDatesRow		= document.getElementById('dinner_dates');

		if(! (mealDatesRow && breakfastDatesRow && dinnerDatesRow)){
			_myDebug('Error: non-resident meal options table needs to be configured');
			return false;
		};

		/* Only do this the first time - else we end up with duplicate inputs */
		/* TODO: empty this before refilling it - in case we edit two separate courses */
		_myDebug('Setting up meals form');
		if(mealDatesRow.getElementsByTagName('th').length == 1) {
			/* and show the checkboxes for breakfast and dinner */
			var startTime = parseInt(focusCourse.getAttribute('start'));
			var endTime = parseInt(focusCourse.getAttribute('end'));
			var colCount = 0;
			var colTotal = 0;
			var firstDinnerDate = '';
			/* just find the number of cols */
			for (var l = startTime; l < endTime + (23 * 60 * 60); l=l+86400){ colTotal++; };
			for (var l = startTime; l < endTime + (23 * 60 * 60); l=l+86400){
				colCount++;
				var mealDate = new Date(l*1000);
				var mealDateFormat = _unixtimetodate(mealDate.getTime()/1000,3);
				if (! firstDinnerDate){
					firstDinnerDate = 'meals_dinner_' + mealDateFormat;
				};

				/* the header row - dates */
				var newMealDate = document.createElement('th');
				var newMealDateText = document.createTextNode(_unixtimetodate(mealDate.getTime()/1000,7));
					newMealDate.appendChild(newMealDateText);
				_myDebug('Adding mealDatesRow');
				mealDatesRow.appendChild(newMealDate);

				/* Breakfast row - inputs */
				var newBreakfastCell = document.createElement('td');
				var newBreakfastDate = document.createElement('input');
					newBreakfastDate.setAttribute('type','checkbox');
					newBreakfastDate.setAttribute('class','checkbox');
					newBreakfastDate.className = 'checkbox';
					newBreakfastDate.setAttribute('id','meals_breakfast_' + _unixtimetodate(mealDate.getTime()/1000,3));
					newBreakfastDate.onclick = function(){ _updateCosts(1); return true; };

					if(colCount == 1){
						/* disable breakfast on first day, except for certain 1 day courses */
						var noBreakFastForYouMyLad = 1;
						for (var cc=0; cc<oneDayCourseCodes.length;cc++){
							if(focusCourse.getAttribute('id').substr(0,2) == oneDayCourseCodes[cc]){
								/* and while we're here, we might as well hide the dinner option */
								_hideOrShow('','','dinner_dates','none');
								noBreakFastForYouMyLad = 0;
							};
						};
						if(noBreakFastForYouMyLad) {
							newBreakfastDate.setAttribute('disabled','true');
						};
					};
					newBreakfastCell.appendChild(newBreakfastDate);
				_myDebug('Adding breakfastDatesRow');
				breakfastDatesRow.appendChild(newBreakfastCell);

				/* Dinner row - inputs */
				var newDinnerCell = document.createElement('td');
				var newDinnerDate = document.createElement('input');
					newDinnerDate.setAttribute('type','checkbox');
					newDinnerDate.setAttribute('class','checkbox');
					newDinnerDate.className = 'checkbox';
					newDinnerDate.setAttribute('id','meals_dinner_' + _unixtimetodate(mealDate.getTime()/1000,3));
					newDinnerDate.onclick = function(){ _updateCosts(1); return true; };
					/* Force them to have dinner on the first night */
					if(colCount == 1) {
						newDinnerDate.setAttribute('checked','true');
						newDinnerDate.setAttribute('name','first_night_dinner');
						newDinnerDate.setAttribute('disabled','true');
					};
					/* Prevent them from having dinner on the last night */
					if(colCount == colTotal) {
						newDinnerDate.setAttribute('disabled','true');
					};


					newDinnerCell.appendChild(newDinnerDate);
				_myDebug('Adding dinnerDatesRow');
				dinnerDatesRow.appendChild(newDinnerCell);
			};
			/* for IE 7, go back and redo the first night checkBox */
			if(firstDinnerDate){
				var firstNightDinnerCheckBox = document.getElementById(firstDinnerDate);
				if(firstNightDinnerCheckBox){
					firstNightDinnerCheckBox.checked = true;
					firstNightDinnerCheckBox.disabled = true;
				};
			};
			_myDebug('Done adding meal cols');
		};
		_myDebug('Done setting up meals form');
	};

	// check some boxes if the _SESSIONXML says they should be checked
	var mealTypes = new Array('lunch','breakfast','dinner');
	for (var t=0;t<mealTypes.length;t++){
		var mealtype = mealTypes[t];
		for (var q=0;q<focusDelegate.getElementsByTagName(mealtype).length;q++){
			var sessionMeal = focusDelegate.getElementsByTagName(mealtype)[q];
			for (var r=0;r<sessionMeal.getElementsByTagName('date').length;r++){
				var mealDate = sessionMeal.getElementsByTagName('date')[r];
				if(mealDate.firstChild && mealDate.firstChild.data) {
					var sessionMealID = mealDate.firstChild.data;
					re = eval('/\\//g');
					sessionMealID = sessionMealID.replace(re,'_');
					sessionMealID = 'meals_' + mealtype + '_' + sessionMealID;
					// alert(sessionMealID + ':true');
					_setVal(sessionMealID,true);
				};
			};
		};
	};


	_myDebug('Dropping in start_date');
	_dropins('span','start_date',_unixtimetodate((focusCourse.getAttribute('start')),4));
	_myDebug('Dropping in prestart_date');
	_dropins('span','prestart_date',_unixtimetodate((focusCourse.getAttribute('start') - 60*60*24),4));
	_myDebug('Dropping in end_date');
	_dropins('span','end_date',_unixtimetodate(focusCourse.getAttribute('end'),4));

	/**
	* Either this is the first time we see the form (no optionalType defined)
	* or this is being called by editDelegate, and we have stuff to populate it.
	* Let is therefor leave all form-filling to editDelegate
	*/

	if(optionalType){
		_myDebug('selectAccommodationType is setting type for this delegate');
		if(! focusDelegate.getElementsByTagName('accommodation')){
			_myDebug('failed to get accommodation node list');
			return false;
		};
		if(! focusDelegate.getElementsByTagName('accommodation')[0]){
			_myDebug('missing accommodation node - so, create it');

			var accommodationNode = _SESSIONXML.createElement('accommodation');
			var mealsNode = _SESSIONXML.createElement('meals');
			accommodationNode.appendChild(mealsNode);
			focusDelegate.appendChild(accommodationNode);

			// return false;
		};
		var accomm = focusDelegate.getElementsByTagName('accommodation')[0];
		accomm.setAttribute('type',optionalType);
	};
	_updateCosts(2);
	_myDebug('selectAccommodationType is exiting');
};

function peopleChooser(optionalGuestOrId){
	_myDebug('peopleChooser:' + (optionalGuestOrId || ''));
	// _hideOrShow('','','add_delegate_editing','block');
	_hideOrShow('','','accomm_shared_room_namediv','none');
	var myPeopleChooser = document.getElementById('people_chooser');
	if(optionalGuestOrId){
		for(var p=0;p<myPeopleChooser.options.length;p++){
			if (myPeopleChooser.options[p].value == optionalGuestOrId){
				_myDebug('found:' + optionalGuestOrId);
				myPeopleChooser.options[p].selected = true;
			};
		};
	};

	var chosenPersonId = myPeopleChooser.options[myPeopleChooser.options.selectedIndex].value;
	if(! chosenPersonId) {
		_myDebug('No guest chosen yet');
		return false;
	};

	var focusDelegate = getFocusNode('delegate');
	if(! focusDelegate) {
		_myDebug('Error: no delegate in focus');
		return false;
	};
	if(chosenPersonId == 'newstudent') {
		chosenPersonId = addDelegate();
		// var focusCourse = getFocusNode('course');
		// alert('peopleChooser calling _setPeopleChooser');
		// _setPeopleChooser(focusCourse,focusDelegate);
		// alert(chosenPersonId);
		return peopleChooser(chosenPersonId);
	};
	if(chosenPersonId == 'guest') {
		// _hideOrShow('','','add_delegate_editing','none');
		_hideOrShow('','','accomm_shared_room_namediv','block');
		focusDelegate.setAttribute('guest','guest');
		_updateCosts(1);
		return false;
	} else {
		/* show some options and update both parties concerned */
		var focusCourse = getFocusNode('course');
		if(! focusCourse) {
			_myDebug('Error: no course in focus');
			return false;
		};

		/* share the room */
		var roomMate = '';
		for (var s=0;s<focusCourse.getElementsByTagName('delegate').length;s++){
			var possibleSharer = focusCourse.getElementsByTagName('delegate')[s];
			if(possibleSharer.getAttribute('id') == chosenPersonId){
				// alert('found roomMate');
				roomMate = possibleSharer;
			};
		};
		if(roomMate){
			_roomShare(focusDelegate,roomMate);
			_updateCosts(1);
		};
		_hideOrShow('','','accomm_shared_room_namediv','none');
	};
};

function _doNothing(){ return false; };

/**
*
* Delete a specified document element. Used in cancel add delegate.
*
*/
function deleteDiv(someDivId){
	if(document.getElementById(someDivId)){
		var divC = document.getElementById(someDivId);
		var divP = divC.parentNode;
		divP.removeChild(divC);
	};
	return false;
};

/**
*
* Some basic cookie reading and writing
*
*/
function setCookie(name, value, expires, path, domain, secure) {
	var curCookie = name + "=" + escape(value) +
		((expires) ? "; expires=" + expires.toGMTString() : "") +
		((path) ? "; path=" + path : "") +
		((domain) ? "; domain=" + domain : "") +
		((secure) ? "; secure" : "");
	document.cookie = curCookie;
};
function _testCookies() {
	if (navigator.userAgent.toLowerCase().indexOf('safari') > -1) {
		/* we can't tell till we try setting cookies from the server... */
		_CANCOOKIE = 1;
		return _CANCOOKIE;
	};
	var d = new Date();
	d.setTime(d.getTime() + 1800000);
	setCookie("cookies", "cookies", d, false, false, false);
	_CANCOOKIE = 0;
	if (document.cookie.indexOf('cookies') != -1) { _CANCOOKIE = 1; };
	d = new Date();
	d.setTime(d.getTime() - 1800000);
	setCookie("cookies", "cookies", d, false, false, false);
	if(! _CANCOOKIE){
		_tellUser(_COOKIE_ERROR);
	};
	return _CANCOOKIE;
};

function getCookie(Name) {
	var search = Name + "=";
	if (document.cookie.length > 0) { // if there are any cookies
		offset = document.cookie.indexOf(search)
		if (offset != -1) { // if cookie exists
			offset += search.length;
			end = document.cookie.indexOf(";", offset)
			if (end == -1) end = document.cookie.length;
			return unescape(document.cookie.substring(offset, end));
		};
	};
	return '';
};

function show_props(obj, obj_name) {
	var result = "";
	for (var i in obj) {
		try {
			result += obj_name + "." + i + " = " + obj[i] + "\n";
		} catch(er) {
			alert('error:' + er);
		};
	};
	return result
};

/**
*
* Little helper functions
*
*/

// Needed just because IE is lame
function _initSelectFromArray(someSelectMenu,someArray,someSplitString){
	_myDebug('..initialising select menu from an array');

 	if(! (someSelectMenu && someArray && someSplitString)){
 		_myDebug('Error: cannot initialise a select menu without full complement of argumaents');
 		return false;
 	};
	someSelectMenu.innerHTML = '';
	for (var s=0;s<someArray.length;s++){
		var oPairs = someArray[s].split(someSplitString);
		var tmpOption = document.createElement('option');
			tmpOption.setAttribute('value',oPairs[1]);
		var tmpOptionText = document.createTextNode(oPairs[0]);
			tmpOption.appendChild(tmpOptionText);
		// alert(_mySerialize(tmpOption));
		someSelectMenu.appendChild(tmpOption);
	};
};

/**
* Validates CC numbers.
* Thanks to http://www.the-art-of-web.com/javascript/validate/3/
*/
function _mod10( cardNumber ){
	var sum = 0;
	var numdigits = cardNumber.length;
	var digits = cardNumber.split('');
	var parity = numdigits % 2;
	for(var i=0; i < numdigits; i++) {
		var digit = parseInt(digits[i]);
		if(i % 2 == parity) digit *= 2;
		if(digit > 9) digit -= 9;
		sum += parseInt(digit);
	};
	return ((sum % 10) == 0);
};


function _myDebug(someMessage,refresh){
	var newMsg = someMessage;
	var d = new Date();
	re = eval('/</g'); newMsg = newMsg.replace(re,'&lt;');
	re = eval('/>/g'); newMsg = newMsg.replace(re,'&gt;');
	newMsg  = '\n<code>' + d.toUTCString() + '</code>\n' + newMsg;
	var forced = 0;
	if(_FORCEDEBUG && ! document.getElementById('debug') && document.getElementsByTagName('body')[0]) {
		document.getElementsByTagName('body')[0].innerHTML = document.getElementsByTagName('body')[0].innerHTML + '\n<div id="debug"></div>\n';
		forced = 1;
	};
	if(document.getElementById('debug')) {
		var tmp = '';
		if(! document.getElementById('debug').innerHTML){
			tmp = '<a href="#" onClick="_myDebug(\'\',1); return false;">[clear debug]</a>\n';
			tmp += '<a href="#" onClick="alert(document.getElementById(\'debug\').innerHTML); return false;">[show debug]</a>\n';
			tmp += '<a href="#" onClick="_requestImport(); return false;">[import XML]</a>\n';
		};
		if(refresh) {
			tmp = '';
		} else {
			tmp += document.getElementById('debug').innerHTML + '<pre>' + newMsg + '</pre>';
		};
		document.getElementById('debug').innerHTML = tmp;
		if(forced && document.getElementById('notepad')){
			notepad = document.getElementById('notepad');
			if(notepad.document) {notepad.document.designMode= "On"; };
		};
		return false;
	};
};

function _tellUser(someMessage,focus) {
	var origMessage = someMessage;
	if(document.getElementById('message')) {
		/**
		* 14/01/2008: make the messages 'nicer' for sensitive WD types...
		*/
		var re = eval('/^Error: /ig');
		someMessage = someMessage.replace(re,'');
		someMessage = someMessage.substring(0,1).toUpperCase() + someMessage.substring(1);
		if(someMessage && someMessage != ' ') {
			_hideOrShow('','','message','block');
			document.getElementById('message').innerHTML = '<a name="message"></a>' + someMessage;
			if(focus || origMessage.toUpperCase().match('ERROR')) {
				document.location.href = '#message';
			};
		} else {
			_hideOrShow('','','message','none');
		};
	} else {
		/* if it's really urgent! */
		if(origMessage.toUpperCase().match('ERROR')) {
			_hideOrShow('','','message_urgent','block');
			document.getElementById('message_urgent').innerHTML = someMessage;
			// alert(someMessage);
		};
	};
};

function _inArray(someName,someArray){
	if(! someArray.length){ return -1; };
	for(var i=0;i<someArray.length;i++){
		if(someArray[i] == someName) return i;
	};
	return -1;
};

function _isValid (someString,checkString){
	if(! someString){ return 0; };
	if (! checkString){ checkString = ' 0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@.'; };
	var counter = 0;
	while (counter < someString.length) {
		if (checkString.indexOf(someString.charAt(counter)) == -1 ){ return 0;};
		counter++;
	};
	return 1;
};

function _hideOrShow(tagName,className,thingID,hideOrShow){
	// _myDebug('tagName:' + tagName + '\nclassName:' + className + '\nthingID:' + thingID + '\nhideOrShow:' + hideOrShow);
	if(thingID && document.getElementById(thingID)) {
			document.getElementById(thingID).style.display=hideOrShow;
	} else {
		for(var i=0;i<document.getElementsByTagName(tagName).length;i++){
			if(
				document.getElementsByTagName(tagName)[i].getAttribute('class') == className
			||	document.getElementsByTagName(tagName)[i].className == className){
				document.getElementsByTagName(tagName)[i].style.display=hideOrShow;
			};
		};
	};
};

function _toggleView(someEleId){
	if(! document.getElementById(someEleId)){ return false; }
	var someEle = document.getElementById(someEleId);
	if(! someEle.style.display || someEle.style.display == 'none'){
		someEle.style.display = 'block';
	} else {
		someEle.style.display = 'none';
	};
};

function _dropins(tagName,className,replacevar){
	_myDebug('_dropins:' + tagName + ',' + className + ',' + replacevar);
	var foundItem = '';
	if(tagName) {
		for(var k=0;k<document.getElementsByTagName(tagName).length;k++){
			if(		document.getElementsByTagName(tagName)[k].getAttribute('class')	== className
				||	document.getElementsByTagName(tagName)[k].className				== className ) {
				// document.getElementsByTagName(tagName)[k].innerHTML = replacevar;
				foundItem = document.getElementsByTagName(tagName)[k];
			};
		};
	} else {
		/* assume className is an element id */
		if(document.getElementById(className)){
			_myDebug('_dropins for element ID:' + className);
			// document.getElementById(className).innerHTML = replacevar;
			foundItem = document.getElementById(className);
		};
	};
	if(foundItem) {
		if (replacevar) {
			_myDebug('_dropins success');
			foundItem.innerHTML = replacevar;
		} else {
			foundItem.style.display = 'hidden';
		};
	};
};

function _setClass(elementID,someClassName){
	if(! document.getElementById(elementID)){
		_myDebug('elementID not found: ' + elementID);
		return false;
	};
	var tmpEle = document.getElementById(elementID);
	tmpEle.setAttribute('class',someClassName);
	tmpEle.className = someClassName;
};


function _setVal(elementID,someVal){
	if(! document.getElementById(elementID)){
		_myDebug('Error: elementID not found: ' + elementID);
		return false;
	};
	var tmpEle = document.getElementById(elementID);

	if(tmpEle.nodeName.toLowerCase() == 'textarea'){
		tmpEle.innerHTML = someVal;
		return false;
	};

	if(tmpEle.nodeName.toLowerCase() == 'select'){
		// alert("_setVal");
		for (var o=0; o<tmpEle.options.length; o++){
			if(tmpEle.options[o].value == someVal){
				// alert("_setVal:" + someVal);
				tmpEle.options[o].selected = true;
				return false;
			};
		};
	};

	if(! tmpEle.getAttribute('type')) {
		/* only input without a type ought to be textarea, dealt with above */
		return false;
	};
	if(tmpEle.getAttribute('type').toLowerCase() == 'checkbox') {
		tmpEle.checked = someVal;
	};
	if(tmpEle.getAttribute('type').toLowerCase() == 'text' || tmpEle.getAttribute('type').toLowerCase() == 'password' || tmpEle.getAttribute('type').toLowerCase() == 'hidden') {
		tmpEle.value = someVal;
	};
	return false;
};

function _getVal(elementID,optionalDoc){
	var mydoc = document;
	if (optionalDoc){
		mydoc = optionalDoc;
	};
	if(! mydoc.getElementById(elementID)){
		_myDebug('Error: elementID not found: ' + elementID);
		return false;
	};
	var tmpEle = mydoc.getElementById(elementID);

	if(tmpEle.nodeName.toLowerCase() == 'textarea'){
		var retCopy = tmpEle.value || tmpEle.innerHTML;
		// if(tmpEle.getAttribute('maxlength') && retCopy && retCopy.length > tmpEle.getAttribute('maxlength')){
		// 	_myDebug('Error: textarea is too long. Please use only ' + tmpEle.getAttribute('maxlength') + ' characters.');
		// 	_tellUser('Error: textarea is too long. Please use only ' + tmpEle.getAttribute('maxlength') + ' characters.');
		// 	return 'Error: textarea is too long. Please use only ' + tmpEle.getAttribute('maxlength') + ' characters.';
		// };
		return retCopy;
	};

	if(tmpEle.nodeName.toLowerCase() == 'select'){
		return tmpEle.options[tmpEle.options.selectedIndex].value;
	};

	if(! tmpEle.getAttribute('type')) {
		/* only input without a type ought to be textarea, dealt with above */
		return false;
	};
	if(tmpEle.getAttribute('type').toLowerCase() == 'checkbox') {
		return tmpEle.checked;
	};
	if(tmpEle.getAttribute('type').toLowerCase() == 'text' || tmpEle.getAttribute('type').toLowerCase() == 'password' || tmpEle.getAttribute('type').toLowerCase() == 'hidden') {
		return tmpEle.value;
	};
	return false;
};

function _showWait(optionalMessage){
	var waitDiv = document.getElementById('wait');
	optionalMessage = optionalMessage || 'Please wait for your page to refresh...';
	if(! waitDiv){
		var waitDiv = document.createElement('div');
		waitDiv.setAttribute('id','wait');
		waitDiv.innerHTML = '<p>'+ optionalMessage +'</p>';
		document.getElementsByTagName('body')[0].appendChild(waitDiv);
		var newWaitDiv = document.getElementById('wait');
		newWaitDiv.style.height = document.body.scrollHeight;
		window.scroll(0,0);
	};
};

function _hideWait(){
	var waitDiv = document.getElementById('wait');
	if(waitDiv){
		var p = waitDiv.parentNode;
		p.removeChild(waitDiv);
	};
};

/**
*
* Replace the named child node of the first arg with the third arg
* NB: Replace child nodes
*
*/
function _replaceNamedNode(someElement,someNodeName,someReplacementNode){
	if(! someElement) {
		_myDebug('Error: no element in which to do substitution');
		return false;
	};
	if(! getChildElementsByTagName(someElement,someNodeName)[0]) {
		_myDebug('Creating subnode...');
		var newSubNode = _SESSIONXML.createElement(someNodeName);
		someElement.appendChild(newSubNode);
		someElement.getElementsByTagName(someNodeName)[0].appendChild(someReplacementNode);
		return true;
	};
	var parentNode = getChildElementsByTagName(someElement,someNodeName)[0];
	var oldNode = parentNode.firstChild;
	if(oldNode){
		parentNode.replaceChild(someReplacementNode,oldNode);
	} else {
		parentNode.appendChild(someReplacementNode);
	};
	return true;
};

/**
*
* Tries to do a getElementsByTagName without recursion.
* It only looks at the parent node names to check.
*
*/
function getChildElementsByTagName(someNode,someArg) {
	var returnArray = new Array();
	var parentName = someNode.nodeName;
	for (var x=0;x<someNode.getElementsByTagName(someArg).length;x++){
		var tmpParentName = someNode.getElementsByTagName(someArg)[x].parentNode.nodeName;
		if(tmpParentName == parentName){
			returnArray.push(someNode.getElementsByTagName(someArg)[x]);
		};
	};
	return returnArray;
};

function _clearFlags(){
	for (var f=0;f<document.getElementsByTagName('b').length;f++){
		var cand = document.getElementsByTagName('b')[f];
		if(cand.getAttribute('class') == 'flag' || (cand.className && cand.className == 'flag')){
			var candP = cand.parentNode;
			candP.removeChild(cand);
		};
	};
};
function _flagField (someFormEle){
	warnFlag		= document.createElement("b");
	warnFlag.setAttribute('class','flag');
	warnFlag.className = 'flag';
	warnFlagText	= document.createTextNode("*");
	warnFlag.appendChild(warnFlagText);
	warnFlag.style.color='#FF0000';
	warnFlag.setAttribute('style','color: #FF0000;');
	if(someFormEle) {
		someFormEle.parentNode.insertBefore(warnFlag,someFormEle);
	};
};

/**
*
* Takes epoc seconds as first arg and returns date formatted in
* various forms, depending on the second arg.
*
* 0:	Friday 3rd June	or Thursday 17th May
* 1:	June 3rd 2007	or	May 17th 2007
* 2:	2007-07-03 or	2007-05-17
* 3:	2007_07_03 or	2007_05_17
* 4:	June 3	or	May 17
* 5:	2007 (4 digit year)
* 6:	0 or 3 (month number)
* 7:	Jun 3 or May 17 or Sep 5 (same as 4, but with 3-character months)
* 8:	Monday or Tuesday or Wednesday etc
*
*/
function _unixtimetodate(someUnixTime,formatNumber){
	_myDebug('_unixtimetodate(' + someUnixTime + ',' + formatNumber + ')');
	var myMonths = 'January|February|March|April|May|June|July|August|September|October|November|December'.split('|');
	var myDays = 'Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday'.split('|');
	var mydate = new Date(someUnixTime * 1000);
	var myMonthString = 1 + parseInt(mydate.getMonth());
	var myDateString = parseInt(mydate.getDate());
	if (myMonthString < 9) {
		myMonthString = '0' + myMonthString;
	} else {
		myMonthString = '' + myMonthString;
	};
	if(myDateString < 9) {
		myDateString = '0' + myDateString;
	} else {
		myDateString = '' + myDateString;
	};
	var myYear = mydate.getYear();
	if(myYear < 2000){ myYear+= 1900; };

	var myDay = myDays[mydate.getDay()];

	/* return different formats */
	if(formatNumber == 1) {
		return myMonths[mydate.getMonth()] + ' ' + _ordinalString(mydate.getDate()) + ' ' + myYear;
	};
	if(formatNumber == 2) {
		return myYear + '-' + myMonthString + '-' + myDateString;
	};
	if(formatNumber == 3) {
		return myYear + '_' + myMonthString + '_' + myDateString;
	};
	if(formatNumber == 4) {
		return myMonths[mydate.getMonth()] + ' ' + mydate.getDate();
	};
	if(formatNumber == 5) {
		return myYear;
	};
	if(formatNumber == 6) {
		return mydate.getMonth();
	};
	if(formatNumber == 7) {
		return myMonths[mydate.getMonth()].substr(0,3) + ' ' + mydate.getDate();
	};
	if(formatNumber == 8) {
		return myDay;
	};
	return myDay + ' ' + _ordinalString(mydate.getDate()) + ' ' + myMonths[mydate.getMonth()];
};

function _ordinalString(someInt){
	someInt = '' + parseInt(someInt);
	if(someInt.substr(someInt.length-1,1) == 1){ return someInt + 'st'; };
	if(someInt.substr(someInt.length-1,1) == 2){ return someInt + 'nd'; };
	if(someInt.substr(someInt.length-1,1) == 3){ return someInt + 'rd'; };
	return '' + someInt + 'th';
};

function _dateToUnixTime(dateString){
	// dateString = '17/04/2007' for example
	var myDay = dateString.substr(0,2);
	var myMonth = parseInt(dateString.substr(3,2)) - 1;
	var myYear = dateString.substr(6);
	var myDate = new Date();
	myDate.setYear(myYear);
	myDate.setMonth(myMonth);
	myDate.setDate(myDay);
	myDate.setSeconds(1);
	return parseInt(myDate.getTime() / 1000);
};

function _sanitise(someCourseId){
	someCourseId = someCourseId.replace('.','_dot_');
	return someCourseId;
};

function _myParseInt(someString,trueInt){
	if(! someString) { return 0; };
	someString = '' + someString;
	var charsA = someString.split('');
	var outS = '';
	for (var c=0;c<charsA.length;c++){
		if(charsA[c] == '.' || parseInt(charsA[c]) == charsA[c]){
			outS += '' + charsA[c];
		};
	};
	if(trueInt) {
		if (outS.substr(0,1) == '0'){
			outS = outS.substr(1);
		};
		return parseInt(outS);
	};
	return outS;
};

function _mySerialize(someXML){
	var markup = '';
	if(! someXML){ return markup; };

	/* IE */
	if(someXML.xml) {
		return someXML.xml;
	};
	try {
		/* Opra */
		xmlSerializer = document.implementation.createLSSerializer();
		markup = xmlSerializer.writeToString(someXML);
	} catch(e) {
		/* FF */
		try {
			xmlSerializer = new XMLSerializer();
			markup = xmlSerializer.serializeToString(someXML);
		} catch(e) {
			/* some stupid browser like IE */
			return '';
		};
	};
	var lineBreakNodes = new Array('course','delegate','a','b','m','n','e','f','s','g');
	for (var l=0;l<lineBreakNodes.length;l++){
		var openB = '<' + lineBreakNodes[l];
		re = eval('/' + openB + '/g');		markup = markup.replace(re,"\n" + openB);
	};
	re = eval('/\\\n\\\n/g');				markup = markup.replace(re,"\n");
	return markup;
};

function _findTagClass(someEle,someClassName,returnNode){
	if(! (someEle && someClassName)){ return ''; };
	for (var i=0;i<someEle.getElementsByTagName('*').length;i++){
		var myCandidate = someEle.getElementsByTagName('*')[i];
		var myCandidateClass = myCandidate.getAttribute('class') || myCandidate.className;
		if(myCandidateClass && myCandidateClass == someClassName){
			if(returnNode){ return myCandidate; };
			if(myCandidate.firstChild){
				return myCandidate.firstChild.data;
			};
		};
	};
	return '';
};

/**
* Only returns the first data from any subnode of someEle called someNodeName.
* Let's also force it to be a direct subnode, not just any descendant.
*/
function _nodeData(someEle,someNodeName){
	if(! (someEle && someNodeName)){ return ''; };

	if(! getChildElementsByTagName(someEle,someNodeName)[0]){
		_myDebug('No subnode called ' + someNodeName);
		return '';
	};
	if(! getChildElementsByTagName(someEle,someNodeName)[0].firstChild){
		_myDebug('No subnode called ' + someNodeName + ' with .firstChild');
		return '';
	};
	return getChildElementsByTagName(someEle,someNodeName)[0].firstChild.data;

	/*
	for (var n=0; n < someEle.getElementsByTagName(someNodeName).length;n++) {
		var testParentName = someEle.getElementsByTagName(someNodeName)[n].parentNode.nodeName.toLowerCase();
		if(testParentName == someEle.nodeName.toLowerCase()){
			if(someEle.getElementsByTagName(someNodeName)[n].firstChild) {
				return someEle.getElementsByTagName(someNodeName)[n].firstChild.data;
			};
		};
	};
	return '';
	*/
	/**
	* The old version would dig down recursively, like getElementsByTagName:
	if(! someEle.getElementsByTagName(someNodeName)[0]){ return '';  };
	if(! someEle.getElementsByTagName(someNodeName)[0].firstChild){ return ''; };
	return someEle.getElementsByTagName(someNodeName)[0].firstChild.data;
	*/
};

/**
* If we pass an existing ID, assume we're cloning an
* existing delegate, so just bump the instance number
*/
function _newDelegateId(existingId){
	var randId = '';
	var myDate = new Date();
	if(existingId) {
		var IDPartsArray = existingId.split(':');
		if(! (IDPartsArray[0] && IDPartsArray[1] && IDPartsArray[2])){
			_myDebug('bad existingId:' + existingId + ' - creating a new one');
		} else {
			var randIncrement = parseInt(myDate.getTime() / 10000) + Math.floor(Math.random()*100);
			randId = IDPartsArray[0] + ':' + IDPartsArray[1] + ':' + (parseInt(IDPartsArray[2]) + randIncrement) ;
			return randId;
		};
	};
	randId =		parseInt(myDate.getTime() / 1000) + Math.floor(Math.random()*1000);
	randId += ':' + parseInt(myDate.getTime() / 1000) + Math.floor(Math.random()*1000);
	randId += ':' + parseInt(myDate.getTime() / 1000) + Math.floor(Math.random()*1000);
	return randId;
};


/**
*
* Use an appropriate generic chunk of XML:
*
* <delegate id="dele-01" protection="" guest="guest|delegate-id">
* <title><![CDATA[Mr]]></title>
* <firstname><![CDATA[Firstname]]></firstname>
* <surname><![CDATA[Surname]]></surname>
* <guestname></guestname>
* <emergencycontact>
*   <name></name>
*   <emergencytel></emergencytel>
* </emergencycontact>
* <carreg></carreg>
* <minibus arrive="" return=""/>
* <specialrequirements></specialrequirements>
* <dietaryrequirements></dietaryrequirements>
* <accommodation type="" pref="" start="" end="" />
* <meals>
*   <breakfast />
*   <lunch />
*   <dinner />
* </meals>
* </delegate>
*/
function _newDelegateNode(firstName,surName){
	var delegateNode = _SESSIONXML.createElement('delegate');
	delegateNode.setAttribute('id',_newDelegateId());
	delegateNode.setAttribute('protection','');
	delegateNode.setAttribute('guest','');
	var titleNode = _SESSIONXML.createElement('title');
		var titleNodeText = _SESSIONXML.createCDATASection('');
			titleNode.appendChild(titleNodeText);
		delegateNode.appendChild(titleNode);
	var firstnameNode = _SESSIONXML.createElement('firstname');
		var firstnameNodeText = _SESSIONXML.createCDATASection(firstName);
			firstnameNode.appendChild(firstnameNodeText);
		delegateNode.appendChild(firstnameNode);
	var surnameNode = _SESSIONXML.createElement('surname');
		var surnameNodeText = _SESSIONXML.createCDATASection(surName);
			surnameNode.appendChild(surnameNodeText);
		delegateNode.appendChild(surnameNode);
	var guestnameNode = _SESSIONXML.createElement('guestname');
		var guestnameNodeText = _SESSIONXML.createCDATASection('');
			guestnameNode.appendChild(guestnameNodeText);
		delegateNode.appendChild(guestnameNode);
	var emergencycontactNode = _SESSIONXML.createElement('emergencycontact');
		var nameNode = _SESSIONXML.createElement('name');
			emergencycontactNode.appendChild(nameNode);
		var telNode = _SESSIONXML.createElement('emergencytel');
			emergencycontactNode.appendChild(telNode);
		delegateNode.appendChild(emergencycontactNode);
	var carregNode = _SESSIONXML.createElement('carreg');
		delegateNode.appendChild(carregNode);
	var minibusNode = _SESSIONXML.createElement('minibus');
		minibusNode.setAttribute('arrive','');
		minibusNode.setAttribute('return','');
		delegateNode.appendChild(minibusNode);
	var specialrequirementsNode = _SESSIONXML.createElement('specialrequirements');
		delegateNode.appendChild(specialrequirementsNode);
	var dietaryrequirementsNode = _SESSIONXML.createElement('dietaryrequirements');
		delegateNode.appendChild(dietaryrequirementsNode);
	var accommodationNode = _SESSIONXML.createElement('accommodation');
		accommodationNode.setAttribute('type','');
		accommodationNode.setAttribute('pref','');
		accommodationNode.setAttribute('start','');
		accommodationNode.setAttribute('end','');
		delegateNode.appendChild(accommodationNode);
	var mealsNode = _SESSIONXML.createElement('meals');
		var breakfastNode = _SESSIONXML.createElement('breakfast');
			mealsNode.appendChild(breakfastNode);
		var lunchNode = _SESSIONXML.createElement('lunch');
			mealsNode.appendChild(lunchNode);
		var dinnerNode = _SESSIONXML.createElement('dinner');
			mealsNode.appendChild(dinnerNode);
		delegateNode.appendChild(mealsNode);
	return delegateNode;
};

/**
* Call a good delegate one with
*	title
*	firstname
*	surname
*	emergencycontact_name (CUT 28/09/2007)
*	emergencycontact_tel (CUT 28/09/2007)
*	emergencycontact_tel (CUT 28/09/2007)
*
* - good delegate, no guest attribute, single room => OK
*
* - good delegate, guest attribute = 'guest', guestname, twin room => OK
*
* - good delegate, guest attribute != 'guest', twin room => OK
*
*
* MO wanted this to flag missing fields - but it's not quite that simple,
* as sometimes a more complex message would be required, EG
* 'Sharing delegate does not exist'. Also, if we want to flag
* missing fiels up on the delegates summary page, we'd want to
* flag them all up - which could be a long, long list.
*
*/
function _validateDelegate(someDelegate){
	_myDebug('_validateDelegate');
	var missingStuff = new Array();
	if(! someDelegate) {
		_myDebug('delegate not specified');
		missingStuff.push('delegate not specified');
		return false;
	};
	if(! _nodeData(someDelegate,'title')){
		_myDebug('missing title');
		missingStuff.push('title');
		// return false;
	};
	if(! _nodeData(someDelegate,'firstname')){
		_myDebug('missing firstname');
		missingStuff.push('firstname');
		// return false;
	};
	if(! _nodeData(someDelegate,'surname')){
		_myDebug('missing surname');
		missingStuff.push('surname');
		// return false;
	};
	var emergencycontact = someDelegate.getElementsByTagName('emergencycontact')[0];
	if(! emergencycontact){
		_myDebug('missing emergencycontact');
		// missingStuff.push('emergency contact');
		// return false;
	};
	if(! _nodeData(emergencycontact,'name')){
		_myDebug('missing emergencycontact_name');
		// missingStuff.push('emergency contact name');
		// return false;
	};
	/**
	* var testTel = _nodeData(emergencycontact,'tel');
	* if(! testTel || ! _isValid(testTel,'0123456789 ()[]') || ! _myParseInt(testTel)){
	* 	_myDebug('missing emergencycontact_tel');
	* 	// missingStuff.push('emergency contact tel');
	* 	// return false;
	* };
	*/
	if(! someDelegate.getElementsByTagName('accommodation')){
		_myDebug('failed to get accommodation node list');
		missingStuff.push('accommodation');
		return missingStuff;
		// return false;
	};
	if(! someDelegate.getElementsByTagName('accommodation')[0]){
		_myDebug('missing accommodation node');
		missingStuff.push('accommodation');
		return missingStuff;
		// return false;
	};
	var accomm = someDelegate.getElementsByTagName('accommodation')[0];

	if(! accomm.getAttribute('type')){
		_myDebug('missing accommodation type');
		missingStuff.push('accommodation type');
		return missingStuff;
		// return false;
	};

	if(accomm.getAttribute('type').indexOf('_2') == -1){
		/* single room */
		if(someDelegate.getAttribute('guest')){
			_myDebug('guest in single room');
			missingStuff.push('guest in single room');
			// return false;
		} else {
			// return true;
		};
	} else {
		/* twin room */
		if(someDelegate.getAttribute('guest')){
			/* guest */
			if(someDelegate.getAttribute('guest') == 'guest'){
				/* real guest */
				var tmpGuestName = _nodeData(someDelegate,'guestname');
				if(tmpGuestName && tmpGuestName.split(' ').length > 1){
					// return true;
				} else {
					_myDebug('Invalid guestname');
					missingStuff.push('guest name');
					// return false;
				};
			} else {
				/* other delegate guest - check for existence  course > delegates > delegate */
				var delegatesNode = someDelegate.parentNode;
				var gExist = 0;
				for (var t=0;t<delegatesNode.getElementsByTagName('delegate').length;t++){
					var tmpDelegate = delegatesNode.getElementsByTagName('delegate')[t];
					if(tmpDelegate.getAttribute('id') == someDelegate.getAttribute('guest')){
						gExist = 1;
					};
				};
				if(gExist){
					// return true;
				} else {
					_myDebug('Sharing delegate does not exist');
					missingStuff.push('room-sharer does not exist');
					// return false;
				};
			};
		} else {
			/* no guest */
			_myDebug('no guest in twin room');
			missingStuff.push('twin room with only one person');
			// return false;
		};
	};

	// _myDebug('Incomplete delegate');
	return missingStuff;
};

function checkCompleteClass(someLink,someDivId) {
	var focusDiv = document.getElementById(someDivId);
	if (! focusDiv){
		_myDebug("ERROR: can't find div ("+ someDivId +") for checkCompleteClass");
		return false;
	};
	for (var p=0;p<focusDiv.getElementsByTagName('p').length;p++){
		var para = focusDiv.getElementsByTagName('p')[p];
		if (para.getAttribute('class') == 'incomplete' || para.getAttribute('className') == 'incomplete') {
			_myDebug(_mySerialize(para));
			if(someDivId == 'delegates') {
				_tellUser(_INCOMPLETE_DELEGEATES);
			} else {
				_tellUser('Error: you have not supplied all the necessary information for one or more of the ' + someDivId.replace('list','s'));
			};
			return false;
		};
	};
	_myDebug('checkCompleteClass - writesession');
	writesession();
	document.location.href = someLink.getAttribute('href');
};

/**
*
* More specific stuff follows, generic stuff is all above.
*
*/


function wesCourse(name,id,dbid,start,end,ability,cost,tutor,availability){
	this.name = name;
	this.id = id;
	this.dbid = dbid;
	this.start = start;
	this.end = end;
	this.ability = ability;
	this.cost = cost;
	this.tutor = tutor;
	this.availability = availability;
	this.attribs = 'name,id,dbid,start,end,ability,cost,availability'; // NOTE: tutor is not here - I'll add this specially.
	return this;
};

function myOnLoad(){
	_myDebug('myOnLoad - readsession');
	// _hideOrShow('','','message','block');
	updateTutorSelect();
	readsession();
};

/**
*
* Used for importing XML defined by Admin user - for debug only.
* NB: doesn't check for malformed XML!!
*/
function _importXML(someString){
	doRequest(someString,'/cgi-bin/onlinebooking.cgi',1);
};
function _requestImport(){
	var importSpace = document.getElementById('xmlimportdiv');
	if(importSpace){
		_importXML(importSpace.value);
		if(importSpace){ document.getElementsByTagName('body')[0].removeChild(importSpace); };
	} else {
		var tmp = document.createElement('textarea');
		tmp.setAttribute('id','xmlimportdiv');
		document.getElementsByTagName('body')[0].appendChild(tmp);
		document.getElementById('xmlimportdiv').value = _mySerialize(_SESSIONXML);
	};
};


/**
* Compares two strings to see if they're sort of the same.
*
* Cuts spaces and makes them lower-case
*/
function _similar(a,b){
	a = '' + a; b = '' + b;
	_myDebug('comparing "'+ a +'" and "' + b + '"');
	a = a.toLowerCase();
	re = eval('/ /g'); a = a.replace(re,'');

	b = b.toLowerCase();
	re = eval('/ /g'); b = b.replace(re,'');

	if (a == b) {
		_myDebug(' - same');
		return true;
	};
	_myDebug(' - different');
	return false;
};


function _lookupAccommodationType(someType){
	_myDebug('_lookupAccommodationType: ' + someType);
	if(! _COSTSXML_LOADED){
		_myDebug('_COSTSARRAY not yet loaded..');
	};
	for (var pc=0; pc<_COSTSARRAY.length;pc++){
		var prodInfo = _COSTSARRAY[pc];
		_myDebug('_lookupAccommodationType considering ' + prodInfo.scenario_code);
		if(prodInfo.scenario_code.match(someType)){
			_myDebug('_lookupAccommodationType returns ' + prodInfo.scenario);
			return prodInfo.scenario;
		};
	};
	_myDebug('_lookupAccommodationType giving up');
	return '<span class="acctype_'+ someType +'">' + someType + '</span>';
};

/**
*
* START: functions for search page
*
*/

// Annoying little function to check lots of checkboxes
// just for display purposes.
function checkToHere(someCheckBox){
	var level = -1;
	if(someCheckBox.checked == true){
		level = parseInt(someCheckBox.value);
	} else {
		level = parseInt(someCheckBox.value) - 1;
	};
	var b = -1;
	for (var i=0;i<document.getElementsByTagName('input').length;i++){
		if(document.getElementsByTagName('input')[i].getAttribute('name') == 'ability'){
			b++;
		};
		if(b < level + 1){
			document.getElementsByTagName('input')[i].checked = true;
		} else {
			document.getElementsByTagName('input')[i].checked = false;
		};
	};
};

// Updates the select menu id="tutor"
// on change in the select menu id="subject"
function updateTutorSelect(){
	var subjSelector = document.getElementById('subject');
	var tutSelector = document.getElementById('tutor');
	var tutSelectorCache = document.getElementById('tutorcache');
	if(! (subjSelector && tutSelector && tutSelectorCache )){
		_myDebug('Error: missing subject or tutor selector, or perhaps tutorcache');
		return false;
	};
	var selectedSubject = '';
	if(document.getElementById('subject')){
		selectedSubject = document.getElementById('subject').options[document.getElementById('subject').options.selectedIndex].value;
	};
	/* first time - copy the options from normal selector to the cache */
	if (! tutSelectorCache.options.length){
		// tutSelectorCache.innerHTML = tutSelector.innerHTML;
		for (var s=0;s<tutSelector.options.length;s++){
			var tmpOption = document.createElement('option');
			tmpOption.setAttribute('value',tutSelector.options[s].value);
			tmpOption.setAttribute('class',tutSelector.options[s].getAttribute('class') || '');
			tmpOption.className = (tutSelector.options[s].className || '');
			var tmpOptionText = document.createTextNode(tutSelector.options[s].text);
			tmpOption.appendChild(tmpOptionText);
			tutSelectorCache.appendChild(tmpOption);
		};
	};

	var newOptions = new Array();
	for (var i=0; i<tutSelectorCache.options.length; i++){
		var myClassName = tutSelectorCache.options[i].getAttribute('class') || tutSelectorCache.options[i].className || '';
		_myDebug('myClassName:' + myClassName);
		if(myClassName && myClassName.match(selectedSubject)) {
			newOptions.push(tutSelectorCache.options[i].text  + '_MAGICSTRING_'+ tutSelectorCache.options[i].value);
		};
	};

	/* add in the empty option first */
	newOptions.unshift('Choose a tutor_MAGICSTRING_');

	_initSelectFromArray(tutSelector,newOptions,'_MAGICSTRING_');

};

function datePicker(someTextFieldID,someDateString){
	var someTextField = document.getElementById(someTextFieldID);
	var txtPos = _findPos(someTextField);
	var dpPopInner = document.getElementById('datepicker');
	if(! dpPopInner){
		var dpPop = document.createElement('div');
		dpPop.setAttribute('id','datepickerwrapper');

		/* ADD an iframe to hide the stuff below, if we're using IE */
		if(! window.XMLHttpRequest){
			var dpFrame = document.createElement('iframe');
			dpFrame.setAttribute('id','datepicker_frame');
			dpFrame.setAttribute('frameborder','0');
			dpFrame.allowTransparency = 'true';
			dpFrame.setAttribute('src','/resources/downloads/styles/blank.htm');
			dpPop.appendChild(dpFrame);
		};

		/* START: add listener */
		if (dpPop.addEventListener) {
			dpPop.addEventListener ("mousedown",mayClosePicker,false);
		} else if (dpPop.attachEvent) {
			dpPop.attachEvent ("onmousedown",mayClosePicker);
		} else {
			dpPop.onmousedown = mayClosePicker();
		};
		/* END: add listener */

		dpPopInner = document.createElement('div');
		dpPopInner.setAttribute('id','datepicker');
		dpPop.appendChild(dpPopInner);
		someTextField.parentNode.appendChild(dpPop);
	};

	var popInnerHTML = '';
	var myMonths = "January|February|March|April|May|June|July|August|September|October|November|December".split('|');
	var myDayCodes = "S|M|T|W|T|F|S".split('|');

	var primedDate = someDateString || someTextField.value;
	var today = new Date();
	if(primedDate){
		var tmpParts = primedDate.split('/');
		// alert('setMonth: ' + tmpParts[1] + ', day:' + tmpParts[0]);
		tmpParts[0] = _myParseInt(tmpParts[0],1);
		tmpParts[1] = _myParseInt(tmpParts[1],1)-1;
		tmpParts[2] = _myParseInt(tmpParts[2],1) + 2000;

		today.setFullYear(tmpParts[2]);
		// alert('setMonth: ' + tmpParts[1] + ', day:' + tmpParts[0]);
		today.setMonth(tmpParts[1],tmpParts[0]);
	};
	var thisMonth = today.getMonth();
	// alert('thisMonth: ' + thisMonth);
	var thisMonthWord = myMonths[thisMonth];

	/* next month and last month links */
	var nextMonthString = _myParseInt(thisMonth,1) + 2;
	// alert('nextMonthString: ' + nextMonthString);
	var nextYearString = _myParseInt(today.getFullYear(),1) - 2000;
	if(nextMonthString > 12){
		nextMonthString = nextMonthString - 12;
		nextYearString = nextYearString + 1;
	};
	var ffString = '01/' + nextMonthString + '/' + nextYearString;

	var lastMonthString = _myParseInt(thisMonth,1);
	var lastYearString = _myParseInt(today.getFullYear(),1) - 2000;
	if(lastMonthString < 1){
		lastMonthString = lastMonthString + 12;
		lastYearString = lastYearString - 1;
	};
	var rwString = '01/' + lastMonthString + '/' + lastYearString;


	popInnerHTML += '<p><a href="javascript:datePicker(\'' + someTextFieldID + '\',\''+ rwString +'\');" class="rw">&nbsp;</a> <span class="monthname">' + thisMonthWord + ' ' + today.getFullYear() + '</span> <a href="javascript:datePicker(\'' + someTextFieldID + '\',\''+ ffString +'\');" class="ff">&nbsp;</a></p>';
	popInnerHTML += '<table>';

	popInnerHTML += '<tr>';
	for (var d=0;d<myDayCodes.length;d++){
		popInnerHTML += '<th>' +  myDayCodes[d] + '</th>';
	};
	popInnerHTML += '</tr>';

	/* figure out where the first day of the month lies, fill with padders */
	var firstOfMonth = new Date(thisMonthWord + ' 1, ' + (_myParseInt(today.getFullYear(),1)));
	popInnerHTML += '<tr>';
	var d=0;
	var rowStyle = 'row0';
	while(d < firstOfMonth.getDay()){
		d++; popInnerHTML += '<td>&nbsp;</td>';
	};

	for(var md=1; md < 1 + _myParseInt(numberOfDays(thisMonth,today.getFullYear()),1); md++){
		d++;
		var cellClass = '';
		if(md == _myParseInt(today.getDate(),1)) {
			cellClass = ' class="selected"';
		};
		var thisYear = (_myParseInt(today.getFullYear(),1) - 2000);
		var tmpDateString = ((_myParseInt(md,1) > 9) ? md : '0' + md) + '/' + ((_myParseInt((thisMonth + 1),1) > 9) ? (thisMonth + 1) : '0' + (thisMonth + 1)) + '/' + ((_myParseInt(thisYear,1) > 9) ? thisYear : '0' + thisYear);
		popInnerHTML += '<td'+cellClass+'><a href="javascript:setAndClose(\'' + someTextField.getAttribute('id') + '\',\''+ tmpDateString +'\')">'+ md +'</a></td>';
		if(d == 7){
			if(rowStyle == 'row0'){rowStyle = 'row1';} else {rowStyle = 'row0';};
			popInnerHTML += '</tr>\n<tr class="'+ rowStyle +'">';
			d = 0;
		};
	};
	while(d<7){
		d++; popInnerHTML += '<td>&nbsp;</td>';
	};
	popInnerHTML += '</tr>';
	popInnerHTML += '</table>';

	// popInnerHTML += '<a href="javascript:closePicker();">close</a>';

	dpPopInner.innerHTML = popInnerHTML;
	dpPopInner.style.marginLeft = txtPos[0] + 'px';
	dpPopInner.style.marginTop = (txtPos[1] - 150) + 'px';
};

function numberOfDays(someMonth,someYear){
	var myMonthDays = "31|28|31|30|31|30|31|31|30|31|30|31".split('|');
	myMonthDays[1] = (leapYear(someYear)) ? 29 : 28;
	return myMonthDays[someMonth];
};

function leapYear(someYear){
	if(someYear%4){
		return false;
	};
	return true;
};


function mayClosePicker(e){
	var firedobj = e.target || e.srcElement;
	if(firedobj && firedobj.id == 'datepickerwrapper'){
		closePicker();
	};
};

function closePicker(){
	if (document.getElementById('datepickerwrapper')){
		var dp = document.getElementById('datepickerwrapper');
		dp.parentNode.removeChild(dp);
	};
};

function setAndClose(someElementId,someDateString){
	if(document.getElementById(someElementId)){
		document.getElementById(someElementId).value = someDateString;
	};
	closePicker();
};

/**
*
* END: functions for search page
*
*/

/**
*
* Functions to do with costing
*
*/


function _updateCosts(noCacheFlag){
	_myDebug('_updateCosts');
	var focusDelegate = getFocusNode('delegate');
	if(! focusDelegate) {
		_myDebug('No delegate in focus');
		return false;
	};

	if(_getVal('accomm_extranight_prestart_date')){
		_hideOrShow('','','extra_lunches','block');
	} else {
		_hideOrShow('','','extra_lunches','none');
	};

	/**
	* the arg true stops it from doing a real save: we just want to do
	* a copy from the form to the XML
	*/
	if(noCacheFlag != 2) {saveDelegate(true);};
	var currCosts = _delegateCost(focusDelegate,noCacheFlag); // with noCache = noCacheFlag
	_myDebug('show the current applicable protection cost for course costing: &pound;' + currCosts[0] + '('+ currCosts[2] +')');

	var tmpTot = _2dp(currCosts[2]);
	_dropins('','delegate_protection_cost','&pound;' + tmpTot);

	tmpTot = _2dp(currCosts[3]);
	_dropins('','guest_protection_cost','&pound;' + tmpTot);

	var studentTotal = currCosts[0];
	if(_getVal('delegate_protection')) {
		studentTotal += currCosts[2];
	};

	if(_getVal('guest_protection')) {
		studentTotal += currCosts[3];
	};

	tmpTot = _2dp(studentTotal);
	_dropins('span','delegate_cost','&pound;' + tmpTot);
};

/**
*
* This one works out the total cost of the course, including protection.
*
*/
function _costCourse(tmpCourse){
	_myDebug('_costCourse:' + tmpCourse.getAttribute('name'));
	var totalCourseCost = 0;
	for (var q=0;q<tmpCourse.getElementsByTagName('delegate').length;q++){
		var tmpDelegate = tmpCourse.getElementsByTagName('delegate')[q];
		var tmp = tmpDelegate.getAttribute('id');
		var delegateCostsArray = _delegateCost(tmpDelegate);
		totalCourseCost = parseFloat(totalCourseCost) + parseFloat(delegateCostsArray[0]);
		_myDebug('totalCourseCost A:' + totalCourseCost);
		if(tmpDelegate.getAttribute('protection') == 'true') {
			totalCourseCost = parseFloat(totalCourseCost) + parseFloat(delegateCostsArray[2]);
			_myDebug('totalCourseCost B:' + totalCourseCost);
		};
		if(tmpDelegate.getAttribute('guestprotection') == 'true') {
			totalCourseCost = parseFloat(totalCourseCost) + parseFloat(delegateCostsArray[3]);
			_myDebug('totalCourseCost C:' + totalCourseCost);
		};
	};
	if(totalCourseCost){
		// tmpCourse.setAttribute('cost',totalCourseCost);
	};
	_myDebug('_costCourse:' + tmpCourse.getAttribute('name') + ': ' + totalCourseCost);
	tmpCourse.setAttribute('expectedcost',totalCourseCost);
	return totalCourseCost;
};


/**
* 02/01/2008: now returns costs with and without VAT 
*/
function _getProductCostByScenario(someScenarioCode){
	_myDebug('_getProductCostByScenario:' + someScenarioCode);
	for (var pc=0; pc<_COSTSARRAY.length;pc++){
		var prodInfo = _COSTSARRAY[pc];
		if(prodInfo.scenario_code == someScenarioCode){
			var mycost = prodInfo.cost;
			if(prodInfo.vat){
				mycost = _myround(mycost * prodInfo.vat);
			};
			_myDebug('_getProductCostByScenario returns:' + mycost);
			var retArr = new Array(mycost,prodInfo.cost);
			return retArr;
		};
	};
	if(someScenarioCode.indexOf(":w") > -1 || someScenarioCode.indexOf(":s") > -1 ){
		_myDebug('trying _getProductCostByScenario without season code');
		var noSeasonCode = someScenarioCode.replace(':w','').replace(':s','');
		return 	_getProductCostByScenario(noSeasonCode);
	};
	var retArr = new Array(0,0);
	return retArr;
};

function _protectionCost(deleCost,season_letter){
	_myDebug('_protectionCost:' + deleCost + ', ' + season_letter);
	if (! deleCost) { return 0; };
	if (deleCost <= _getProductCostByScenario('cp_1_boundary:' + season_letter)[0]){ return _getProductCostByScenario('cp_1:' + season_letter)[0]; };
	if (deleCost <= _getProductCostByScenario('cp_2_boundary:' + season_letter)[0]){ return _getProductCostByScenario('cp_2:' + season_letter)[0]; };
	if (deleCost <= _getProductCostByScenario('cp_3_boundary:' + season_letter)[0]){ return _getProductCostByScenario('cp_3:' + season_letter)[0]; };
	_myDebug('Error:' + deleCost + ' has no _protectionCost');
	return 0;
};

function delegateProtectionClick(someCheckBox)	{
	if(someCheckBox.checked && ! confirm('By selecting this option, I confirm I have read, understood and agreed to the terms and conditions')){
		return false;
	};
	setTimeout (_updateCosts, 200); /* can use cached costs for this */
	return true;
};


/**
*
* Round an amount of pounds and pence to the nearest 5p
*
*/
function _myround (number){
	number = number * 20;
	number = Math.round(number);
	number = number / 20;
	return number;
};

/**
* Add .00 to any numbers without pence
*/
function _2dp(quantity){
	quantity = quantity || '';
	quantity = '' + quantity;
	/* if there is no decimal point at all */
	if(quantity && quantity != 'undefined' && quantity.indexOf(".") == -1){ quantity += '.00'; };
	/* if there is a decimal point, but less than 2 dp */
	if(quantity && quantity.substr(quantity.length-2,2).indexOf(".") != -1){ quantity += '0'; };
	return quantity;
};

/**
*
* May have to revisit this function, if cost model becomes more complex.
*
* Takes a delegate node as argument and returns an array:
*
* (courseCost,numberOfNights)
*
* Also, this function takes into account any room-sharing and guests, etc.
* It does that by back-tracking down the XML tree to study all the delegates
* on the same course as the argument delegate.
*
* nonres			Non-residential
* standard_share_1	Standard single room, shared bathroom
* standard_priv_1	Standard single room, private bath/shower
* // standard_share_2	Standard twin room, shared bathroom
* standard_priv_2	Standard twin room, private bath/shower
* superior_1		Superior single room, private bath/shower
* superior_2		Superior twin room, private bath/shower
*
*
* NB: AccommodationCost includes the cost of any additional
* meals if you are nonres or if you have a (guest="guest")
* guest in your room who needs lunches.
*
* NB: Returns protection cost as a separate item.
*
*/
function _delegateCost(tmpDelegate,noCache){
	noCache = 0;
	_myDebug('_delegateCost for ' + _nodeData(tmpDelegate,'firstname'));
	// _myDebug('_delegateCost for ' + _mySerialize(tmpDelegate));

	if(! tmpDelegate) {
		_myDebug('Error: no delegate node supplied');
		return false;
	};

	var delegateNameTag = _nodeData(tmpDelegate,'firstname') +  ' ' + _nodeData(tmpDelegate,'surname');
	_clearCostsFor(delegateNameTag);

	if(! noCache && _DELEGATECOSTCACHE[tmpDelegate.getAttribute('id')]){
		_myDebug('cached costs for ' + tmpDelegate.getAttribute('id'));
		// return _DELEGATECOSTCACHE[tmpDelegate.getAttribute('id')];
	};

	if(! tmpDelegate.parentNode) {
		_myDebug('Error: delegate node has no parent');
		return false;
	};
	if(! tmpDelegate.parentNode.parentNode) {
		_myDebug('Error: delegate node has no ancestor course');
		return false;
	};
	var tmpCourse = tmpDelegate.parentNode.parentNode;
	var courseCode = tmpCourse.getAttribute('id');
	courseCode = courseCode.substr(0,courseCode.indexOf('_')).toUpperCase();

	var tmpAccommodation = tmpDelegate.getElementsByTagName('accommodation')[0];

	if(! tmpAccommodation){
		_myDebug('Error: delegate node has no accommodation node');
		return false;
	};

	/* work out how many days we need */
	var courseDuration = Math.floor((tmpCourse.getAttribute('end') - tmpCourse.getAttribute('start'))/(60*60*24));
	var extraDays = 0;
	if(tmpAccommodation.getAttribute('start') == 'true') { extraDays++; };
	if(tmpAccommodation.getAttribute('end') == 'true') { extraDays++; };

	/**
	* To acccommodate West Dean's seasonal changes in product price
	*/
	var season_letter = 's';

	// number between 1 and 12
	var tmp_month = 1 + _unixtimetodate(tmpCourse.getAttribute('start'),6);
	_myDebug('tmpAccommodation start tmp_month:' + tmp_month);
	if(tmp_month > 10 || tmp_month < 6){ season_letter = 'w'; };

	_myDebug('Course duration:' + courseDuration + ' days');
	_myDebug('\textra days:' + extraDays + ' days');
	var numberOfNights = courseDuration + extraDays;

	var tmpDelegateCost = parseFloat(tmpCourse.getAttribute('cost'));
	_myDebug('tmpDelegateCost:' + tmpDelegateCost);

	// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
	if(tmpCourse.getAttribute('basket') == 'basket'){
		_ITEMISEDCOSTS.push(new Array(delegateNameTag,'Course fee',tmpDelegateCost,tmpDelegateCost));
	};

	var numberOfGuests = 0;
	var myGuestName = '';
	if(tmpAccommodation.getAttribute('type') && tmpAccommodation.getAttribute('type').indexOf('_2') != -1){
		_myDebug('twin room..');
		/* twin room */
		if(tmpDelegate.getAttribute('guest') == 'guest'){
			_myDebug('with guest..');
			numberOfGuests = 1;
			myGuestName = _getGuestName(tmpDelegate);
			_clearCostsFor(myGuestName);
		} else {
			_myDebug('with other sharing student... so show costs for this student only');
			numberOfGuests = 0;
		};
	} else {
		_myDebug('single room..');
		numberOfGuests = 0;
	};
	_myDebug('numberOfGuests:' + numberOfGuests);

	_myDebug('tmpAccommodation.getAttribute(type):' + tmpAccommodation.getAttribute('type'));
	if(tmpAccommodation.getAttribute('type') && tmpAccommodation.getAttribute('type') != 'nonres'){
		/* For the student delegate: coursetime */
		var accommodationScenario = tmpAccommodation.getAttribute('type') + ':coursetime:' + season_letter;

		var tmpCostArr = _getProductCostByScenario(accommodationScenario);
		var tmpIncVat = courseDuration * parseFloat(tmpCostArr[0]);
		var tmpExVat = tmpIncVat;
		tmpDelegateCost += tmpIncVat;
		// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
		if(tmpCourse.getAttribute('basket') == 'basket'){
			_ITEMISEDCOSTS.push(new Array(delegateNameTag,'Accommodation during course',tmpIncVat,tmpExVat));
		};

		_myDebug('tmpDelegateCost:' + tmpDelegateCost);

		/* For the student delegate: noncoursetime */
		accommodationScenario = tmpAccommodation.getAttribute('type') + ':noncoursetime:' + season_letter;

		tmpCostArr = _getProductCostByScenario(accommodationScenario);
		tmpDelegateCost += extraDays * parseFloat(tmpCostArr[0]);
		tmpIncVat = extraDays * parseFloat(tmpCostArr[0]);
		tmpExVat = extraDays * parseFloat(tmpCostArr[1]);

		// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
		if(tmpCourse.getAttribute('basket') == 'basket'){
			_ITEMISEDCOSTS.push(new Array(delegateNameTag,'Accommodation for extra night(s)',tmpIncVat,tmpExVat));
		};

		_myDebug('tmpDelegateCost with student delegate accommodation:' + tmpDelegateCost);
	};
	var tmpStudentDelegateCost = tmpDelegateCost;
	_myDebug('tmpStudentDelegateCost: (after accommodation)' + tmpDelegateCost);

	if(numberOfGuests){

		/* For the guest delegate: coursetime */
		accommodationScenario = 'guest:coursetime:' + season_letter;
		var tmpCostArr = _getProductCostByScenario(accommodationScenario);
		tmpDelegateCost += courseDuration * parseFloat(tmpCostArr[0]);
		var tmpIncVat = courseDuration * parseFloat(tmpCostArr[0]);
		var tmpExVat = courseDuration * parseFloat(tmpCostArr[1]);

		// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
		if(tmpCourse.getAttribute('basket') == 'basket'){
			_ITEMISEDCOSTS.push(new Array(myGuestName,'Accommodation during course',tmpIncVat,tmpExVat));
		};
		_myDebug('tmpDelegateCost:' + tmpDelegateCost);

		/* For the guest delegate: noncoursetime */
		accommodationScenario = tmpAccommodation.getAttribute('type') + ':noncoursetime:' + season_letter;
		tmpCostArr = _getProductCostByScenario(accommodationScenario);
		tmpDelegateCost += extraDays * parseFloat(tmpCostArr[0]);
		tmpIncVat = extraDays * parseFloat(tmpCostArr[0]);
		tmpExVat = extraDays * parseFloat(tmpCostArr[1]);
		// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
		if(tmpCourse.getAttribute('basket') == 'basket'){
			_ITEMISEDCOSTS.push(new Array(myGuestName,'Accommodation for extra night(s)',tmpIncVat,tmpExVat));
		};
		_myDebug('tmpDelegateCost:' + tmpDelegateCost);

	};

	/* START: meals */
	var mealsCost = 0;
	var studentMealsCost = 0;

	/**
	* first, remove any spurious meals such as breakfasts or dinners for residents,
	* or lunches for non-residents
	*/
	// var dinnerLog = 'b:'+ _mySerialize(tmpDelegate.getElementsByTagName('meals')[0]);
	if(tmpAccommodation.getAttribute('type')) {
		if(tmpAccommodation.getAttribute('type') == 'nonres') {
			/* remove any lunches */
			var mealName = 'lunch';
			for (var k=0; k<tmpDelegate.getElementsByTagName(mealName).length;k++){
				var repNode = tmpDelegate.getElementsByTagName(mealName)[k];
				for (var l=0; l<repNode.getElementsByTagName('date').length;l++){
					var remNode = repNode.getElementsByTagName('date')[l];
					var remNodeString = remNode.firstChild.data;
					remNode.parentNode.removeChild(remNode);
					re = eval('/\\//g');
					remNodeString = remNodeString.replace(re,'_');
					remNodeString = 'meals_' + mealName + '_' + remNodeString;
					_setVal(remNodeString,false);
				};
			};

		} else {
			/* remove any breakfasts or dinners */
			var mealName = 'breakfast';
			for (var k=0; k<tmpDelegate.getElementsByTagName(mealName).length;k++){
				var repNode = tmpDelegate.getElementsByTagName(mealName)[k];
				for (var l=0; l<repNode.getElementsByTagName('date').length;l++){
					var remNode = repNode.getElementsByTagName('date')[l];
					var remNodeString = remNode.firstChild.data;
					remNode.parentNode.removeChild(remNode);
					re = eval('/\\//g');
					remNodeString = remNodeString.replace(re,'_');
					remNodeString = 'meals_' + mealName + '_' + remNodeString;
					_setVal(remNodeString,false);
				};
			};
			mealName = 'dinner';
			for (var k=0; k<tmpDelegate.getElementsByTagName(mealName).length;k++){
				var repNode = tmpDelegate.getElementsByTagName(mealName)[k];
				for (var l=0; l<repNode.getElementsByTagName('date').length;l++){
					var remNode = repNode.getElementsByTagName('date')[l];
					var remNodeString = remNode.firstChild.data;
					remNode.parentNode.removeChild(remNode);
					re = eval('/\\//g');
					remNodeString = remNodeString.replace(re,'_');
					remNodeString = 'meals_' + mealName + '_' + remNodeString;
					_setVal(remNodeString,false);
				};
			};
		};
	};

	/* remember, dinner on first night is free for nonres */
	var firstNightDate = _unixtimetodate(tmpCourse.getAttribute('start'),3);

	/**
	* breakfast and dinner - for (non-resident) student only
	* lunch - for BOTH student and guest NB!!!
	*/
	var mealTypes = new Array('lunch','breakfast','dinner');
	for (var t=0;t<mealTypes.length;t++){
		var mealtype = mealTypes[t];

		var focusRepast = tmpDelegate.getElementsByTagName(mealtype)[0];
		if(focusRepast){
			var mealCount = 0;
			var tmpIncVat = 0;
			var	tmpExVat = 0;
			// dinnerLog += '\n\n: found repast:'+ _mySerialize(focusRepast);
			var mealUnitCost = 0;
			if(focusRepast.getElementsByTagName('date').length){
				var tmpCostArr = _getProductCostByScenario(mealtype + ':' + season_letter);
				mealUnitCost = parseFloat(tmpCostArr[0]);
				if(! mealUnitCost){
					/* try without the season code */
					tmpCostArr = _getProductCostByScenario(mealtype);
					mealUnitCost = parseFloat(tmpCostArr[0]);
				};
				tmpIncVat = parseFloat(tmpCostArr[0])
				tmpExVat = parseFloat(tmpCostArr[1])
			};
			for (var m=0;m<focusRepast.getElementsByTagName('date').length;m++){
				var mealDate = focusRepast.getElementsByTagName('date')[m].firstChild.data || '';
				mealDate = mealDate.replace(/\//g,'_');
				// dinnerLog += '\n\n----\n\n\t- mealtype:'+ mealtype;
				if((mealtype == 'dinner' && mealDate != firstNightDate) || (mealtype != 'dinner')){
					mealsCost += mealUnitCost;
					mealCount++;
					// dinnerLog += '\n\n----\n\n\t-mealtype/cost:' + mealtype + '/' + mealsCost;
					studentMealsCost += mealUnitCost;
					/* NB: lunch is for both student and guest, so add an extra lunch */
					if(mealtype == 'lunch'){
						// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
						if(tmpCourse.getAttribute('basket') == 'basket'){
							_shiftPush(_ITEMISEDCOSTS,new Array(delegateNameTag, _capText(mealtype) ,mealCount * tmpIncVat,mealCount * tmpExVat));
							if(numberOfGuests){
								_shiftPush(_ITEMISEDCOSTS,new Array(myGuestName, _capText(mealtype) ,mealCount * tmpIncVat,mealCount * tmpExVat));
								mealsCost += mealUnitCost;
								mealCount++;
							};
						};
					} else {
							// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
							if(tmpCourse.getAttribute('basket') == 'basket'){
								_shiftPush(_ITEMISEDCOSTS,new Array(delegateNameTag, _capText(mealtype),mealCount * tmpIncVat,mealCount * tmpExVat));
							};
					};
				};
				_myDebug('mealsCost increment...');
			};
			_myDebug('mealsCost:' + mealsCost);
		};
	};
	// dinnerLog += '\n\n----\n\na:'+ _mySerialize(tmpDelegate.getElementsByTagName('meals')[0]);
	// alert(dinnerLog);
	/* END: meals */

	tmpDelegateCost += mealsCost;
	tmpStudentDelegateCost += studentMealsCost;
	_myDebug('tmpStudentDelegateCost: (after meals)' + tmpStudentDelegateCost);

	/* first night dinner discount, if accommodation has been bought */
	var dinnerDiscountCount = 0;

	if(tmpAccommodation.getAttribute('type') != 'nonres'){
		// _myDebug('accommodation type other than nonres, so get dinner discount:' + _mySerialize(tmpAccommodation));
		// dinnerDiscountCount = _getDinnerDiscount(courseCode,tmpCourse.getAttribute('start'),numberOfNights,season_letter);
		dinnerDiscountCount = _getDinnerDiscount(courseCode,tmpCourse.getAttribute('start'),courseDuration,season_letter);
	} else {
		_myDebug('accommodation type is:' + tmpAccommodation.getAttribute('type'));
	};
	var dinnerDiscount = dinnerDiscountCount * parseFloat(_getProductCostByScenario('dinnerdiscount:' + season_letter)[0]);
	if(dinnerDiscountCount){
		// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
		if(tmpCourse.getAttribute('basket') == 'basket'){
			_ITEMISEDCOSTS.push(new Array(delegateNameTag, 'Dinners already included in the course fee',dinnerDiscount,dinnerDiscount));
		};
	};
	tmpDelegateCost += dinnerDiscount;
	tmpStudentDelegateCost += dinnerDiscount;
	_myDebug('tmpStudentDelegateCost: (after dinnerDiscount)' + tmpDelegateCost);

	/* cancellation protection */

	/* for the student delegate */
	var cancellationProtection = _protectionCost(tmpStudentDelegateCost,season_letter);
	_myDebug('cancellationProtection:' + cancellationProtection);
	if(tmpDelegate.getAttribute('protection') == 'true'){
		// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
		if(tmpCourse.getAttribute('basket') == 'basket'){
			_ITEMISEDCOSTS.push(new Array(delegateNameTag, 'Cancellation protection',cancellationProtection,cancellationProtection));
		};
	};

	var guestCancellationProtection = _protectionCost((parseFloat(tmpDelegateCost) - parseFloat(tmpStudentDelegateCost)),season_letter);
	_myDebug('guestCancellationProtection:' + guestCancellationProtection);
	if(tmpDelegate.getAttribute('guestprotection') == 'true'){
		// Only meddle with the _ITEMISEDCOSTS if we're looking at the basket course
		if(tmpCourse.getAttribute('basket') == 'basket'){
			_ITEMISEDCOSTS.push(new Array(myGuestName, 'Cancellation protection',guestCancellationProtection,guestCancellationProtection));
		};
	};

	tmpDelegateCost = _myround(tmpDelegateCost);
	_myDebug('tmpDelegateCost:' + tmpDelegateCost);

	var returnArray = new Array(tmpDelegateCost,numberOfNights,cancellationProtection,guestCancellationProtection);
	_DELEGATECOSTCACHE[tmpDelegate.getAttribute('id')] = returnArray;
	// Only show the _ITEMISEDCOSTS if we're looking at the basket course
	if(tmpCourse.getAttribute('basket') == 'basket'){
		_showItemised();
	};
	return returnArray;
};

function _shiftPush(someArray,someOtherArray){
	for (var k=0;k<someArray.length;k++){
		if (
			someArray[k][0] == someOtherArray[0] &&
			someArray[k][1] == someOtherArray[1]){
			someArray[k] = someOtherArray;
			return true;
		};
	};
	someArray.push(someOtherArray);
};

/**
*
* File the booked courses and proceed
*
*/
function fileBooking(){
	someResponse = _SESSIONXML.documentElement;

	// writesession();
	return true;
};


/**
* First-night-dinners discount
*/
function _getDinnerDiscount(tmp_course_id,tmp_course_start,tmp_course_core_nights,season_letter) {
	_myDebug("_getDinnerDiscount: id:" + tmp_course_id + " nights:" + tmp_course_core_nights);

	var discount_price = _getProductCostByScenario("dinnerdiscount:" + season_letter)[0];

	/**
	* IF course reference is one of SS, MMI, WDW, CGF, CSQ, CWF, MTC, BVMA, BC, PC (not BCBespoke or PCBespoke)
	* THEN all dinners DURING THE COURSE are included in cost
	* ELSIF course start day !=  course end day
	* THEN only the first night's dinner is included
	* ELSE no dinner included
	*/

	var courseref = tmp_course_id.toUpperCase();
	var test_string = "_SS_MMI_WDW_CGF_CSQ_CWF_MTC_BVMA_BC_PC_";
	var discount_count = 0;
	_myDebug("courseref:" + courseref);
	// if(test_string =~ /_${courseref}_/ && $courseref !~ /espoke/){
	_myDebug("courseref test 1:" + test_string.indexOf("_" + courseref + "_"));
	_myDebug("courseref test 2:" + courseref.indexOf("espoke"));

	if(test_string.indexOf("_" + courseref + "_") != -1 && courseref.indexOf("espoke") == -1){
		// all dinners during course are included in cost
		_myDebug("all dinners during course are included in cost");
		discount_count = tmp_course_core_nights;
	} else if (tmp_course_core_nights > 0){
		// only the first night's dinner is included
		_myDebug("only the first night's dinner is included");
		discount_count = 1;
	} else {
		// no dinner included
		_myDebug("no dinner included");
		discount_count = 0;
	};

	_myDebug("_getDinnerDiscount count:" + discount_count);
	return discount_count;
};


function loginForm(onFlag) {
	if(onFlag) {
		_hideOrShow('','','loginform','block');
	} else {
		_hideOrShow('','','loginform','none');
	};
};

/**
* Thanks to http://www.quirksmode.org/js/findpos.html
*/
function _findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft;
		curtop = obj.offsetTop;
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		};
	};
	return [curleft,curtop];
};

function old_capText(someText){
	someText = someText.substring(0,1).toUpperCase() + someText.substring(1).toLowerCase();
	return someText;
};
function _capText(someText){
	var myWords = someText.split(' ');
	for (var w=0;w<myWords.length;w++){
		myWords[w] = myWords[w].substring(0,1).toUpperCase() + myWords[w].substring(1).toLowerCase();
	};
	return myWords.join(' ');
};

function _showItemised() {

	var delegateNamesArray = new Array();
	for (var k=0;k<_ITEMISEDCOSTS.length;k++){
		if(_inArray(_ITEMISEDCOSTS[k][0],delegateNamesArray) == -1){
			delegateNamesArray.push(_ITEMISEDCOSTS[k][0]);
		};
	};

	/* We do everything twice here - once in HTML, once plain-text */
	var returnString = '';
	var txtReturnString = '';
	var exVatSum = 0;
	var vatSum = 0;
	for (var j=0;j<delegateNamesArray.length;j++){
		returnString	+= '<p><b>' + delegateNamesArray[j] + '</b><br />\n';
		txtReturnString += '\n'		+ delegateNamesArray[j] + '\n';
		for (var k=0;k<_ITEMISEDCOSTS.length;k++){
			if(_ITEMISEDCOSTS[k][0] == delegateNamesArray[j] && _ITEMISEDCOSTS[k][2]){
				vatSum += _ITEMISEDCOSTS[k][2];
				exVatSum += _ITEMISEDCOSTS[k][3];
				returnString += '<span style="float: left; width: 40%;">' + _ITEMISEDCOSTS[k][1] + '</span><span style="float: left; width: 40%;">&#163;' + _2dp(_myround(_ITEMISEDCOSTS[k][2])) + ' </span><br clear="all" />\n';
				txtReturnString += _ITEMISEDCOSTS[k][1] + ' GBP ' + _2dp(_myround(_ITEMISEDCOSTS[k][2])) + '\n';
			};
		};
		returnString += '</p>\n';
		txtReturnString += '\n';
	};
	var vatMemo = '';
	if(vatSum != exVatSum){
		vatMemo += '<br />';
		vatMemo += _VATTEXT.replace('_VATAMOUNT_',_2dp(_myround(vatSum - exVatSum)));
	};
	returnString += '<p>\n';
	returnString += '<span style="float: left; width: 40%;"> Total:</span><span style="float: left; width: 40%;">&#163;' + _2dp(_myround(vatSum)) + '</span><br clear="all" />\n';
	returnString += vatMemo;
	returnString += '</p>\n';

	_dropins('','itemised_summary',returnString);

	txtReturnString += '\n';
	txtReturnString += 'Total:\t\tGBP ' + _2dp(_myround(vatSum)) + '\n';
	txtReturnString += vatMemo.replace('£','GBP ').replace('<br />','\n\n');
	txtReturnString += '\n';

	var tmp = _SESSIONXML.createCDATASection(txtReturnString);
	_replaceNamedNode(_getBooker(),'summary',tmp);
	
	// return returnString;
};

function _clearCostsFor (someNameTag){
	var newArr = new Array();
	for (var k=0;k<_ITEMISEDCOSTS.length;k++){
		if(_ITEMISEDCOSTS[k][0] != someNameTag){
			newArr.push(_ITEMISEDCOSTS[k]);
		};
	};
	_ITEMISEDCOSTS = newArr;
};

function _uglyTellUser(someMessage){
	var sessionID = getCookie('sessionid');
	if(_UGLYSESSION == sessionID){
		_tellUser(someMessage);
	};
	return '';
};

function _3DAuth(someProtXText){
	_myDebug('_3DAuth');
	// var _ACSURL	= 'https://ukvpstest.protx.com/mpitools/accesscontroler?action=pareq';
	// var _PAREQ		= 'eJxVUU1vgkAQvfdXEK5N2F1ABTOu8aOJHmhINfG8gYnQCuiyVOqv7y5CtXt6b3bmzcwbmLfFyfpGWedVObOZQ+05f4F9JhHXO0waiRwirGtxRCtPZ7ZLmctGrh8E1PNd3wsDm0O8+MALh16GaxWHARmorpdJJkrFQSSX5fad+yEbTyZAegoFyu2aMxawMAw8en9A7mEoRYH8gLVaoyiBdBSSqimV/OGBOwYyEGjkiWdKnespIdfr1bnqqlRXOZU8Os0XEJMA5DFQ3BhUa8E2Tzmubp/VbrOLbvkyexO3wD/tV4fXRvnRDIjJgFQo5C6lAZ3QkcXolI6nvgeki4MozCScuf5Ib3cncDY9Fs8/zxHQHkssk2GVgQG256pEneEC+cOQYp3wWFaqtaJ4q/saDuSxx2pjbE6UMdQ43CEjlmuDGKVep2YIEJNL+uOR/soa/bv+LwwLspw=';
	// var _MD			= '201215248803424398';
	var _DDDINFO = new Array();
	_DDDINFO['_TERMURL'] = _TERMURL;
	_DDDINFO['_PAREQ'] = '';
	_DDDINFO['_MD'] = '';
	_DDDINFO['_ACSURL'] = '';
	var keysArray = 'PAReq|MD|ACSURL|TERMURL'.split("|");
	var protXArray = someProtXText.split("\n");
	for (var q=0;q<protXArray.length;q++){
		for (var k=0;k<keysArray.length;k++){
			var tmpK = keysArray[k] + '=';
			var tmpKUC = '_' + keysArray[k].toUpperCase();
			if(protXArray[q].match(tmpK)){
				_DDDINFO[tmpKUC] = protXArray[q].replace(tmpK,'');
			};
		};
	};
	for (var k=0;k<keysArray.length;k++){
		var tmpKUC = '_' + keysArray[k].toUpperCase();
		if(! _DDDINFO[tmpKUC]){
			_myDebug('Error: cannot find '+ tmpKUC +' for 3DAuth');
			_tellUser('Error: cannot find '+ tmpKUC +' for 3DAuth');
			return '';
		};
		// alert(_DDDINFO[tmpKUC]);
		_autoFormHTML = _autoFormHTML.replace(tmpKUC,_DDDINFO[tmpKUC]);
	};

	var threeDFormHTML = '<iframe id="dddframe" onload="checkddd();" style="width: 100%; height: 360px;"></iframe>';
	document.getElementById('message').innerHTML = threeDFormHTML;
	_hideOrShow('','','message','block');
	var threeDForm = document.getElementById('dddframe').contentDocument;
	if (threeDForm == undefined || threeDForm == null) {
		threeDForm = document.getElementById('dddframe').contentWindow.document;
	};
	threeDForm.open();
	threeDForm.writeln(_autoFormHTML);
	threeDForm.close();
	_myDebug('_3DAuth QUIT');
};
function _getFrameVals(someVarName){
	if (! someVarName) { 
		_myDebug('cannot find 3dpostback data for null variable');
		return '';
	};
	var threeDForm = document.getElementById('dddframe').contentDocument;
	if (threeDForm == undefined || threeDForm == null) {
		threeDForm = document.getElementById('dddframe').contentWindow.document;
	};
	if (threeDForm == undefined || threeDForm == null) { 
		_myDebug('cannot find 3dpostback data for: ' + someVarName);
		return '';
	};
	if(threeDForm.getElementById(someVarName)){
		return threeDForm.getElementById(someVarName).innerHTML;
	};
};

function checkddd(){
	try {
		if(_getFrameVals('westdean_MD')){
			// Note the case change for PaRes --> PARes. This is intentional.
			_myDebug('this looks like the postback request');
			_setVal('MD',_getFrameVals('westdean_MD'));
			_setVal('PARes',_getFrameVals('westdean_PaRes'));
			_tellUser('Please now wait while we check your card details....');
			var tmp = _SESSIONXML.createCDATASection('Authentication Complete');
			var messagePNode = _SESSIONXML.getElementsByTagName('page')[0];
			_replaceNamedNode(messagePNode,'message',tmp);
			_myDebug(_mySerialize(_SESSIONXML));
			// alert('now saveCard()');
			saveCard();
		};
	} catch(e) {
		/* Likely just wrong domain */
	};
};
//-->
