	function Variant(sName, sSwatchPath, sProductID, bReadOnly, sAddToBasketImage, sAddToBasketAnchor, sQtyControl, iLineItemNo) {
		this.Name = sName;
		this.Options = new Array();
		this.VariantCode = 0;
		this.SwatchPath = sSwatchPath;
		this.ProductID = sProductID;
		this.ReadOnly = bReadOnly;
		this.SelectedValues = new Array();
		this.AddToBasketImage = sAddToBasketImage;
		this.AddToBasketAnchor = sAddToBasketAnchor;
		this.QuantityControl = sQtyControl;
		this.LineItemNo = iLineItemNo;
	}

	function VariantFinal(sCode, sOptionName, sSwatchPath, bInStock, sStockMessage, dPrice) {
		this.VariantCode = sCode;
		this.Name = sOptionName;
		this.SwatchPath = sSwatchPath;
		this.InStock = bInStock;
		this.VariantFinal = true;
		this.Price = dPrice;
		this.StockMessage = (sStockMessage == null) ? '' : sStockMessage;
	}
	
	function VariantInfo(sType, sPrompt, sWarning, bCaseSensitive) {
		this.Type = sType; //what sort of variant is this - dropDown / swatch / letter
		this.Prompt = (sPrompt == null || sPrompt == '') ? ((sType == 'swatch') ? sDefaultSwatchPrompt : sDefaultDropDownPrompt) : sPrompt; //the variant prompt
		this.Warning = sWarning; //the warning to the user - ie. 'choose this' on submit
		this.CaseSensitive = bCaseSensitive; //whether or not letter variants should have the requested letters validated case-sensitively or not
		this.QuantityControl = null;
		this.QuantityControlType = null;
		this.OnlyValidateOnQuantityChosen = false;		
	}
	
	function ValidationOptions(iProductNum, sQuantityControl, sQuantityControlType, bValidateOnQuantityChosen) {
		this.ProductNum = iProductNum;
		this.QuantityControl = sQuantityControl;
		this.QuantityControlType = sQuantityControlType;
		this.OnlyValidateOnQuantityChosen = bValidateOnQuantityChosen;
		writeDebugInfo('Added validation options to Product ' + iProductNum + '. OnlyValidateOnQuantityChosen=' + bValidateOnQuantityChosen);
	}

	function addVariantOptions(variant, arOptions, bOptionsAreVariants, arVariantCodes, arInStock, arStockMessage, arSwatchPaths, arPrices) {
		
		if (arSwatchPaths == null)
			arSwatchPaths = new Array(arOptions.length);
		
		if (arInStock == null)
			arInStock = new Array(arOptions.length);
		
		if (arStockMessage == null)
			arStockMessage = new Array(arOptions.length);
			
		if (arVariantCodes == null)
			arVariantCodes = new Array(arOptions.length);
			
		if (arPrices == null)
			arPrices = new Array(arOptions.length);

		for (x=0; x<arOptions.length; x++) {
			if (bOptionsAreVariants) {
				variant.Options[variant.Options.length] = new Variant(arOptions[x], arSwatchPaths[x]);
			} else {
				variant.Options[variant.Options.length] = new VariantFinal(arVariantCodes[x], arOptions[x], arSwatchPaths[x], arInStock[x], arStockMessage[x], arPrices[x]);
			}
		}
	}

	function drawVariantControls() {
		writeDebugInfo('Starting drawVariantControls(). '+arVariantInfo.length+' products found');
			
		var sError = '';
		
		//loop through each variant (product)
		for (x=0; x<arVariantInfo.length; x++) {
			//loop through each variant in the product
			for (y=0; y<arVariantInfo[x].length; y++) {
				writeDebugInfo('&nbsp;&nbsp;Drawing product '+(x+1)+' ('+arVariantInfo[x][y].Type+') - '+arVariantInfo[x].length+' variants found');
				var sIdent = (x+1)+'_'+(y+1);

				//construct the control
				var sControl = '';
				var sOnChange = '';

				if (y == arVariantInfo[x].length-1)
					sOnChange = "populateVariantCode("+(x+1)+", "+(y+1)+");";
				else
					sOnChange = "populateVariantControl(this, 'ddVariant"+(x+1)+'_'+(y+2)+"', "+(y+2)+", false, "+(x+1)+");";

				switch (arVariantInfo[x][y].Type) {
					case 'dropDown':
						//get the span the control is going in
						var sControlElement = 'spnVariant'+sIdent+'DropDown';
						sControl = '<select name="ddVariant'+sIdent+'" id="ddVariant'+sIdent+'" onChange="'+sOnChange+'" class="VariantDropDown"></select>';
						writeDebugInfo('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Drawing a dropDown');
						writeDebugInfo('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Control: ' + sControl);
						break;
						
					case 'letter':
						var sControlElement = '';
						writeDebugInfo('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;letter variant');
						break;
				//	case 'swatch':
				//		get the span the control is going in
				//		var sControlElement = 'spnSwatch'+sIdent+'DropDown';
				//		sControl += '<select name="ddVariant'+sIdent+'" id="ddVariant'+sIdent+'" onChange="'+sOnChange+'" style="display: none;"></select>';
				//		
				//		populate the swatch title span
				//		var sSwatchPromptElement = 'spnSwatch'+sIdent+'Prompt';
				//		if (document.getElementById(sSwatchPromptElement))
				//			document.getElementById(sSwatchPromptElement).innerHTML = arVariantInfo[x][y].Prompt;
				//		else
				//			writeDebugInfo('Couldn\'t find the element: '+sSwatchPromptElement+'. Unable to write the swatch prompt to the page.', 'Error');
				//		
				//		writeDebugInfo('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Drawing a swatch');
				//		break;
					case 'matrixx':
					
 							sOnChange = "populateVariantMatrix(this, 'spnMatrix"+(x+1)+'_'+(y+2)+"', "+(y+2)+", false, "+(x+1)+", "+(y+1)+");";
							
							//get the span the control is going in
							var sControlElement = 'spnMatrix'+sIdent+'DropDown';
							
							sControl += '<select name="ddVariant'+sIdent+'" id="spnMatrix'+sIdent+'" onChange="'+sOnChange+'" style="display: none;"></select>';
							writeDebugInfo('control element: ' + sControl);
							//populate the swatch title span
							var sMatrixPromptElement = 'spnMatrix'+sIdent+'Prompt';
							if (document.getElementById(sMatrixPromptElement))
								document.getElementById(sMatrixPromptElement).innerHTML = arVariantInfo[x][y].Prompt;
							else
								writeDebugInfo('Couldn\'t find the element: '+sMatrixPromptElement+'. Unable to write the matrix prompt to the page.', 'Error');
						
						
						
						writeDebugInfo('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Drawing a matrix');
						break;
					case 'matrixy':
					
						break;

				}
				if (sControlElement != '' && sControl != '') {
					var controlElement = document.getElementById(sControlElement);
					//put the control in the element
					if (controlElement)
					{
						controlElement.innerHTML = sControl;
					}
					else
					{
						sError += '\n\t'+sControlElement;
					}
				}
			}			
		}
		
		if (sError != '') {
			writeDebugInfo('Couldn\'t find the spans for the following controls: '+sError);
			return false;
		} else {
			return true;
		}
	}


	function populateVariantCodeForMatrix(sVarID, iVariantNo, iChildNo, sInStock, sPrice)
	{
		var vtxt = document.getElementById(eval('sVariantBoxID' + eval('sProdID_'+eval(iVariantNo))));
		vtxt.value = sVarID;

		

		document.getElementById('spnPrice_'+iVariantNo).innerHTML = sPrice;
		document.getElementById('spnStockMessage'+iVariantNo).innerHTML = sInStock;
	
	}

	function populateVariantCode(iVariantNo, iChildNo, iLineItemNo) {
		writeDebugInfo('populateVariantCode: '+iVariantNo+', '+iChildNo+', '+iLineItemNo);

		if (iVariantNo == null) {
			//only relevant for single product pages
			var vtxt = document.getElementById(eval('sVariantBoxID' + eval('sProdID_'+'1')));
			vtxt.value = '';
		} else {	
			
			writeDebugInfo('VariantBoxID: ' + eval('sVariantBoxID' + eval('sProdID_'+eval(iVariantNo))));
			
			var vtxt = document.getElementById(eval('sVariantBoxID' + eval('sProdID_'+eval(iVariantNo))));
			//get the root variant
			var parentVariant = eval('variant'+iVariantNo);

			//get the address if we're adding multiple variants on the same page		
			if (bAddMultiple) {
				var sMultipleAddress = parentVariant.ProductID;
				//alert(parentVariant.LineItemNo);
				if (parentVariant.LineItemNo != null)
					sMultipleAddress += '_' + parentVariant.LineItemNo;
					
				//alert(sMultipleAddress);
			}
				
			//get the variant object that we need to address
			var variant = 'variant'+iVariantNo;
			for (x=1; x<=iChildNo; x++) {
				//get the selected index of the relevant dropDown
				var objDD = eval("document.getElementById('ddVariant"+iVariantNo+"_"+x+"')");
				variant += '.Options['+(objDD.selectedIndex-1)+']';
			}
	
			writeDebugInfo('Variant: '+ variant);
			
			//otherwise we have a path to a valid variant, so get it!
			if (eval(variant))
			{
			writeDebugInfo('&nbsp;&nbsp;variant object: ' + eval(variant).VariantCode);
			
			var objVariant = eval(variant);
			writeDebugInfo('&nbsp;&nbsp;getting variant object ('+((objVariant.VariantFinal) ? 'VariantFinal' : 'Variant')+'): <br>&nbsp&nbsp;&nbsp;&nbsp;'+variant);
			
			//set the variant code
			if (!objVariant.InStock && !bAllowAddingIfOutOfStock) {
				if (bAddMultiple)
					document.getElementById('txtVariantID_'+sMultipleAddress).value = '';
				else
					vtxt.value = '';
			} else {
				if (bAddMultiple)
					document.getElementById('txtVariantID_'+sMultipleAddress).value = objVariant.VariantCode;
				else
					vtxt.value = objVariant.VariantCode;
			}
			
			//show the price
			if (document.getElementById('spnPrice_'+iVariantNo) && objVariant.Price != null)
				document.getElementById('spnPrice_'+iVariantNo).innerHTML = objVariant.Price;
				//*********The following code should be on the French site to stop the variant prices from being shown wrong*******
				//if (document.getElementById('spnPrice_'+iVariantNo) && objVariant.Price != null)
		    //{	
				//reformat the price as EIBCS returns it incorrectly
			//	var rawprice=objVariant.Price.substring(0,objVariant.Price.length-2);
			//	var newprice;
			//	var index = rawprice.indexOf(',')
			//	if(index != -1)
			//	{					
			//		newprice=rawprice.substring(0,index-1)+','+rawprice.charAt(index-1) + rawprice.substring(index+1,rawprice.length-1);										
			//		newprice += objVariant.Price.substring(objVariant.Price.length-2,objVariant.Price.length)
			//	}				
			//	document.getElementById('spnPrice_'+iVariantNo).innerHTML = newprice;
			//}
			//END	French
			
			//if the variant is in stock and we have a addToBasketImage then show the appropriate basket image
			if (objVariant.InStock && objVariant.VariantFinal) {
				if (parentVariant.AddToBasketImage != null && bHideBasketOnOutOfStock) {
					if (document.getElementById(parentVariant.AddToBasketImage) != null)
						document.getElementById(parentVariant.AddToBasketImage).src = sAddToBasketImg;
					else
						writeDebugInfo('Couldn\'t find the control: '+parentVariant.AddToBasketImage+'. Unable to reset the basket image to the grey version.', 'Error');
				} else if (bHideQtyOnOutOfStock) {
					if (parentVariant.QuantityControl != null) {
						if (document.getElementById(parentVariant.QuantityControl))
							document.getElementById(parentVariant.QuantityControl).style.display = 'inline';
						else
							writeDebugInfo('Couldn\'t find the control: '+parentVariant.QuantityControl+'. Unable to hide the quantity control.', 'Error');
					}
				}
				
				if (parentVariant.AddToBasketAnchor != null) {
					if (document.getElementById(parentVariant.AddToBasketAnchor))
						document.getElementById(parentVariant.AddToBasketAnchor).style.display = 'inline';
					else
						writeDebugInfo('Couldn\'t find the control: '+parentVariant.AddToBasketAnchor+'. Unable to show the basket link.', 'Error');
				}
			} else if (!objVariant.InStock && objVariant.VariantFinal) {
				if (parentVariant.AddToBasketAnchor != null && bHideBasketOnOutOfStock) {
					writeDebugInfo('&nbsp;&nbsp;variant out of stock - hiding basket anchor<br>&nbsp;&nbsp;&nbsp;&nbsp;('+variant+')');
					if (document.getElementById(parentVariant.AddToBasketAnchor))
						document.getElementById(parentVariant.AddToBasketAnchor).style.display = 'none';
					else
						writeDebugInfo('Couldn\'t find the control: '+parentVariant.AddToBasketAnchor+'. Unable to hide the basket link.', 'Error');
				} else if (bHideQtyOnOutOfStock) {
					writeDebugInfo('&nbsp;&nbsp;variant out of stock - hiding product quantity control<br>&nbsp;&nbsp;&nbsp;&nbsp;('+variant+')');
					if (parentVariant.QuantityControl != null) {
						if (document.getElementById(parentVariant.QuantityControl))
							document.getElementById(parentVariant.QuantityControl).style.display = 'none';
						else
							writeDebugInfo('Couldn\'t find the control: '+parentVariant.QuantityControl+'. Unable to hide the quantity control.', 'Error');
					}
				}
			}
			
			//reset the warning message
			if (document.getElementById('spnVariant'+iVariantNo+'_'+iChildNo+'Warning'))
				document.getElementById('spnVariant'+iVariantNo+'_'+iChildNo+'Warning').style.display = 'none';
			else
				writeDebugInfo('Couldn\'t find the control: spnVariant'+iVariantNo+'_'+iChildNo+'Warning. Unable to set the warning message.', 'Error');
			
			//write out the stock message
			if (document.getElementById('spnStockMessage'+iVariantNo)) {
				document.getElementById('spnStockMessage'+iVariantNo).innerHTML = (objVariant.StockMessage) ? objVariant.StockMessage : '';
				if (sOutOfStockHighlightClass != null && sOutOfStockHighlightClass != '' && !objVariant.InStock)
					document.getElementById('spnStockMessage'+iVariantNo).className = sOutOfStockHighlightClass;
				else
					document.getElementById('spnStockMessage'+iVariantNo).className = '';
			} else 
				writeDebugInfo('Couldn\'t find the control: spnStockMessage'+iVariantNo+'. Unable to set the stock level message.', 'Error');				
		
			}
		}
	}

	function swatchSelect(ddParent, sChild, iChildNo, bPromptOnly, iVariantNo, iOptionNo, imgID, swatchName, spnSwatchName) {
		ddParent.selectedIndex = iOptionNo;
		doSwatchSwapping(iVariantNo, imgID, swatchName, iChildNo, spnSwatchName);
		populateVariantControl(ddParent, sChild, iChildNo, bPromptOnly, iVariantNo);
	}

	function swatchFinal(ddParent, iChildNo, iOptionNo, iVariantNo, imgID, swatchName, spnSwatchName) {
		ddParent.selectedIndex = iOptionNo;
		doSwatchSwapping(iVariantNo, imgID, swatchName, iChildNo, spnSwatchName);
		populateVariantCode(iVariantNo, iChildNo);
	}
	
	function swatchFinalMatrix(ddParent, iChildNo, iOptionNo, iVariantNo, imgID, swatchName, spnSwatchName, sVarID, sInStock, sPrice) {
		ddParent.selectedIndex = iOptionNo;
		doSwatchSwapping(iVariantNo, imgID, swatchName, iChildNo, spnSwatchName);
		populateVariantCodeForMatrix(sVarID, iVariantNo, iChildNo, sInStock, sPrice);
	}

	function doSwatchSwapping(iVariantNo, imgID, swatchName, iChildNo, spnSwatchName) {
		//if there's a saved image then reset it's class
		if (document.getElementById(eval('swatchVar'+iVariantNo+'SavedImg')))
			document.getElementById(eval('swatchVar'+iVariantNo+'SavedImg')).className = sClassSwatchNoHighlight;
			
		//set the class of the new selected image
		document.getElementById(imgID).className = sClassSwatchHighlight;

		//save the new selected image
		eval('swatchVar'+iVariantNo+'SavedImg = \''+imgID+'\'');

		//save the new selected name
		eval('swatchVar'+iVariantNo+'SavedName = \''+swatchName+'\'');

		//display the selected name - add a line break if the name is greater than the max length
		if (swatchName.length > iMaxSwatchNameLength)
			swatchName = '<br>'+swatchName;
		
		document.getElementById(spnSwatchName).innerHTML = swatchName;
	}

	function populateVariantControl(ddParent, sChild, iChildNo, bPromptOnly, iVariantNo) {
		writeDebugInfo('<br>populateVariantControl: '+ddParent+', '+sChild+', '+iChildNo+', '+bPromptOnly+', '+iVariantNo);

		//see if the parent variant is read-only
		var bReadOnly = false;
		if (eval('variant'+iVariantNo+'.ReadOnly'))
			bReadOnly = true;

		//reset the variant ID to null
		populateVariantCode(null);
		//get the child object
	    
	    ddChild = document.getElementById(sChild);
	    	
	
		//if we have a parent and it's reset to a prompt, then the child should be prompt only too
		if (ddParent != null && ddParent[ddParent.selectedIndex].value == -1) {
			bPromptOnly = true;
		} else if (ddParent != null) {
			//save the current child value so that we can reset it if possible after re-population
			ddSavedSelectedValue = ddChild[ddChild.selectedIndex].text;
			writeDebugInfo('&nbsp;&nbsp;got selected value and saved it: '+ddSavedSelectedValue);
		}

		//if the read-only flag is set, then do not do prompt only as we need to select the chosen value
		if (bReadOnly)
			bPromptOnly = false;

		writeDebugInfo('bPromptOnly: '+bPromptOnly+', bReadOnly: '+bReadOnly);

		//get the variant object that we need to address
		var variant = 'variant'+iVariantNo;
		if (ddParent != null) {
			for (var x=1; x<iChildNo; x++) {
				if (!bPromptOnly)
					variant += '.Options[(document.getElementById(\'ddVariant'+iVariantNo+'_'+x+'\').selectedIndex-1)]';
				else
					variant += '.Options[0]';
			}
		}

		//get the variant object and it's options
		writeDebugInfo('&nbsp;&nbsp;get the variant object:<br/>&nbsp;&nbsp;&nbsp;&nbsp;'+variant);
		var vVariant = eval(variant);
		var arVariantOptions = vVariant.Options;

		//clear the previous values from the child 
		clearOptions(ddChild);

		writeDebugInfo('&nbsp;&nbsp;cleared the options');	
		//display the prompt from the VariantInfo object
		if (arVariantInfo[(iVariantNo-1)][(iChildNo-1)].Prompt != '')
			ddChild[ddChild.length] = new Option(htmlReplace(arVariantInfo[(iVariantNo-1)][(iChildNo-1)].Prompt), -1);

		if (!bPromptOnly) {
			//try and get the swatch span for this set of options
			var sSwatchElement = 'spnSwatch'+iVariantNo+'_'+iChildNo;

			writeDebugInfo('&nbsp;&nbsp;Swatch element: ' + sSwatchElement);
			var bDoSwatch = false;
			if (document.getElementById(sSwatchElement)) {
				bDoSwatch = true;
				//clear any previous data
				document.getElementById(sSwatchElement).innerHTML = '';
			}
			
			writeDebugInfo('&nbsp;&nbsp;looping thru variant options...');	
			for (var x=0; x<arVariantOptions.length; x++) {
			
				ddChild[ddChild.length] = new Option(arVariantOptions[x].Name, arVariantOptions[x].VariantCode);

				if (bDoSwatch && arVariantOptions[x].SwatchPath != '') {
				
					//work out if this is the last variant or not
					if (arVariantOptions[x].Options != null)
						sHref = 'swatchSelect(document.getElementById(\'ddVariant'+iVariantNo+'_'+iChildNo+'\'), \'ddVariant'+iVariantNo+'_'+(iChildNo+1)+'\', '+(iChildNo+1)+', false, '+iVariantNo+', '+(x+1)+', \'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \''+arVariantOptions[x].Name+'\', \'spnSwatch'+iVariantNo+'_'+iChildNo+'Name\');';
					else
						sHref = 'swatchFinal(document.getElementById(\'ddVariant'+iVariantNo+'_'+iChildNo+'\'), '+iChildNo+', '+(x+1)+', '+iVariantNo+', \'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \''+arVariantOptions[x].Name+'\', \'spnSwatch'+iVariantNo+'_'+iChildNo+'Name\')';

					//set the innerhtml of the swatchElement span
 					try 
 					{
 						//this works in IE but not Firefox
 						var elementAnchor = document.createElement('<a href="javascript:'+sHref+'" onMouseOver="MM_ChangeSwatch(\'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \'spnSwatch'+iVariantNo+'_'+iChildNo+'Name\', \''+arVariantOptions[x].Name +'\')" onMouseOut="MM_RevertSwatch(\'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \'spnSwatch'+iVariantNo+'_'+iChildNo+'Name\', '+iVariantNo+')">')
 						var elementImage = document.createElement('<img src="'+arVariantOptions[x].SwatchPath+'" border="0" id="imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'" class="outlinewhite">');
 						var swatchElement = document.getElementById(sSwatchElement);
 						elementAnchor.appendChild(elementImage);
 						swatchElement.appendChild(elementAnchor);
 						
 					}
 					catch (e) 
 					{
 						//this will work in Firefox
 						var elementAnchor = document.createElement("a");
 						elementAnchor.setAttribute("href", "javascript:"+sHref); 
 						elementAnchor.setAttribute('onMouseOver', 'MM_ChangeSwatch(\'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \'spnSwatch'+iVariantNo+'_'+iChildNo+'Name\', \''+arVariantOptions[x].Name +'\')');
 						elementAnchor.setAttribute('onMouseOut', 'MM_RevertSwatch(\'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \'spnSwatch'+iVariantNo+'_'+iChildNo+'Name\', '+iVariantNo+')');
 						
 						var elementImage = document.createElement('<img src="'+arVariantOptions[x].SwatchPath+'" border="0" id="imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'" class="outlinewhite"></a>');
 						
 						elementAnchor.appendChild(elementImage);
 						
 						var swatchElement = document.getElementById(sSwatchElement);
 						swatchElement.appendChild(elementAnchor);
 					}
 					
				
				} else if (bDoSwatch && arVariantOptions[x].SwatchPath == '')
					writeDebugInfo('&nbsp;&nbsp;Missing swatch info - there is no path to the swatch image!', 'Error');
					
			}
				
			//if there is a saved selected value then try and reselect it
			var bRestoredChosenValue = false;
			if (ddSavedSelectedValue != '') {
				for (var x=0; x<ddChild.length; x++) {
					if (ddChild[x].text == ddSavedSelectedValue) {
						ddChild.selectedIndex = x;
						bRestoredChosenValue = true;
						break;
					}
				}
				
				//if we didn't find the saved selected value then we need to check if this is a swatch variant and reset the name if so
				if (!bRestoredChosenValue && bDoSwatch) {
					if (document.getElementById(sSwatchElement+'Name'))
						document.getElementById(sSwatchElement+'Name').innerHTML = '';
					else
						writeDebugInfo('&nbsp;&nbsp;Couldn\'t find swatch name element: '+sSwatchElement+'Name', 'Error');
						
					//reset the stock level indicator
					if (document.getElementById('spnStockMessage'+iVariantNo))
						document.getElementById('spnStockMessage'+iVariantNo).innerHTML = '';
					else
						writeDebugInfo('&nbsp;&nbsp;Couldn\'t find stock message element: spnStockMessage'+iVariantNo, 'Error');
						
					//reset the saved params
					eval("swatchVar"+iVariantNo+"SavedImg = ''");
					eval("swatchVar"+iVariantNo+"SavedName = ''");
				
				//if we didn't find the saved selected value then we need to reset stuff
				} else if (!bRestoredChosenValue) {	
					populateVariantCode(iVariantNo, iChildNo);
				
				//otherwise if we have restored a previously chosen value then we need to update the variant code
				} else if (bRestoredChosenValue && ddChild[ddChild.selectedIndex].value != -1) {
					populateVariantCode(iVariantNo, iChildNo);
				}
			}

			//disable the control if this is a read-only page
			if (bReadOnly)
				ddChild.disabled = true;
			else
				ddChild.disabled = false;
		} else {
			//alert('disable child');
			ddChild.disabled = true;
		}
		
		//if the prompt is not selected in the parent then reset the parent warning
		if (ddParent && ddParent[ddParent.selectedIndex].value != '-1') {
			if (document.getElementById('spnVariant'+iVariantNo+'_'+(iChildNo-1)+'Warning'))
				document.getElementById('spnVariant'+iVariantNo+'_'+(iChildNo-1)+'Warning').style.display = 'none';
			else
				writeDebugInfo('&nbsp;&nbsp;Couldn\'t find warning element: spnVariant'+iVariantNo+'_'+(iChildNo-1)+'Warning', 'Error');
		}

		//populate the hierarchy - first we try and get the dropDown beneath the current one to see if there is another level
		var sNewChild = 'document.getElementById(ddChild.name.substr(0, ddChild.name.indexOf("_'+iChildNo+'"))+("_'+(iChildNo+1)+'"))';
		var ddNewChild = eval(sNewChild);
		
		if (ddNewChild) {
			//if there is another level and the current dropDown is not on the prompt
			if (ddChild[ddChild.selectedIndex].value != -1) {			
				writeDebugInfo('&nbsp;&nbsp;recurse: '+ddChild.name+', '+ddNewChild.name+', '+(iChildNo+1)+', false, '+iVariantNo);
				populateVariantControl(ddChild, ddNewChild.name, (iChildNo+1), false, iVariantNo);
				
			//otherwise if there is another level and the current dropDown is on the prompt
			} else if (ddChild[ddChild.selectedIndex].value == -1) {
				writeDebugInfo('&nbsp;&nbsp;recurse: '+ddChild.name+', '+ddNewChild.name+', '+(iChildNo+1)+', true, '+iVariantNo);
				populateVariantControl(ddChild, ddNewChild.name, (iChildNo+1), true, iVariantNo);
			}
		}
	}	
	
	function htmlReplace(htmlCode) {
		return htmlCode.replace(/&eacute;/g,'\u00E9').replace(/&egrave;/g,'\u00E8').replace(/&ecirc;/g,'\u00EA');
	}
	
	function populateVariantMatrix(ddParent, sChild, iChildNo, bPromptOnly, iVariantNo, iPropX, iPropY) {
		writeDebugInfo('<br>populateVariantMatrix: '+ddParent+', '+sChild+', '+iChildNo+', '+bPromptOnly+', '+iVariantNo+', '+iPropX+', '+iPropY);

		//see if the parent variant is read-only
		var bReadOnly = false;
		if (eval('variant'+iVariantNo+'.ReadOnly'))
			bReadOnly = true;

		//reset the variant ID to null
		populateVariantCode(null);
		//get the child object
	   
	    ddChild = document.getElementById(sChild);
		
		//if we have a parent and it's reset to a prompt, then the child should be prompt only too
		if (ddParent != null && ddParent[ddParent.selectedIndex].value == -1) {
			bPromptOnly = true;
		} else if (ddParent != null) {
			//save the current child value so that we can reset it if possible after re-population
			ddSavedSelectedValue = ddChild[ddChild.selectedIndex].text;
			writeDebugInfo('&nbsp;&nbsp;got selected value and saved it: '+ddSavedSelectedValue);
		}

		//if the read-only flag is set, then do not do prompt only as we need to select the chosen value
		if (bReadOnly)
			bPromptOnly = false;

		writeDebugInfo('bPromptOnly: '+bPromptOnly+', bReadOnly: '+bReadOnly);

		//get the variant object that we need to address
		var variant = 'variant'+iVariantNo;
		if (ddParent != null) {
			for (var x=1; x<iChildNo; x++) {
				if (!bPromptOnly)
					variant += '.Options[(document.getElementById(\'ddVariant'+iVariantNo+'_'+x+'\').selectedIndex-1)]';
				else
					variant += '.Options[0]';
			}
		}
		

		//get the variant object and it's options
		writeDebugInfo('&nbsp;&nbsp;get the variant object:<br/>&nbsp;&nbsp;&nbsp;&nbsp;'+variant);

		var vVariant = eval(variant);
		var arVariantOptionsX = vVariant.Options;
		
		//clear the previous values from the child 
		clearOptions(ddChild);
		
		writeDebugInfo('&nbsp;&nbsp;cleared the options');
		
		//display the prompt from the VariantInfo object
		if (arVariantInfo[(iVariantNo-1)][(iChildNo-1)].Prompt != '')
			ddChild[ddChild.length] = new Option(arVariantInfo[(iVariantNo-1)][(iChildNo-1)].Prompt, -1);
			
		if (!bPromptOnly) {
			//try and get the swatch span for this set of options

			var sMatrixElement = 'spnMatrix'+iVariantNo+'_'+iChildNo;

			var bDoMatrix = false;
			if (document.getElementById(sMatrixElement)) {
				bDoMatrix = true;
				//clear any previous data
				document.getElementById(sMatrixElement).innerHTML = '';
			}
			
			// get the first list of X values
			var arVariantOptionsY = eval(arVariantOptionsX[0]).Options;
			
			var sContent = '<table>'
			var elementTable = document.createElement("table");
			var elementTRYHead = document.createElement("tr");
			
			var elementTDXYHead = document.createElement("td");
			elementTRYHead.appendChild(elementTDXYHead);
			var elementTDXYHead1 = document.createElement("td");
			elementTRYHead.appendChild(elementTDXYHead1);
		
			writeDebugInfo('&nbsp;&nbsp;written top corners');
			
			var arrHeaderNames = new Array();
			
			for (var y=0; y<arVariantOptionsY.length; y++) {
			
			
				var elementTDYHead = document.createElement("td");
				elementTDYHead.innerHTML += arVariantOptionsY[y].Name + "<br>";
				
				try 
				{
				
					var imgYHeadElement = document.createElement("img");
					imgYHeadElement.setAttribute("src",arVariantOptionsY[y].SwatchPath);
					imgYHeadElement.setAttribute("alt",arVariantOptionsY[y].Name);
					elementTDYHead.appendChild(imgYHeadElement);
					elementTRYHead.appendChild(elementTDYHead);
				}
				catch (e)
				{
					var imgYHeadElement = document.createElement('<img src=\'' + arVariantOptionsY[y].SwatchPath + '\' alt=\'' + arVariantOptionsY[y].Name + '\>');
					elementTDYHead.appendChild(imgYHeadElement);
					elementTRYHead.appendChild(elementTDYHead);
				}
				
				//write the header names to an array
				arrHeaderNames[y] = arVariantOptionsY[y].Name;
		
			}
			
			elementTable.appendChild(elementTRYHead);
			
			writeDebugInfo('&nbsp;&nbsp;written top row');
			
			for (var x=0; x<arVariantOptionsX.length; x++) {
			
				arVariantOptionsY = eval(arVariantOptionsX[x]).Options;
				var elementTR = document.createElement("tr");
				
				var elementTD1Head = document.createElement("td");
				elementTD1Head.innerHTML += arVariantOptionsX[x].Name;
				elementTR.appendChild(elementTD1Head);
		
				writeDebugInfo('&nbsp;&nbsp;written left header ' + x);
				try
				{
					var elementTDHead = document.createElement("td");
					var imgHeadElement = document.createElement("img");
					imgHeadElement.setAttribute("src",arVariantOptionsX[x].SwatchPath);
					imgHeadElement.setAttribute("alt",arVariantOptionsX[x].Name);
					elementTDHead.appendChild(imgHeadElement);
					elementTR.appendChild(elementTDHead);
				}
				catch (e)
				{
					var imgHeadElement = document.createElement("<img src='" + arVariantOptionsX[x].SwatchPath + "' alt='" + arVariantOptionsX[x].Name + "'>");
					elementTDHead.appendChild(imgHeadElement);
					elementTR.appendChild(elementTDHead);
				}
		
				var alreadyShifted = 0;

				
				for (var y=0; y<arVariantOptionsY.length; y++) {
		
		
					// find the correct header
					var headerCol;
					for (var i=0; i<arrHeaderNames.length; i++)
					{
						if (arVariantOptionsY[y].Name == arrHeaderNames[i])
						{
							headerCol = i;
						}
					}
					var counter = 0;
					for (var i=y;i<headerCol-alreadyShifted;i++)
					{
						var elementTD = document.createElement("td"); 								
 						elementTR.appendChild(elementTD); 
 						counter ++;
					}
					alreadyShifted +=counter;
					
					sHref = 'swatchFinalMatrix(document.getElementById(\'ddVariant'+iVariantNo+'_'+iChildNo+'\'), '+iChildNo+', '+(x+1)+', '+iVariantNo+', \'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \''+arVariantOptionsX[x].Name + ' ' + arVariantOptionsY[y].Name+'\', \'spnMatrix'+iVariantNo+'_'+iChildNo+'Name\',\'' + arVariantOptionsY[y].VariantCode + '\',\'' + arVariantOptionsY[y].StockMessage + '\',\'' + arVariantOptionsY[y].Price + '\')';

					try
					{

 															
 						var elementAnchor = document.createElement("a");
 						elementAnchor.setAttribute("href", "javascript:"+sHref); 
 						elementAnchor.setAttribute('onMouseOver', 'MM_ChangeSwatch(\'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \'spnMatrix'+iVariantNo+'_'+iChildNo+'Name\', \''+arVariantOptionsX[x].Name + ' ' + arVariantOptionsY[y].Name +'\')');
 						elementAnchor.setAttribute('onMouseOut', 'MM_RevertSwatch(\'imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x+'\', \'spnMatrix'+iVariantNo+'_'+iChildNo+'Name\', '+iVariantNo+')');
 						
 						
 						
 						var elementImage = document.createElement("img");
 						if (arVariantOptionsY[y].InStock == true)
 						{
 							elementImage.setAttribute("src","../images/swatches/instock.gif");
 							elementImage.setAttribute("alt",arVariantOptionsY[y].StockMessage);
 						}
 						else
 						{
 							elementImage.setAttribute("src","../images/swatches/nostock.gif");
 							elementImage.setAttribute("alt",arVariantOptionsY[y].StockMessage);
 						}
 						elementImage.setAttribute("border","0");
 						elementImage.setAttribute("id","imgSwatch"+iVariantNo+"_"+iChildNo+"_"+x); 
 						
 						elementAnchor.appendChild(elementImage);
 						
 					
 						
 						var elementTD = document.createElement("td"); 								
 						elementTD.appendChild(elementAnchor);	
 						elementTR.appendChild(elementTD); 	
 					}
 					catch (e)
 					{
 						var elementAnchor = document.createElement("a href='javascript:" + sHref + "' onMouseOver='MM_ChangeSwatch(\'imgSwatch"+iVariantNo + "_" + iChildNo + "_" + x + "\', \'spnMatrix" + iVariantNo + "_" + iChildNo + "Name\', \'" + arVariantOptionsX[x].Name + " " + arVariantOptionsY[y].Name + "\') onMouseOut=MM_RevertSwatch(\'imgSwatch" + iVariantNo + "_" + iChildNo + "_" + x + "\', \'spnMatrix" + iVariantNo + "_" + iChildNo + "Name\', " + iVariantNo + ")'");
 						
 						if (arVariantOptionsY[y].InStock == true)
 						{
 							var elementImage = document.createElement("img src='../images/swatches/instock.gif' alt='" + arVariantOptionsY[y].StockMessage + "' border=0 id='imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x)'");
 	
 						}
 						else
 						{
							var elementImage = document.createElement("img src='../images/swatches/nostock.gif' alt='" + arVariantOptionsY[y].StockMessage + "' border=0 id='imgSwatch'+iVariantNo+'_'+iChildNo+'_'+x)'"); 						
						}
						
 						elementAnchor.appendChild(elementImage);
 						var elementTD = document.createElement("td"); 								
 						elementTD.appendChild(elementAnchor);	
 						elementTR.appendChild(elementTD); 
 					}
 					
 					writeDebugInfo('&nbsp;&nbsp;written cell ' + x + ',' + y);

				}

				elementTable.appendChild(elementTR);
				writeDebugInfo('&nbsp;&nbsp;written row ' + x);
			}

		
			var matrixElement = document.getElementById(sMatrixElement);
			
			// this one is for IE
 			matrixElement.innerHTML = elementTable.outerHTML;
 			
 			// this one is for firefox
 			matrixElement.appendChild(elementTable);
 			
 	//		writeDebugInfo('&nbsp;&nbsp;written table to: '+ matrixElement.id + ':'+ matrixElement.innerHTML);
 			
			//if there is a saved selected value then try and reselect it
			var bRestoredChosenValue = false;
			if (ddSavedSelectedValue != '') {
				for (var x=0; x<ddChild.length; x++) {
					if (ddChild[x].text == ddSavedSelectedValue) {
						ddChild.selectedIndex = x;
						bRestoredChosenValue = true;
						break;
					}
				}
				
				//if we didn't find the saved selected value then we need to check if this is a swatch variant and reset the name if so
				if (!bRestoredChosenValue && bDoSwatch) {
					if (document.getElementById(sSwatchElement+'Name'))
						document.getElementById(sSwatchElement+'Name').innerHTML = '';
					else
						writeDebugInfo('&nbsp;&nbsp;Couldn\'t find swatch name element: '+sSwatchElement+'Name', 'Error');
						
					//reset the stock level indicator
					if (document.getElementById('spnStockMessage'+iVariantNo))
						document.getElementById('spnStockMessage'+iVariantNo).innerHTML = '';
					else
						writeDebugInfo('&nbsp;&nbsp;Couldn\'t find stock message element: spnStockMessage'+iVariantNo, 'Error');
						
					//reset the saved params
					eval("swatchVar"+iVariantNo+"SavedImg = ''");
					eval("swatchVar"+iVariantNo+"SavedName = ''");
				
				//if we didn't find the saved selected value then we need to reset stuff
				} else if (!bRestoredChosenValue) {	
					populateVariantCode(iVariantNo, iChildNo);
				
				//otherwise if we have restored a previously chosen value then we need to update the variant code
				} else if (bRestoredChosenValue && ddChild[ddChild.selectedIndex].value != -1) {
					populateVariantCode(iVariantNo, iChildNo);
				}
			}

			//disable the control if this is a read-only page
			if (bReadOnly)
				ddChild.disabled = true;
			else
				ddChild.disabled = false;
		} else {
			//alert('disable child');
			ddChild.disabled = true;
		}
		
		//if the prompt is not selected in the parent then reset the parent warning
		if (ddParent && ddParent[ddParent.selectedIndex].value != '-1') {
			if (document.getElementById('spnVariant'+iVariantNo+'_'+(iChildNo-1)+'Warning'))
				document.getElementById('spnVariant'+iVariantNo+'_'+(iChildNo-1)+'Warning').style.display = 'none';
			else
				writeDebugInfo('&nbsp;&nbsp;Couldn\'t find warning element: spnVariant'+iVariantNo+'_'+(iChildNo-1)+'Warning', 'Error');
		}

		//populate the hierarchy - first we try and get the dropDown beneath the current one to see if there is another level
		var sNewChild = 'document.getElementById(ddChild.name.substr(0, ddChild.name.indexOf("_'+iChildNo+'"))+("_'+(iChildNo+1)+'"))';
		var ddNewChild = eval(sNewChild);
		
		if (ddNewChild) {
			//if there is another level and the current dropDown is not on the prompt
			if (ddChild[ddChild.selectedIndex].value != -1) {			
				writeDebugInfo('&nbsp;&nbsp;recurse: '+ddChild.name+', '+ddNewChild.name+', '+(iChildNo+1)+', false, '+iVariantNo);
				populateVariantMatrix(ddChild, ddNewChild.name, (iChildNo+1), false, iVariantNo, iPropX, iPropY);
				
			//otherwise if there is another level and the current dropDown is on the prompt
			} else if (ddChild[ddChild.selectedIndex].value == -1) {
				writeDebugInfo('&nbsp;&nbsp;recurse: '+ddChild.name+', '+ddNewChild.name+', '+(iChildNo+1)+', true, '+iVariantNo);
				populateVariantMatrix(ddChild, ddNewChild.name, (iChildNo+1), true, iVariantNo, iPropX, iPropY);
			}
		}
	//	writeDebugInfo('&nbsp;&nbsp;still written table to: '+ matrixElement.id + ':'+ matrixElement.innerHTML);
	}	

	
	
	function writeDebugInfo(sInfo, sLevel) {
		if (sLevel == 'Error') {
			sInfo = '<strong style="color: red;">'+sInfo+'</strong>';
			
			if (!bIsLoad && bDebug)
				alert('There was an error in the variant javascript!\n\nPlease see the debugging info');
			else
				bLoadError = true;
		}
		
		sInfo = '<br>'+sInfo;
		
		if (bDebug)
			document.getElementById('spnVariantDebug').innerHTML += sInfo;
	}

	function clearOptions(OptionList) {
		for (x=OptionList.length; x>=0; x--) {
			OptionList[x] = null;
		}
	}
	
	function MM_ChangeSwatch(imageName, nameElement, swatchName)
	{
		document.getElementById(imageName).className = sClassSwatchHighlight;
		document.getElementById(nameElement).innerHTML = swatchName;
	}

	function MM_RevertSwatch(imageName, nameElement, iVariantNo)
	{
		var sSavedSwatchImg = eval('swatchVar'+iVariantNo+'SavedImg');
		if (imageName == sSavedSwatchImg)
			document.getElementById(imageName).className = sClassSwatchHighlight;
		else
			document.getElementById(imageName).className = sClassSwatchNoHighlight;
			
		document.getElementById(nameElement).innerHTML = eval('swatchVar'+iVariantNo+'SavedName');
	}
	
	function submitNoVariant(sProductID) {
		document.forms[0].elements['txtProductID'].value = sProductID;
		document.forms[0].elements['txtVariantCode'].value = '';
		document.forms[0].submit();
	}
	
	function submitAddedToWishList(sProductID) {
		document.forms[0].elements['txtProductID'].value = sProductID;
		document.forms[0].elements['txtVariantCode'].value = '';
		document.forms[0].elements['addedToWishList'].value = 'true';
		document.forms[0].submit();
	}
	
	

	function validateLetter(iProductNum, bAddMultiple, bFocus) {
		//get the parent
		if (bAddMultiple) 
			var parentVariant = eval('variant'+iProductNum);
		
		//get the available letters
		sLetters = eval('variant'+iProductNum+'.Options[0].Name');
		
		//get the requested letters
		var sRequested = formElements['txtChoice'+iProductNum+'_1'].value;
		
		//see if all requests should be validated as upper case for this product
		writeDebugInfo('validating letter variant ('+iProductNum+'). CaseSensitive = '+arVariantInfo[iProductNum-1][0].CaseSensitive);
		if (!arVariantInfo[iProductNum-1][0].CaseSensitive)
			sRequested = sRequested.toUpperCase();
		
		//if the user has entered no data then prompt...
		if (sRequested.length < 1) {
			document.getElementById('spnVariant'+iProductNum+'_1Warning').innerHTML = arVariantInfo[iProductNum-1][0].Warning;
			document.getElementById('spnVariant'+iProductNum+'_1Warning').style.display = 'inline';
			
			if (bFocus)
				formElements['txtChoice'+iProductNum+'_1'].focus();
				
			return false;
		} else {
			//make sure the warning is hidden
			document.getElementById('spnVariant'+iProductNum+'_1Warning').style.display = 'none';
			
			var sUnavail = '';
			for (var x=0; x<sRequested.length; x++) {
				if (sLetters.indexOf(sRequested.substr(x,1)) == -1 && sRequested.substr(x,1) != ' ') {
					if (sUnavail.indexOf(sRequested.substr(x,1)) < 0)
						sUnavail += ', '+sRequested.substr(x,1);
				}
			}
			
			if (sUnavail=='') {
				if (bAddMultiple)
					formElements['txtVariantID_'+parentVariant.ProductID].value = '#LETTER#'+sRequested;
				else
					formElements['txtVariantCode'].value = '#LETTER#'+sRequested;
					
				return true;
			} else {
				if (sUnavail.length > 3) {
					sTemp = sUnavail.substr(0, sUnavail.length-3);
					sUnavail = sTemp + ' and ' + sUnavail.substr(sUnavail.length-1);
				}
				
				//CONFIGURABLE - configure the error message below that users see when they try to order a letter that isn't available
				sAlert = 'Sorry, the ' + ((sUnavail.length>3) ? 'letters ' : 'letter ') + sUnavail.substr(2) + ' ' + ((sUnavail.length>3) ? 'are' : 'is') + ' not currently available.\n\nPlease amend your choice and try again.';
				document.getElementById('spnVariant'+iProductNum+'_1Warning').innerHTML = '<strong>' + sAlert + '</strong>';
				document.getElementById('spnVariant'+iProductNum+'_1Warning').style.display = 'inline';
				formElements['txtChoice'+iProductNum+'_1'].focus();
				return false;
			}			
		}	
	}
	function validate(iProductNum, sProductID) 
	{
		return validateVariant(iProductNum, sProductID, null, null, null);
	}
	
	function wlValidate(wishListValidate, iProductNum, sProductID, bDoSubmit, bAddMultiple, bFocus) {
		writeDebugInfo('called validate('+iProductNum+', '+sProductID+', '+bDoSubmit+', '+bAddMultiple+', '+bFocus+');');
		
		document.forms[0].elements['addedToWishList'].value = 'true';
		
		if (bDoSubmit == null)
			bDoSubmit = true;
			
		if (bFocus == null)
			bFocus = true;
			
		for (x=0; x<arVariantInfo[(iProductNum-1)].length; x++) {
			if (arVariantInfo[(iProductNum-1)][0].Type == 'letter') {
				//if this is a letter then we need to validate differently
				bDoSubmit = validateLetter(iProductNum, bAddMultiple, bFocus);
			} else {
				if (formElements['ddVariant'+iProductNum+'_'+(x+1)].selectedIndex == 0) {
					document.getElementById('spnVariant'+iProductNum+'_'+(x+1)+'Warning').style.display = 'inline';
					
					if (bFocus) {
						//if this is a swatch variant and we're trying to focus on the swatch item then go for the anchor instead
						var ddObj = formElements['ddVariant'+iProductNum+'_'+(x+1)];
						if (arVariantInfo[(iProductNum-1)][0].Type == 'swatch') {
							if (ddObj.style.display != 'none') {
								ddObj.focus();
							} else {
								//try and focus on the anchor instead
								if (document.getElementById('SwatchAnchor_'+iProductNum)) {
									var sLoc = location.href;
									if (sLoc.indexOf('#') > -1)
										sLoc = sLoc.substr(0, sLoc.indexOf('#'));
										
									location.href = sLoc + '#SwatchAnchor_'+iProductNum;
								}
							}
						} else {
							ddObj.focus();
						}
						
						bFocus = false;
					}
						
					bDoSubmit = false;
				} else {
					document.getElementById('spnVariant'+iProductNum+'_'+(x+1)+'Warning').style.display = 'none';
				}
			}
		}
		
		if (bDoSubmit && !bAddMultiple) {
			formElements['txtProductID'].value = sProductID;
			form.submit();
		} else if (bAddMultiple) {
			return bDoSubmit;
		}
	}
	
	function validateVariant(iProductNum, sProductID, bDoSubmit, bAddMultiple, bFocus) {
		writeDebugInfo('called validateVariant('+iProductNum+', '+sProductID+', '+bDoSubmit+', '+bAddMultiple+', '+bFocus+');');
		if (bDoSubmit == null)
			bDoSubmit = true;
			
		if (bFocus == null)
			bFocus = true;
			
		//check to see if we only need to validate if there is a quantity
		bValidate = true;
		if (arValidationOptions[(iProductNum-1)] != null) {
			if (arValidationOptions[(iProductNum-1)].OnlyValidateOnQuantityChosen) {
				if (arValidationOptions[(iProductNum-1)].QuantityControlType == "dropDown") {
					if (document.getElementById(arValidationOptions[(iProductNum-1)].QuantityControl).selectedIndex > 0)
						bValidate = true;
					else
						bValidate = false;
				} else if (arValidationOptions[(iProductNum-1)].QuantityControlType == "textBox") {
					if (!Number(document.getElementById(arValidationOptions[(iProductNum-1)].QuantityControl).value)) {
						alert('Please enter a number for the quantity');
						document.getElementById(arValidationOptions[(iProductNum-1)].QuantityControl).focus();
					} else {
						if (Number(document.getElementById(arValidationOptions[(iProductNum-1)].QuantityControl).value) > 0)
							bValidate = true;
						else
							bValidate = false;
					}
				}
			} else {
				bValidate = true;
			}
		} else {
			bValidate = true;
		}
		
		if (bValidate) {
			for (x=0; x<arVariantInfo[(iProductNum-1)].length; x++) {
				if (arVariantInfo[(iProductNum-1)][0].Type == 'letter') {
					//if this is a letter then we need to validate differently
					bDoSubmit = validateLetter(iProductNum, bAddMultiple, bFocus);
				} else {
					//alert(formElements['ddVariant'+iProductNum+'_'+(x+1)].selectedIndex);
					if (formElements['ddVariant'+iProductNum+'_'+(x+1)].selectedIndex == 0) {
						document.getElementById('spnVariant'+iProductNum+'_'+(x+1)+'Warning').style.display = 'inline';
						
						if (bFocus) {
							//if this is a swatch variant and we're trying to focus on the swatch item then go for the anchor instead
							var ddObj = document.getElementById('ddVariant'+iProductNum+'_'+(x+1));
							if (arVariantInfo[(iProductNum-1)][0].Type == 'swatch' || arVariantInfo[(iProductNum-1)][0].Type == 'matrixx') {
								if (ddObj.style.display != 'none') {
									ddObj.focus();
								} else {
									//try and focus on the anchor instead
									if (document.getElementById('SwatchAnchor_'+iProductNum)) {
										var sLoc = location.href;
										if (sLoc.indexOf('#') > -1)
											sLoc = sLoc.substr(0, sLoc.indexOf('#'));
											
										location.href = sLoc + '#SwatchAnchor_'+iProductNum;
									}
								}
							} else {
								ddObj.focus();
							}
							
							bFocus = false;
						}
							
						bDoSubmit = false;
					} else {
						document.getElementById('spnVariant'+iProductNum+'_'+(x+1)+'Warning').style.display = 'none';
					}
				}
			}
		}
		
		if (bDoSubmit && !bAddMultiple) {
			document.getElementById('txtProductID').value = sProductID;
			form.submit();
		} else if (bAddMultiple) {
			return bDoSubmit;
		}
	}
	
	//on a multiple page we need to loop through all products
	function validateMultiple() {
		if (validateMultipleReturn())
			form.submit();
	}
	
	function validateMultipleReturn() {
		var bDoSubmit = true;
		for (z=0; z<arVariantInfo.length; z++) {
			//alert(z);
			if (bDoSubmit)
				bDoSubmit = validateVariant((z+1), null, bDoSubmit, true, true);
			else
				//if we've already had a negative we don't want to overwrite it
				var bTemp = validateVariant((z+1), null, bDoSubmit, true, false);
				
			//alert('bDoSubmit: '+bDoSubmit);
		}
		return bDoSubmit;
		//return false;
	}	
	
	function preloadImages() {
		imgAddToBasket = new Image();
		imgAddToBasketGrey = new Image();
		
		if (sAddToBasketImg != '')
			imgAddToBasket.src = sAddToBasketImg;
			
		if (sAddToBasketGreyImg != '')
			imgAddToBasketGrey.src = sAddToBasketGreyImg;
	}
	
	function doPersonalisation(iVariantNo) {
		//get the variant
		var variant = eval('variant'+iVariantNo);
		for (var x=0; x<variant.SelectedValues.length; x++) {
			findSelectedValue(formElements['ddVariant'+iVariantNo+'_'+(x+1)], variant.SelectedValues[x]);

			//if there is a child, populate it
			if (x<=variant.SelectedValues.length-2)
				populateVariantControl(formElements['ddVariant'+iVariantNo+'_'+(x+1)], 'ddVariant'+iVariantNo+'_'+(x+2), x+2, false, iVariantNo);
			else if (x==variant.Options.length-1)
				populateVariantCode(iVariantNo, x+1);
		}
	}
	
	function findSelectedValue(ctrl, value) {
		for (y=0; y<ctrl.length; y++) {
			if (ctrl[y].text == value) {
				ctrl.selectedIndex = y;
				break;
			}
		}
	}

	/*** REQUIRED VARIABLES - DO NOT MOD ***/
	//saved dropDown selected value 
	var ddSavedSelectedValue = '';

	//array for the variant types
	var arVariantInfo = new Array();
	var arValidationOptions = new Array();
	
	var bLoadError = false;
	
	//variables to hold the add to basket images
	var imgAddToBasket;
	var imgAddToBasketGrey;

	/*** MOD THESE ON A PER-SITE BASIS ***/
	//classes for highlighting the swatch images 
	var sClassSwatchNoHighlight = 'outlinewhite';
	var sClassSwatchHighlight = 'outlinepink';
	
	//store the locations of the able/unable to add to basket images
	//note, if you do not want to use these, please make the variables empty strings
	var sAddToBasketImg = '';
	var sAddToBasketGreyImg = '';
	
	//default prompts
	var sDefaultSwatchPrompt = 'Please select a colour';
	var sDefaultDropDownPrompt = 'Please select an option';
	
	//the maximum length of the swatch name before it wraps - if the name is longer than this then it causes problems
	//with the name wrapping and causing the cursor to get 'stuck' and it fires mouseover and mouseout when the
	//image moves down as a result of the name wrapping. This is very specific to the design of the site - if the swatch images aren't
	//directly beneath the name then this won't be a problem, in which case just set it to 10000 or something daft ;)
	var iMaxSwatchNameLength = 10;
	
	//if you want the stock message to have a class applied to it when out of stock then put the class name here, otherwise use an empty string
	var sOutOfStockHighlightClass = 'highlight';
