
/*********************************************************
*  FoodPerfected Main Scripts File                       *
*  All scripts are the copyright work of ElectricStorm   *
*  // PrintedExistence.com unless otherwise stated.      * 
/********************************************************/



//===========================================
//  Globals
//===========================================


//ALL possible content pages that can be pulled into the main index.php.
//nb, these are the actual page names.
var contentPages = new Array();
contentPages[0] = 'home';
contentPages[1] = 'quote';
contentPages[2] = 'about';
contentPages[3] = 'contact';
contentPages[4] = 'links';
contentPages[5] = 'caterbanquets';
contentPages[6] = 'catercorporate';
contentPages[7] = 'caterinhome';
contentPages[8] = 'catergallery';
contentPages[9] = 'eventgeneral';
contentPages[10] = 'eventweddings';
contentPages[11] = 'eventbabyshowers';
contentPages[12] = 'eventprivate';
contentPages[13] = 'eventbanquets';
contentPages[14] = 'eventpremiers';
contentPages[15] = 'eventconventions';
contentPages[16] = 'eventgallery';
contentPages[17] = 'cafegeneral';
contentPages[18] = 'cafemenus';
contentPages[19] = 'cafespecials';
contentPages[20] = 'cafelocation';
contentPages[21] = 'cafegallery';
contentPages[22] = 'testientertainment';
contentPages[23] = 'testievents';
contentPages[24] = 'testievents2';
contentPages[25] = 'testievents3';
contentPages[26] = 'testicommerce';
contentPages[27] = 'pressreleases';
contentPages[28] = 'cafegallery2';
contentPages[29] = 'catergallery2';
contentPages[30] = 'eventgallery2';

//content pages that use template 3 (the 1 single box).
var t3Pages = new Array();
t3Pages[0] = 'quote';
t3Pages[1] = 'contact';
t3Pages[2] = 'links';
t3Pages[3] = 'about';

//array of main pages that appear on the top level nav (actual page names).
//nb, this array is used by the nav arrow script.
var mainPages = new Array();
mainPages[0] = 'home';
mainPages[1] = 'caterbanquets';
mainPages[2] = 'eventgeneral';
mainPages[3] = 'cafegeneral';
mainPages[4] = 'catergallery2';
mainPages[5] = 'testientertainment';
mainPages[6] = 'quote';
mainPages[7] = 'about';
mainPages[8] = 'contact';
mainPages[9] = 'links';

//array of $mainpages that have subnavs, with their subnavs (actual page names).
//nb, this array is used to determine which main page to feed to the nav arrow script.
var subNavs = new Array();
subNavs['caterbanquets'] = new Array('caterbanquets', 'catercorporate', 'caterinhome', 'catergallery');
subNavs['eventgeneral'] = new Array('eventgeneral', 'eventweddings', 'eventbabyshowers', 'eventprivate', 'eventbanquets', 'eventpremiers', 'eventconventions', 'eventgallery');
subNavs['cafegeneral'] = new Array('cafegeneral', 'cafemenus', 'cafespecials', 'cafelocation', 'cafegallery');
subNavs['testientertainment'] = new Array('testientertainment', 'testievents', 'testievents2', 'testievents3', 'testicommerce', 'pressreleases');
subNavs['catergallery2'] = new Array('catergallery2', 'eventgallery2', 'cafegallery2');

//array of subnavs page names linked with their parent key in $subnavs array above.
var leftSubnavs = new Array();
leftSubnavs['caterbanquets'] = 'catering';
leftSubnavs['eventgeneral'] = 'events';
leftSubnavs['cafegeneral'] = 'cafe';
leftSubnavs['testientertainment'] = 'testimonials';
leftSubnavs['catergallery2'] = 'galleries';

//array of gallery pages with the gallery dir they relate to.
//nb, this array is used to set up the gallery scripts (also used on galleries.php scripts file).
var galleries = new Array();
galleries['catergallery'] = 'catering';
galleries['eventgallery'] = 'events';
galleries['cafegallery'] = 'cafe';
galleries['catergallery2'] = 'catering';
galleries['eventgallery2'] = 'events';
galleries['cafegallery2'] = 'cafe';

//array of homepage bucket ids and the full pages they relate to.
//nb, this array is used by the scripts file to determine which content to load in.
var homeBkts = new Array();
homeBkts['homebkt1'] = 'caterbanquets';
homeBkts['homebkt2'] = 'cafegeneral';
homeBkts['homebkt3'] = 'eventgeneral';
homeBkts['homebkt4'] = 'testientertainment';


//===========================================






//===========================================
//  OnLoad Stuff
//===========================================


window.onload = activate;


// on window load, initialize other functions: 
function activate() {
	blurLinks();	
	setupNavArrow(); //(setup Baz's nav arrow functions on menu_animation.js)
	goToCorrectPage();
	setInterval('goToCorrectPage()', 500); //(run this function repeatedly (every 1/2 second) to ensure it updates if user clicks back button)
	initialize(); //(initialize Google map on page load (in case of user enabling JS then refreshing))
}



// blurLinks function
// gets rid of the annoying dotted line that appears around clicked links.
function blurLinks() {
	
	var links = document.getElementsByTagName('A');
	
	for (var i = 0; i < links.length; i++) { 
		currentLink = links[i];
		currentLink.onfocus = function() { this.blur(); };
	}	
	
}



var prevHash; //(use this to check whether hash has changed each time we re-run goToCorrectPage)


// goToCorrectPage function
// loads in the correct ajax pane depending on hash in the url (if there is one).
function goToCorrectPage() {
		
	var theHash = window.location.hash;
	
	//if the hash has changed since the last time we ran this function...
	if (theHash != prevHash) {				
						
		//load in the appropriate ajax pane (will also update prevHash)
		var thePage = theHash.substr(1); //(cut off the #) 
		swapPage(thePage); 

	}

}


//===========================================






//===========================================
//  Ajaxy Stuff 
//===========================================


// define xmlHttp as global var 
// (this way we can use it to check whether a request is in progress)
var xmlHttp = null;


// ajaxCreate function 
// creates the HttpRequest object for the other ajax functions and passes it back.
// (receives the containerId for use in the onreadystatechange bit)
function ajaxCreate(containerId) {

	try {
		//Firefox, Opera 8.0+, Safari
		xmlHttp = new XMLHttpRequest();
	}
	catch (e) {
		
		try {
			//IE 6+
			xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e) {
			//(browser can't understand ajax):
			return false;
		}
	}

	//onreadystatechange property: stores function that will process the response from server.
	xmlHttp.onreadystatechange = function() {
	
		//readyState 4 means the request is complete.
		if (xmlHttp.readyState == 4) {

			//responseText holds the servers response.
			document.getElementById(containerId).innerHTML = xmlHttp.responseText;
			
			//set global var back to null when we're done with it (so we know whether it's ok to start another request):
			xmlHttp = null;
		}

	}
	
	return xmlHttp;

}



// ajaxFetch function 
// fetches a file in with ajax and places it in the given container.
function ajaxFetch(containerId, fetchPage) {

	//create the HttpRequest object using my seperate function:
	var xmlHttp = ajaxCreate(containerId);
	
	//if HttpRequest object created successfully send request:
	if (xmlHttp != null) {	
		//open takes 3 params: method, url, asyncronous (true/false).
		xmlHttp.open("GET", fetchPage, true);	
		xmlHttp.send(null);
	}
	
}



// ajaxPost function 
// submits the contents of a form to a processing page using ajax.
function ajaxPost(containerId, formId, processingPage) {

	//create the HttpRequest object using my seperate function:
	var xmlHttp = ajaxCreate(containerId);
	
	//if HttpRequest object created successfully...
	if (xmlHttp != null) {	

		//fetch the form & process the contents into a string seperated by &s using my processForm function:
		var theForm = document.getElementById(formId);
		var params = processForm(theForm);
		
		//open takes 3 params: method, url, asyncronous (true/false).
		xmlHttp.open("POST", processingPage, true);
		xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		xmlHttp.send(params);

	}

}



// processForm function 
// processes the form fields and returns a single & seperated string of name / value pairs.
function processForm(theForm) {

	var str = '';

	//loop through every field in the form:
	for (var i = 0; i < theForm.elements.length; i++) {	
		
		//if text field / textarea / hidden / radio / submit:
		if (theForm.elements[i].type == 'text' || theForm.elements[i].type == 'textarea' || theForm.elements[i].type == 'hidden' 
		|| theForm.elements[i].type == 'radio' || theForm.elements[i].type == 'submit') {	
			str += theForm.elements[i].name + '=' + escape(theForm.elements[i].value) + '&';
		}			
		//if select box:
		else if (theForm.elements[i].type == 'select-one') {
			str += theForm.elements[i].name + '=' + theForm.elements[i].options[theForm.elements[i].selectedIndex].value + '&';
		}				
		//if checkbox: 
		if (theForm.elements[i].type == 'checkbox') {	
			//just add it with an "on" if it is checked:
			if (theForm.elements[i].checked == true) {
				str += theForm.elements[i].name + '=on&';
			}
		}			
	
	}

	//add a final var (some processing pages need to distinguish between forms sent with php & with ajax:
	str += 'ajaxform=true';
	
	//need to encode any + signs in the string (otherwise they get replaced with spaces):
	str = str.replace(/\+/g,'%2B');		
	
	return str;

}


//===========================================






//===========================================
//  Page Swapping
//===========================================


// swapPage function
// 1. checks the given content page is valid and new.
// 2. sets the location hash so this page state can be bookmarked / gone back to.
// 3. moves the nav arrow to the correct place.
// 4. determines whether we neeed to change leftsubnav.
// 5. determines whether we need to change templates. 
// 6. fades stuff out then starts next functions as required.
function swapPage(toPage) {	
		
	//see whether given toPage is in the global contentPages array (i.e. is valid):
	if (searchArray(contentPages, toPage) == -1) { 
		//if it isn't, reset it to home:
		toPage = 'home';
	}	
	
	//if we're going to a new page...
	if ('#'+toPage != prevHash) {
		
		//define prevPage based on prevHash (for the leftnavs bit below):
		if (prevHash != undefined) { 
			var prevPage = prevHash.substr(1); //(only substr if prevHash exists!)
		}
		else {
			var prevPage = 'bblank'; //(arbitary string- there is no bblank.php- just need to set it to something that won't be valid) 
		}
		
		//set the hash so we can recognise this page state:
		window.location.hash = toPage;
		prevHash = '#' + toPage; //(setting prevHash here will prevent a double fade as goToCorrectPage rechecks)
	
		
		//move the nav arrow along to the correct top level link:		
		//if the given page is a main page, just go straight there:
		if (searchArray(mainPages, toPage) != -1) {
			moveNavArrow(toPage);
		}
		//if the given page is a subnav page, locate the correct main page:
		else {
			//loop through the subNavs array:
			for (var i in subNavs) {
				//search each subarray, and when page found, go to that key:
				if (searchArray(subNavs[i], toPage) != -1) {
					moveNavArrow(i);
					break;	
				}
			}
		}
	
	
		//now for the actual page swap...
		
		//determine what template our toPage requires:
		//(nb, have already determined that toPage is valid above)
		//pages that use template 3 (the 1 single box) are in t3Pages array: 
		if (searchArray(t3Pages, toPage) != -1) {
			var toTemplate = 3;
		}	
		//only home uses template 1:  
		else if (toPage != 'home') {
			var toTemplate = 2;
		}
		else {
			var toTemplate = 1;
		}		
		
		//determine what template we're currently using:
		//(nb, we have identifying divs at the bottom of each template so we can do this).
		if (document.getElementById('template3')) {
			var curTemplate = 3;
		}
		else if (document.getElementById('template2')) {
			var curTemplate = 2;
		}
		else {
			var curTemplate = 1;
		}
		
		
		//determine whether we need to change navs:
		//nb, IMPORTANT! must use 0 / 1 not bool, as bools don't pass properly!
		var fadeOutNav = 0; //(is there a current nav to fade out?)
		var persistNav = 0; //(is there a persistent nav?- don't fade out / in if keeping the same one)
		
		if (document.getElementById('template2')) { //(only t2 uses navs)

			persistNav = 1; //(will reset to 0 if we need to change)
			
			var curNav = 0;
			var toNav = 0;
	
			for (var i in subNavs) {
				//locate the current pages nav if it has one:
				if (searchArray(subNavs[i], prevPage) != -1) { //(prevPage set above)
					curNav = leftSubnavs[i];
				}
				//locate the to pages nav:
				if (searchArray(subNavs[i], toPage) != -1) {
					toNav = leftSubnavs[i];
				}
			}			
			
			//if we do need to change navs:
			if (curNav != toNav) {									
				persistNav = 0;
				if (curNav != 0) {
					fadeOutNav = 1;
				}
			}		
		
		}
		
		
		//do we need to change template? 
		//no:
		//(nb, t1 doesn't have content so ensure we go to template switch if on t1)
		if (curTemplate == toTemplate && toTemplate != 1) {
			
			//fade out the current center content:
			fadeOut('centercontent', 40); 
			
			//if there is a non-persistent a nav to fade out, do that too:
			if (fadeOutNav == 1) {
				fadeOut('leftsubnav', 40); 
			}
			
			//wait for the duration of the fade, then fetch in the new content 
			//vars = toPage, swapping template (1 = true/0 = false), persistent nav:
			setTimeout("fetchPageContent('"+toPage+"', 0, '"+persistNav+"')", 600);

		}
		//do we need to change template?
		//yes:
		else {
			
			//fade out the template, content and navs all together:
			fadeOut('contentswap', 40); 
			
			//wait for the duration of the fade, and then fetch in the new template:
			setTimeout("fetchTemplate('"+toPage+"', '"+toTemplate+"', '"+persistNav+"')", 600);

		}

	}

}



// fetchTemplate function
// 1. ensures user is at the top of the page.
// 2. ajax fetches in the new template.
// 3. proceeds to the next step.
function fetchTemplate(toPage, toTemplate, persistNav) {

	//ensure the user is brought to the top of the new page (they may have scrolled down):
	instantPageTop();
	
	//do the ajax fetch:
	ajaxFetch('contentswap', 'content/templates/template'+toTemplate+'.php');

	//proceed to part 2:
	fetchTemplate2(toPage, persistNav);

}



// fetchTemplate2 function
// 1. waits until the ajax content has been fetched.
// 2. moves on to the function to fetch page content (#centercontent).
function fetchTemplate2(toPage, persistNav) {

	//if ajax content isn't fetched yet, wait patiently...
	if (xmlHttp != null) {
		setTimeout('fetchTemplate2("'+toPage+'", "'+persistNav+'")', 50);
	}
	//when ready continue:
	else {
	
		//proceed to fetch page content (#centercontent):
		//vars = toPage, swapping template (1 = true/0 = false), persistent nav:
		fetchPageContent(toPage, 1, persistNav);

	}
	
}



// fetchPageContent function
// (triggered either directly or after fetchTemplate).
// 1. ensures user is at the top of the page.
// 2. ajax fetches in the page content for #centercontent (templates 2 & 3 only as 1 has no #centercontent).
// 3. proceeds to the next step.
function fetchPageContent(toPage, swapTemplate, persistNav) {

	//ensure the user is brought to the top of the new page (they may have scrolled down):
	instantPageTop();
	
	//(nb, t1 doesn't have content so don't try to fetch)
	if (!document.getElementById('template1')) { 
		//do the ajax fetch:
		ajaxFetch('centercontent', 'content/pages/'+toPage+'.php');	
	}	
	
	//proceed to part 2:
	fetchPageContent2(toPage, swapTemplate, persistNav);
	
}



// fetchPageContent2 function
// 1. waits until the ajax content has been fetched.
// 2. if we are on template 2 and there is no persistent navs flag, fetches the new leftsubnav.
// 3. moves onto the next step.
function fetchPageContent2(toPage, swapTemplate, persistNav) {

	//if ajax content isn't fetched yet, wait patiently...
	if (xmlHttp != null) {
		setTimeout('fetchPageContent2("'+toPage+'", "'+swapTemplate+'", "'+persistNav+'")', 50);
	}
	//when ready continue:
	else {
			
		//if we're on t2 and there isn't a persistent nav flag, go get the new navs:				
		if (document.getElementById('template2') && persistNav == 0) {

			for (var i in subNavs) {
				//locate the to pages nav:
				if (searchArray(subNavs[i], toPage) != -1) {
					//do the ajax fetch:
					ajaxFetch('leftsubnav', 'content/subnavs/'+leftSubnavs[i]+'.php');
				}
			}	
		}

		//and move on to the next step:
		fetchPageContent3(toPage, swapTemplate, persistNav);	

	}

}



// fetchPageContent3 function
// 1. waits until the ajax content has been fetched.
// 2. sets up the leftnav (if there is one)- makes correct link show as text. 
// 3. sets up the galleries if this is a gallery page.
// 4. initializes the google map if this is a page with a map on.
// 5. runs blurLinks again to blur all the links on the content pane.
// 6. fades in the template / content / leftnav depending on values passed.
function fetchPageContent3(toPage, swapTemplate, persistNav) {
		
	//if ajax content isn't fetched yet, wait patiently...
	if (xmlHttp != null) {
		setTimeout('fetchPageContent3("'+toPage+'", "'+swapTemplate+'", "'+persistNav+'")', 50);
	}
	//when ready continue:
	else {

		//all the content is now in place (still faded out) so do our final bits...
		
		//if there is a leftnav, set it up:
		if (document.getElementById('leftsubnav')) {
		
			//set up the subnav links correctly (make correct one unclickable):				
			var subnavLinks = document.getElementById('leftsubnav').getElementsByTagName('A');
			
			for (var i = 0; i < subnavLinks.length; i++) {
				//when we hit the link for the current page... 				
				if (subnavLinks[i].id.substr(4) == toPage) { 
					//change its class:
					subnavLinks[i].className = 'snl_on';
					
					//if its in a sub-subnav (e.g. testimonials > events) open that up:
					if (subnavLinks[i].parentNode.id.substr(0, 10) == 'snl2inner_') {
						openLeftSubnavL2(subnavLinks[i].parentNode.id.substr(10));
					}					
				}
				//make sure all other links are changed back to normal:
				else {
					subnavLinks[i].className = 'snl';
				}
			}
		}

		//set up the gallery scripts if this is a gallery:
		if (galleries[toPage] != undefined) {
			setupGal(galleries[toPage]);
		}
		
		//initialize the google map if we are on a map page (so far just cafe location):
		if (document.getElementById('map_canvas')) {
			initialize();
		}
		
		//blur links in the new content:
		blurLinks();	
		
		
		//now fade in depending on the value of swapTemplate...
		if (swapTemplate == 1) {				
			//set the main content pane to fully visible if there is one (will still be hidden as template is):
			if (document.getElementById('centercontent')) {
				document.getElementById('centercontent').style.filter = 'alpha(opacity=100)'; 
				document.getElementById('centercontent').style.opacity = 1;
				curOpacity['centercontent'] = 100; //(set curOpacity for fade functions)
				
				//remove style attrib (entirely, for IE7) so anti-ailising will be applied:
				document.getElementById('centercontent').removeAttribute('style');
			}	
			//set the leftsubnav to fully visible if there is one (will still be hidden as template is):
			if (document.getElementById('leftsubnav')) {
				document.getElementById('leftsubnav').style.filter = 'alpha(opacity=100)'; 
				document.getElementById('leftsubnav').style.opacity = 1;
				curOpacity['leftsubnav'] = 100; //(set curOpacity for fade functions)

				//remove style attrib (entirely, for IE7) so anti-ailising will be applied:
				document.getElementById('leftsubnav').removeAttribute('style');
			}
			
			//and fade in the template:
			fadeIn('contentswap', 40);
		}
		else {			
			//fade in the main content pane:
			fadeIn('centercontent', 40);
			
			//(fade in the leftsubnav only if there is one):
			if (document.getElementById('leftsubnav') && persistNav != 1) {
				fadeIn('leftsubnav', 40);		
			}
		}

	}

}



// instantPageTop function
// brings the user instantly to the top of the page.
function instantPageTop() {

	var distScrolled = window.pageYOffset;
	
	//(IE understands document.documentElement.scrollTop instead of window.pageYOffset):
	if (distScrolled == undefined) {
		distScrolled = document.documentElement.scrollTop;
	}
		
	window.scrollBy(0, 0 - distScrolled); 

}



// openLeftSubnavL2 function
// slides open the given subnav within the leftsubnav (e.g. testimonials > events).
function openLeftSubnavL2(theSubnav) {

	//get the to height by checking the height of the inner div:
	var toHeight = document.getElementById('snl2inner_'+theSubnav).offsetHeight;	
	//and the starting height of the container we'll be growing:
	var contHeight = document.getElementById('snl2_'+theSubnav).offsetHeight;
	 
	 //only grow the container if it is smaller than toHeight (avoid reopens).
	 if (contHeight < toHeight) {
		 slideOut('snl2_'+theSubnav, toHeight, 5, 20);
	}

}


//===========================================






//===========================================
//  General Functions (Misc Reusable Stuff)
//===========================================


// FADE IN / OUT:

var curOpacity = new Array(); //(store current opacity of each element in global (so in / out functions can both access))
var fadeTimeout = new Array(); //(stop fade in / out functions from ever overlapping each other on the same element)


// fadeIn function
// fades a layer in.
function fadeIn(itemID, fadeSpeed) {
	
	//stop the fadeOut function for this item (if it is still looping)
	clearTimeout(fadeTimeout[itemID]);
	
	//see've curOpacity is set for this element:
	if (curOpacity[itemID] == undefined) {
		//if not set the default start opacity:
		curOpacity[itemID] = 0;
	}
	
	var theItem = document.getElementById(itemID);
	theItem.style.filter = 'alpha(opacity='+ curOpacity[itemID] +')'; 
	theItem.style.opacity = curOpacity[itemID] / 100;
	
	//if still less than 1, go again:
	if (curOpacity[itemID] < 100) {
		curOpacity[itemID] += 10;
		if (curOpacity[itemID] > 100) { curOpacity[itemID] = 100; }
		fadeTimeout[itemID] = setTimeout('fadeIn("'+itemID+'", "'+fadeSpeed+'")', fadeSpeed);
	}
	else {
	
		//quick n dirty hack for our un-anti-ailized text in IE bug:
		if (itemID == 'contentswap' || itemID == 'centercontent' || itemID == 'leftsubnav') {
			theItem.removeAttribute('style');
		}
	}
	
}



// fadeOut function
// fades a layer out. 
function fadeOut(itemID, fadeSpeed) {
				
	//stop the fadeIn function for this item (if it is still looping)
	clearTimeout(fadeTimeout[itemID]);	
	
	//see've curOpacity is set for this element:
	if (curOpacity[itemID] == undefined) {
		//if not set the default end opacity:
		curOpacity[itemID] = 100;
	}
	
	var theItem = document.getElementById(itemID);	
	theItem.style.filter = 'alpha(opacity='+ curOpacity[itemID] +')'; 
	theItem.style.opacity = curOpacity[itemID] / 100; 
	
	//if still greater than 0, go again:
	if (curOpacity[itemID] > 0) {
		curOpacity[itemID] -= 10;
		if (curOpacity[itemID] < 0) { curOpacity[itemID] = 0; }		
		fadeTimeout[itemID] = setTimeout('fadeOut("'+itemID+'", "'+fadeSpeed+'")', fadeSpeed);
	}
			
}




//SLIDE IN / OUT:

// store timeouts for each individual sliding item in array (stops them interfering with each other)
// in global so can be accessed by both slideIn and slideOut functions (so they never overlap and get stuck!)
var slideTimeout = new Array(); 


// slideOut function
// slides open a pane to the given height. 
function slideOut(itemID, toHeight, jumpSize, jumpSpeed) {
	
	//stop the slideIn function for this item (if it is still looping)
	clearTimeout(slideTimeout[itemID]);

	
	//get current height:
	var currentHeight = document.getElementById(itemID).offsetHeight;
		
	//if not already big enough: 
	if (currentHeight < toHeight) {
		
		//+ jumpSize px:
		var newHeight = currentHeight + (jumpSize * 1); //(multiplying converts jumpSize to int (otherwise JS would just append it))
		//if we've jumped above the desired height, shrink back down: 
		if (newHeight > toHeight) { newHeight = toHeight; }
			
		//make the height adjustment:
		document.getElementById(itemID).style.height = newHeight + 'px';
		
		//if height still isn't enough, wait jumpSpeed ms then go again:
		if (newHeight < toHeight) {
			slideTimeout[itemID] = setTimeout("slideOut('"+itemID+"', '"+toHeight+"', '"+jumpSize+"', '"+jumpSpeed+"')", jumpSpeed);
		}
	}		

}



// slideIn function
// slides closed a pane to the given height.
function slideIn(itemID, toHeight, jumpSize, jumpSpeed) {
	
	//stop the slideOut function for this item (if it is still looping)
	clearTimeout(slideTimeout[itemID]);


	//get current height:
	var currentHeight = document.getElementById(itemID).offsetHeight;
	
	//if not already small enough: 
	if (currentHeight > toHeight) {
		
		//- jumpSize px:
		var newHeight = currentHeight - (jumpSize * 1); //(multiplying converts jumpSize to int (otherwise JS would just append it))
		//if we've jumped below the desired height, grow back up: 
		if (newHeight < toHeight) { newHeight = toHeight; }
			
		//make the height adjustment:
		document.getElementById(itemID).style.height = newHeight + 'px';
		
		//if height is still too great, wait jumpSpeed ms then go again:
		if (newHeight > toHeight) {
			slideTimeout[itemID] = setTimeout("slideIn('"+itemID+"', '"+toHeight+"', '"+jumpSize+"', '"+jumpSpeed+"')", jumpSpeed);
		}
	}

}




// searchArray function
// searches the given array for the given value and returns the items position or -1 if not found.
function searchArray(theArray, val) {
	
	for (var i = 0; i < theArray.length; i++) {
		if (theArray[i] == val) { return i; }
	}
	
	return -1;

}




// scrollToTop function
// scrolls up smoothly up to the top of the page.
function scrollToTop() {
	
	//get the distance the user has scrolled down the page:
	//(Nb, pageYOffset works for FF, Opera, Saf, Netscape and Chrome. IE sees as "undefined")
	var distScrolled = window.pageYOffset;
	
	//(IE understands document.documentElement.scrollTop):
	if (distScrolled == undefined) {
		distScrolled = document.documentElement.scrollTop;
	}
	
	//scroll up by 30px at a time:
	window.scrollBy(0, -30); 
    
	//if we're not at the top of the page yet, do it again:
	if (distScrolled > 0) {
		setTimeout('scrollToTop()', 10); 
	}

}


//===========================================






//===========================================
//  The Dropdown Menu
//===========================================


// showSubnav function
// shows the given subnav.
function showSubnav(theSubnavId) {
	
	var theSubnav = document.getElementById('subnav_'+theSubnavId);	
	theSubnav.style.display = 'block';
	
}



// hideSubnav function
// hides the given subnav.
function hideSubnav(theSubnavId) {
	
	var theSubnav = document.getElementById('subnav_'+theSubnavId);
	theSubnav.style.display = 'none';

}


//===========================================






//===========================================
//  Homepage Specific Functions
//===========================================


// homePicOver function
// swaps the given homepage image for its mouseover version.
function homePicOver(theImg) {
	
	if (theImg.src.search('_over') == -1) {
		theImg.src = theImg.src.replace(/.jpg/,'_over.jpg');
	}
	
}



// homePicOff function
// swaps the given homepage image back to its regular state.
function homePicOff(theImg) {

	theImg.src = theImg.src.replace(/_over.jpg/,'.jpg');

}




// bktHoverOn function
// gives bucket its creamy orange hover color.
// nb, so far used only for homepage, but will work on any rbox1.
// nb, don't forget to add the hover images preloader to any other page that uses it.
function bktHoverOn(bktId) {
	
	var theBkt = document.getElementById(bktId);
	
	//fix the side graphics (change td classes):
	var theTds = theBkt.getElementsByTagName('TD');
	
	for (var i = 0; i < theTds.length; i++) {
		if (theTds[i].className == 'rbox1top' || theTds[i].className == 'rbox1left' || 
			theTds[i].className == 'rbox1bot' || theTds[i].className == 'rbox1right') {	
			theTds[i].className = theTds[i].className + '_on';
		}			
	}
	
	//fix the corner graphics (change corner img srcs):
	var theImgs = theBkt.getElementsByTagName('IMG');
	
	for (var i = 0; i < theImgs.length; i++) {
		if (theImgs[i].src.search('/rbox1/') > -1) {
			theImgs[i].src = theImgs[i].src.replace(/rbox1/, 'rbox1_on');
		}
	}
	
	//fix the table background color (middle bit):
	theBkt.style.background = '#f3fdbd';
	
	//make it look clickable:
	theBkt.style.cursor = 'pointer';

}



// bktHoverOff function
// returns bucket to white with greeny grey borders state. 
// nb, so far used only for homepage, but will work on any rbox1. 
function bktHoverOff(bktId) {
	
	var theBkt = document.getElementById(bktId);
	
	//fix the side graphics (change td classes):
	var theTds = theBkt.getElementsByTagName('TD');
	
	for (var i = 0; i < theTds.length; i++) {
		if (theTds[i].className == 'rbox1top_on' || theTds[i].className == 'rbox1left_on' || 
			theTds[i].className == 'rbox1bot_on' || theTds[i].className == 'rbox1right_on') {	
			theTds[i].className = theTds[i].className.substr(0, theTds[i].className.length -3);
		}			
	}
	
	//fix the corner graphics (change corner img srcs):
	var theImgs = theBkt.getElementsByTagName('IMG');
	
	for (var i = 0; i < theImgs.length; i++) {
		if (theImgs[i].src.search('/rbox1_on/') > -1) {
			theImgs[i].src = theImgs[i].src.replace(/rbox1_on/, 'rbox1');
		}
	}
	
	//fix the table background color (middle bit):
	theBkt.style.background = '#fff';

	//make it stop looking clickable:
	theBkt.style.cursor = 'default';

}




// expandHomeBkt function
// 1. sets the expand direction for the given homepage bucket and sets off slideOutHomeBkt for it. 
// 2. removes onclick / mouseover etc actions for ALL and sets them back to white.
// 3. fades out the other buckets.
// 4. hides ALL the more arrows.
// 5. fades out the righthand images.
function expandHomeBkt(bktId) {
	
	//deal with the given bucket:
	var theBkt = document.getElementById(bktId);
	
	//abs. position so it slides over the top of the other buckets:
	theBkt.style.position = 'absolute';
	
	//set the expand direction depending on which bucket it is:
	if (bktId == 'homebkt1' || bktId == 'homebkt3') { hDirection = 'left'; }
	else { hDirection = 'right'; }
	
	if (bktId == 'homebkt1' || bktId == 'homebkt2') { vDirection = 'down'; }
	else { vDirection = 'up'; }
	
	//and set off the slideOutHomeBkt function:
	slideOutHomeBkt(bktId, hDirection, vDirection, 20);


	//now loop through ALL the homepage buckets (inc given), and make necessary changes:
	var buckets = new Array('homebkt1', 'homebkt2', 'homebkt3', 'homebkt4');
	
	for (var i = 0; i < buckets.length; i++) {	
	
		curBkt = document.getElementById(buckets[i]);
		
		//remove onclick / mouseover / out actions for ALL so they can't go off again, and set back to white:
		curBkt.onclick = ''; 
		curBkt.onmouseover = '';
		curBkt.onmouseout = '';
		bktHoverOff(buckets[i]);
				
		//fade out all buckets EXCEPT given one:
		if (buckets[i] != bktId) {
			fadeOut(buckets[i], 40);
		}
		
		//finally, hide ALL the more arrows 
		//(nb, IE7 fails to fade out abs. positioned more arrs on faded buckets, + we need to get expanded buckets one too).
		var thisBktImgs = curBkt.getElementsByTagName('IMG');
		
		for (var j = 0; j < thisBktImgs.length; j++) {
			if (thisBktImgs[j].className == 'homebktmorearr') {
				thisBktImgs[j].style.display = 'none';
			}
		}
	}
	
	
	//fade out the righthand images:
	fadeOut('homepic1', 40);
	fadeOut('homepic2', 40);

}



// slideOutHomeBkt function
// slides out the given homepage bucket to its full size.
// (called by expandHomeBkt()).
// resets opacity of other homepage elements in curOpacity global, and loads in the new page at the end.
function slideOutHomeBkt(bktId, hDirection, vDirection, jumpSpeed) {
	
	
	//static vars
	//(nb, could be globals if necessary, but only used by this function so far)
	var startHBktWidth = 310; //(nb, if changing start width and height, remember to change on stylesheet too)
	var startHBktHeight = 170; 
	var fullHBktWidth = 850; //(nb, if changing this, don't forget to change mainbkt width and height on stylesheet)
	var fullHBktHeight = 390; //(nb, use the center td for height, not the table, as we need to reliably expand content area)	
	var bktWidthJumpSize = 15;
	var bktHeightJumpSize = 6; //(expand slower, so that the width and height max out together)
	var hBktRightSpace = 200; //(the space taken up by the righthand images (need to fill with bucket when expanding))


	var theBkt = document.getElementById(bktId);

	//we need the center td (to set the height) so go fetch:
	var theTds = theBkt.getElementsByTagName('TD');
	
	for (var i = 0; i < theTds.length; i++) {
		if (theTds[i].className == 'homebktctrtd') {
			var theCtrTd = theTds[i];
		}
	}

	//get current width & height:
	var curWidth = theBkt.offsetWidth;
	var curHeight = theCtrTd.offsetHeight;

	//see've we need to expand the width any further:
	if (curWidth < fullHBktWidth) {

		var newWidth = curWidth + bktWidthJumpSize;
		//if we've jumped above the desired width, shrink back down: 
		if (newWidth > fullHBktWidth) { newWidth = fullHBktWidth; }
			
		//make the width adjustment:
		theBkt.style.width = newWidth + 'px';
		
		//now see whether we're going backwards:
		if (hDirection == 'right') {
			//(and set negative left margin if needed)
			
			//1. get current left margin:
			var curLeftMargin = theBkt.style.marginLeft.search('px') == -1 ? 0 : parseInt(theBkt.style.marginLeft.split("px")[0]);
			
			//2. we want to go slightly to the right (to cover the righthand images space)
			//so figure out a % of the righthand space to add back onto our negative left each time:
			var numLoops = Math.floor((fullHBktWidth - startHBktWidth) / bktWidthJumpSize);			
			var pieceOfRight = Math.floor(hBktRightSpace / numLoops);
			
			//3. for position accuracy, we need to ensure that our left margin hasn't over-extended (as jumps are quite large)
			var newMargin = curLeftMargin - bktWidthJumpSize + pieceOfRight;
			if (newMargin - hBktRightSpace - startHBktWidth < 1 - fullHBktWidth) {
				//if too large, shrink to the max:
				newMargin = 1 - fullHBktWidth + hBktRightSpace + startHBktWidth;
			}			
			
			//4. make the margin adjustment:
			theBkt.style.marginLeft = newMargin + 'px';
		}		
	}
	
	//see've we need to expand the height any further:
	if (curHeight < fullHBktHeight) {

		var newHeight = curHeight + bktHeightJumpSize; 
		//if we've jumped above the desired height, shrink back down: 
		if (newHeight > fullHBktHeight) { newHeight = fullHBktHeight; }
			
		//make the height adjustment:
		theCtrTd.style.height = newHeight + 'px';

		//now see whether we're expanding upwards:
		if (vDirection == 'up') {
			//(and set negative top margin if needed)
			theBkt.style.marginTop = startHBktHeight - newHeight + 'px'; 
		}		
	}
	
	//if either width or height still aren't big enough, wait jumpSpeed ms then go again.
	if (newWidth < fullHBktWidth || newHeight < fullHBktHeight) {
		setTimeout("slideOutHomeBkt('"+bktId+"', '"+hDirection+"', '"+vDirection+"', '"+jumpSpeed+"')", jumpSpeed);
	}	
	//otherwise we're on the final loop, so...
	else {
		//go ahead & fetch in the right content in the normal way:
		swapPage(homeBkts[bktId])	
		
		//bring the homepage items back up to full opacity for the next time we see the homepage:
		curOpacity['homebkt1'] = 1;
		curOpacity['homebkt2'] = 1;
		curOpacity['homebkt3'] = 1;
		curOpacity['homebkt4'] = 1;
		curOpacity['homepic1'] = 1;
		curOpacity['homepic2'] = 1;	
	}

}


//===========================================






//===========================================
//  Catering Pages Functions
//===========================================


// openFoodMenu function
// 1. snaps closed all other menus on the page (to avoid triggering IE can't-fade-large-elements bug)
// 2. checks whether the given menu is open or closed and does the opposite with a slide.
function openFoodMenu(menuID) {

	//when opening one menu, we want to close all others on the page, so make sure we have the structure:
	if (document.getElementById('samplemenuscont')) {
		
		var theCont = document.getElementById('samplemenuscont');
		var allDivs = theCont.getElementsByTagName('DIV');
		
		//loop through all the divs within the #samplemenucont container:		
		for (var i = 0; i < allDivs.length; i++) {
			//if it's a sample menu:
			if (allDivs[i].className == 'samplemenu') {
				//if it's not the given menu...	
				if (allDivs[i].id != menuID) {
					//if it's open, snap it closed (no slide):
					if (allDivs[i].offsetHeight > 0) {
						allDivs[i].style.height = '0px';
					}
				}
			}
		} 
		
				
		//now see whether the given menu is open:
		if (document.getElementById(menuID).offsetHeight > 0) {
			//yes- slide it closed:
			slideIn(menuID, 0, 12, 10);
		}
		else {
			//no, slide it open to the height of the inner div:
			var innerDivs = document.getElementById(menuID).getElementsByTagName('DIV');
			var toMenuHeight = 0;
			for (var j = 0; j < innerDivs.length; j++) {
				if (innerDivs[j].className == 'samplemenuinner') {
					toMenuHeight = innerDivs[j].offsetHeight;
					break;
				}
			}

			slideOut(menuID, toMenuHeight, 12, 10);
		}
	
	}

}


//===========================================









