function searchClass(jsonData){
	
	this.searchStockType = searchStockType;
	this.getAllColorCodes = getAllColorCodes;
	
	function searchStockType(color, size1, size2, availableMenus) {
		
		/*
		 * The data model can be one of three potential formats
		 * type1 is when the search string is of the form: size1|size2|color
		 * type2 is when the search string is of the form: size1|color|size2
		 * type3 is when the search string is of the form: color|size1|size2
		 * 
		 * The reason for this is, the JSP generates the JSON model in the same order
		 * it generates the menus on the page. So, although the color/style menu usually
		 * comes last on the page, if it happens to come before one or both of the
		 * size menus, we get in to the "type2" or "type3" situation. Again, "type1" is
		 * the normal (most prevalent) case.
		 * 
		 * First, we detect which "type" scenario we're in, then, the appropriate search
		 * string is generated. 
		 * 
		 */
		
		var searchType = "type1" // assume type1
		
		if (availableMenus) {
			// if the color/style menu is "in between" two size menus
			if ( availableMenus[1] && availableMenus[2] && (availableMenus[1] == "menuColor") && (availableMenus[2] == "menu_1") ) {
				searchType = "type2";
			}
			// if the color/style menu comes first, and a size menu follows it
			else if ( availableMenus[0] && availableMenus[1] && (availableMenus[0] == "menuColor") && (availableMenus[1] == "menu_0") ) {
				searchType = "type3";
			}
			// Otherwise, all other conditions are "type1"
		}
		
		var resultArray = new Array(3);
		resultArray[0] = false; // return false if searchStr is not found
		
		if (color == -1 || size1 == -1 || size2 == -1) {
			// do nothing, and simply return resultArray[0] = false
		}
		else {
			var searchStr;
			if ( (color != "false")&&(size1 != "false")&&(size2 != "false") ) {
				if ( searchType == "type2" ) { searchStr = size1 + "|" + color + "|" + size2; }
				else if ( searchType == "type3" ) { searchStr = color + "|" + size1 + "|" + size2; }
				// otherwise it's type3
				else { searchStr = size1 + "|" + size2 + "|" + color; }	
			}
			else if ( (color != "false")&&(size1 != "false")&&(size2 == "false") ) {			
				if ( searchType == "type3" ) { searchStr = color + "|" + size1; }
				// otherwise type1 and type2 have the same search string:
				else { searchStr = size1 + "|" + color; }
			}
			else if ( (color != "false")&&(size1 == "false")&&(size2 == "false") ) {
				searchStr = color;
			}
			else if ( (color == "false")&&(size1 != "false")&&(size2 == "false") ) {
				searchStr = size1;
			}
			
			if (window.jsonData) {
				if (jsonData.metaTypes) {
					var metaTypeArray = jsonData.metaTypes;
					var context;
					for (var s in metaTypeArray) {
						context = jsonData[s];
						if (context) {	
							for (var n = 0; n<context.length;n++) {
								if (context[n] == searchStr) {
									resultArray[0] = metaTypeArray[s][0];
									resultArray[1] = metaTypeArray[s][1];
									resultArray[2] = s;
									break;
								}
							}
							// Break out of the outer loop if we have a match
							if (resultArray[0] != false) {
								break;
							}
						}
					}
				}
			}
			
			/*
			 * if no search result, resultArray[0] is false
			 * if there was a match, resultArray[0] contains the status string from the JSON ("sold out", "in stock", etc)
			 * if there was a match, but the item should be disabled, resultArray[1] is false
			 * also if there was a match, resultArray[2] contains the metaType index for the kind of metaType the result was
			 *  That is, In Stock is always at index 0 of metaTypes, Sold Out is always at index 1, etc.
			 */ 
		}
		return resultArray;
	}
	
	function getAllColorCodes() {
		var colorCodesArray = new Array();
		for (var j in jsonData.attributeArrays[jsonData.attributeArrays.length-1]) {
			colorCodesArray[j] = j;
		}
		return colorCodesArray;
	}
}	
	
function menuClass() {
	
	var colorMenuId = "menuColor";
	var size1MenuId = "menu_0";
	var size2MenuId = "menu_1";
	
	this.getColor = getColor;
	this.getSize1 = getSize1;
	this.getSize2 = getSize2;
	this.updateColorMenu = updateColorMenu;
	
	function get(attrIndex) {
		if (!document.getElementById("menu_"+attrIndex)) return 0;
		var attrVal = document.getElementById("menu_"+attrIndex).value;
		if ( attrVal == null ) {
			attrVal = 0;
		}
		return attrVal;
	}
	
	// returns "false" if this menu doesn't exist
	function getColor() {
		if (!document.getElementById(colorMenuId)) return "false";
		var selectedColor = document.getElementById(colorMenuId).selectedIndex - 1;
		//var selectedColor = document.getElementById(colorMenuId).value;
		if ( selectedColor == null ) {
			selectedColor = "false";
		}
		//trace("color selected Index: "+document.getElementById(colorMenuId).selectedIndex);
		return selectedColor;
	}
	
	// returns "false" if this menu doesn't exist
	function getSize1() {
		if (!document.getElementById(size1MenuId)) return "false";
		var selectedSize1 = document.getElementById(size1MenuId).selectedIndex - 1;
		//var selectedSize1 = document.getElementById(size1MenuId).value;
		if ( selectedSize1 == null ) {
			selectedSize1 = "false";
		}
		return selectedSize1;
	}
	
	// returns "false" if this menu doesn't exist
	function getSize2() {
		if (!document.getElementById(size2MenuId)) return "false";
		var selectedSize2 = document.getElementById(size2MenuId).selectedIndex - 1;
		//var selectedSize2 = document.getElementById(size2MenuId).value;
		if ( selectedSize2 == null ) {
			selectedSize2 = "false";
		}
		return selectedSize2;
	}
	
	function updateColorMenu(colorCode) {
		// 1 is added below because the menu's index is offset by 1 due to the first element being a label
		if ( document.getElementById(colorMenuId) ) {
			document.getElementById(colorMenuId).selectedIndex = parseInt(colorCode) + 1;
		}
	}
}

function swatchesClass(swatchCount) {
	this.swatchClicked = swatchClicked;
	this.setOutOfStock = setOutOfStock;
	this.setAllInStock = setAllInStock;
	
	function swatchClicked(initiatingElement) {
		var color = initiatingElement.getAttribute("colorData");
		pageControllerObject.colorChange(color);
	}
	
	function setAllInStock() {
		
		for ( var colorCode = 0; colorCode<swatchCount; colorCode++ ) {
			var imageLinkId = "swatchImageLink" + colorCode;
			var textLinkId = "swatchTextLink" + colorCode;
			if ( document.getElementById(imageLinkId) && document.getElementById(textLinkId) ) {
				
				var textLinkElement = document.getElementById(textLinkId);
				var imageLinkElement = document.getElementById(imageLinkId);
				textLinkElement.onclick = function(){pageControllerObject.swatchesObject.swatchClicked(this); return false;};
				textLinkElement.setAttribute("href", "#");
				textLinkElement.setAttribute("class","listLink");
				if (textLinkElement.firstChild.childNodes[2]) {	
					textLinkElement.firstChild.removeChild( textLinkElement.firstChild.childNodes[2] );	
				}
				imageLinkElement.onclick = function(){pageControllerObject.swatchesObject.swatchClicked(this); return false;};
				imageLinkElement.setAttribute("href", "#");
			} 
		}
	}
	
	function setOutOfStock(colorCode, statusText) {
		var imageLinkId = "swatchImageLink" + colorCode;
		var textLinkId = "swatchTextLink" + colorCode;
		if ( document.getElementById(imageLinkId) && document.getElementById(textLinkId)) {
			var imageLinkElement = document.getElementById(imageLinkId);
			var textLinkElement = document.getElementById(textLinkId);
		
			// for IE
			imageLinkElement.onclick = null;
			//imageLinkElement.href = null;
			textLinkElement.onclick = null;
			//textLinkElement.href = null;
		
			if (imageLinkElement.removeAttribute) {
				imageLinkElement.removeAttribute("onclick");
				imageLinkElement.removeAttribute("href");
				textLinkElement.removeAttribute("onclick");
				textLinkElement.removeAttribute("href");
				textLinkElement.removeAttribute("class");
			}
		
			/*
			else {  // if removeAttribute is not supported (ie5)
				imageLinkElement.onclick = null;
				imageLinkElement.href = null;
				textLinkElement.onclick = null;
				textLinkElement.href = null;
			}
			*/
		
			if (textLinkElement.firstChild) {
				if (statusText) {
					textLinkElement.firstChild.appendChild( document.createTextNode( " (" + statusText + ")" ) );
				}
			}
		}
	}
}

function swatchesZoomClass(swatchCount) {
	this.swatchClicked = swatchClicked;
	this.setOutOfStock = setOutOfStock;
	this.setAllInStock = setAllInStock;
	this.deactivateLink = deactivateLink;
	this.activateLink = activateLink;
	this.setSwatchMouseBehavior = setSwatchMouseBehavior;

	function setSwatchMouseBehavior() {

		for ( var colorCode = 0; colorCode < swatchCount; colorCode++ ) {
			var imageLinkId = "swatch" + colorCode;
			if (document.getElementById(imageLinkId) ) {
				var imageLinkElement = document.getElementById(imageLinkId);
				
				//add onmouseout behavior
				imageLinkElement.onmouseover = function(){pageControllerObject.swatchMouseOver(this); return false;};
				
				//add onmouseover behavior
				imageLinkElement.onmouseout = function(){pageControllerObject.swatchMouseOut(this); return false;};
			}
		}
	}


	function swatchClicked(initiatingElement) {
		// get colorCode from "colorData" attribute
		var colorCode = initiatingElement.getAttribute("colorData");
		
		// is image swapping enabled
		if (popupImages.imageFunctionIndicator == 4)  {
			// perform image swapping
			pageControllerObject.colorChange(colorCode, true);
		}
		
	}
	
	function setAllInStock() {
		
		for ( var colorCode = 0; colorCode < swatchCount; colorCode++ ) {
			
			var imageLinkId = "swatch" + colorCode;
		
			if ( document.getElementById(imageLinkId) ) {
				var imageLinkElement = document.getElementById(imageLinkId);
				
				// activate swatch link
				imageLinkElement.onclick = function(){pageControllerObject.swatchesObject.swatchClicked(this); return false;};
								
				// remove border around image
				imageLinkElement.style.border = '1px solid #fff';
				
				// set status text to empty string
				if (popupImages.soldOutText) { 
					popupImages.soldOutText[colorCode] = "";
				}
				
			} 
		}
	}
	
	function setOutOfStock(colorCode, statusText) {
		var imageLinkId = "swatch" + colorCode;
		var altText = popupImages.colorNames[colorCode];
		
		if (statusText) {
			if (popupImages.soldOutText) { 
				popupImages.soldOutText[colorCode] = "(" + statusText + ")";
			}
			altText +=  " (" + statusText + ")";
		}
				
		if ( document.getElementById(imageLinkId) ) {
			var imageLinkElement = document.getElementById(imageLinkId);
			
			// for IE
			imageLinkElement.onclick = null;
			
			// remove link on selected image
			if (imageLinkElement.removeAttribute) {
				imageLinkElement.removeAttribute("onclick");
			}
			imageLinkElement.setAttribute("style", "cursor:default;");
			imageLinkElement.setAttribute("alt", altText);
			imageLinkElement.setAttribute("title", altText);
		}
	}
	
	function deactivateLink(colorCode) {
		var imageLinkId = "swatch" + colorCode;
		
		if ( document.getElementById(imageLinkId) ) {
			var imageLinkElement = document.getElementById(imageLinkId);
			
			// for IE
			imageLinkElement.onclick = null;
			
			// remove link on selected image
			if (imageLinkElement.removeAttribute) {
				imageLinkElement.removeAttribute("onclick");
				//imageLinkElement.removeAttribute("href");
			}
			imageLinkElement.setAttribute("style", "cursor:default;");
			
			// add border around image
			imageLinkElement.style.border = '1px solid #33604c';
		}
	}
	
	function activateLink(colorCode) {
		var imageLinkId = "swatch" + colorCode;
		
		if ( document.getElementById(imageLinkId) ) {
			var imageLinkElement = document.getElementById(imageLinkId);
			
			// activate swatch link
			imageLinkElement.onclick = function(){pageControllerObject.swatchesObject.swatchClicked(this); return false;};
			//imageLinkElement.setAttribute("href", "#");
			imageLinkElement.setAttribute("style", "cursor:pointer;");
			
			// remove border around image
			imageLinkElement.style.border = '1px solid #fff';
			
		}
	}
}


function imageSwapClass(imageArray) {
	
	var imgId = "productShot"; // this can be changed to whatever the ID of the img tag is
	this.swap = swap;
	
	// 1st argument is ignored if the 2nd arg is present
	function swap(colorCode, optionalImageURL) {
		var newImageUrl;
		if (optionalImageURL) {
			newImageUrl = optionalImageURL;
		} else if (imageArray[0]) { // make sure the imageArray actually contains something
			newImageUrl = imageArray[colorCode];
		}
		var swapElement = document.getElementById(imgId);
		if ( newImageUrl && swapElement.src != newImageUrl ) {
			swapElement.src = newImageUrl;
		}
	}
}


function imageSwapZoomClass(imageArray) {
	
	this.swapMainThumb = swapMainThumb;
	
	// 1st argument is ignored if the 2nd arg is present
	function swapMainThumb(colorCode, optionalImageURL) {

		var newImageUrl;
		if (optionalImageURL) {
			newImageUrl = optionalImageURL;
		} else if (imageArray[0]) { // make sure the imageArray actually contains something
			newImageUrl = imageArray[colorCode];
		}
		// swap Main thumbnail image
		var swapElement1 = document.getElementById("main1");
		var swapElement2 = document.getElementById("main2");
		if ( newImageUrl && swapElement1 && swapElement1.src != newImageUrl ) {
			swapElement1.src = newImageUrl;
			swapElement2.src = newImageUrl;
		}
				

	}
}

// Changes the textual display of the currently selected color, on the View Larger popup page
// 1st argument is ignored if the 2nd is present
function colorTextSwap(colorTextArray) {
	
	this.swap = swap;
	this.setVisibility = setVisibility;
	var textDivID = "colorName"
	
	function setVisibility(visibilityFlag) {
		if ( document.getElementById(textDivID) ) {
			var colorTextDiv = document.getElementById(textDivID);
			if (visibilityFlag == true) {	
				colorTextDiv.style.visibility = "visible";
			}
			if (visibilityFlag == false) {
				colorTextDiv.style.visibility = "hidden";
			}	
		}	
	}
	
	function swap(colorCode, optionalColorText) {
		if ( document.getElementById(textDivID) ) {
			var newColorText = "";
			if (optionalColorText) {
				newColorText = optionalColorText;
				colorCode = 0; // set colorCode just in case it happened to be -1 so the below condition doesn't fail 
			}
			else if ( (colorTextArray) && (colorCode != -1) ) {
				newColorText = colorTextArray[colorCode];
			}
			if (colorCode != -1) {
				// intentionally verbose
				var colorTextDiv = document.getElementById(textDivID);
				if (colorTextDiv.firstChild && colorTextDiv.firstChild.firstChild) {
					var innerColorTextDiv = colorTextDiv.firstChild;
					var colorTextSpan = innerColorTextDiv.firstChild;
					// Branch here for IE, which seems to have issues with children of Span elements
					if (colorTextSpan) {
						if ( colorTextSpan.firstChild == null ) {
							if (innerColorTextDiv.innerHTML) {
								innerColorTextDiv.innerHTML = newColorText;
							}
						}
						else {
							colorTextSpan.firstChild.nodeValue = newColorText;
						}
					}
				}
			}		
		}
	}
}

function colorTextZoomSwap(colorNames) {
	
	this.swap = swap;

	function swap(colorCode, optionalColorText) {
				
		if (colorCode == null) {
			colorCode = this.curColorCode;
		}
		
		// get color name from popupImages.colorNames using colorCode
		var colorText;
		if (optionalColorText) {
			colorText = optionalColorText;
		}
		else if ( colorNames && (colorCode != -1) ) {
			colorText = colorNames[colorCode];
		}
		
		// check if sold out
		if (popupImages.soldOutText[colorCode]) {
			// color sold out - append sold out text
			colorText += " ";
			colorText += popupImages.soldOutText[colorCode];
		}
		
		// swap color text
		if ( document.getElementById("zoomSwatchText") ) {
			
			var colorTextDiv = document.getElementById("zoomSwatchText");
			colorTextDiv.innerHTML = colorText;
		}
	}
}

function zoomControlClass() {
	
	this.zoomIn = zoomIn;
	this.zoomOut = zoomOut;
	this.reset = reset;
	this.swap = swap;
	this.setZoomControlMouseBehavior = setZoomControlMouseBehavior;


	function setZoomControlMouseBehavior() {
		
		if (document.getElementById("zoomControls") ) {
			
			document.getElementById("zoomInBtn").onclick = function(){pageControllerObject.zoomControlObject.zoomIn(); return false;};  
			document.getElementById("zoomOutBtn").onclick = function(){pageControllerObject.zoomControlObject.zoomOut(); return false;};  
			document.getElementById("resetBtn").onclick = function(){pageControllerObject.zoomControlObject.reset(); return false;};  
		}
	}
	
	function zoomIn() {
		flashProxy.call("zoomIn");
		
		//send metrics on first click
		if (zoomControlMetrics) {
			sendZoomControlMetric();
		}
	}
	
	function zoomOut() {
		flashProxy.call("zoomOut");
		
		//send metrics on first click
		if (zoomControlMetrics) {
			sendZoomControlMetric();
		}
	}
		
	function reset() {
		flashProxy.call("reset");
		
		//send metrics on first click
		if (zoomControlMetrics) {
			sendZoomControlMetric();
		}
	}
	
	function swap(imageIndex, resetIndicator) {
		if (resetIndicator && resetIndicator==1) {
			setFlashParamReset(imageIndex);
		}
		else {
			setFlashParam(imageIndex);
		}
	}

	function setFlashParam(imageIndex) {
		flashProxy.call("loadNewMovie", popupImages.zoomUrlArray[imageIndex], imageIndex);
	}
	
	function setFlashParamReset(imageIndex) {
		flashProxy.call("loadNewMovieReset", popupImages.zoomUrlArray[imageIndex], imageIndex);
	}
	
	function sendZoomControlMetric() {
		s_events=s_pageName=s_prop2=s_prop4=s_eVar4=s_eVar14=s_prop15=s_prop22="";
		s_prop24 = "ZoomClick";
		void(sendAnalyticsEvent(''));
		zoomControlMetrics = false;
	}
	
}

function zoomAltThumbsClass() {
	
	this.onThumbClick = onThumbClick;
	this.resetThumbnails = resetThumbnails;
	this.selectMainThumbnail = selectMainThumbnail;
	this.setAltThumbMouseBehavior = setAltThumbMouseBehavior;
	this.showHideSwatches = showHideSwatches;

	function setAltThumbMouseBehavior() {
		
		if (document.getElementById("zoomImages") ) {
			if (popupImages.altImageAnchors[0]) {
				for (i=0; i < popupImages.altImageAnchors.length; i++) {
					document.getElementById(popupImages.altImageAnchors[i]).onclick = function(){pageControllerObject.zoomAltThumbsObject.onThumbClick(this); return false;};  
				}	
			}
		}
	}

	function onThumbClick(initiatingElement) {
		
		// get colorCode from element atributes
		var colorCode = initiatingElement.getAttribute("zoomData");
		
		// set altView flag and colorCode if thumbnailCode == "main"
		var altView = true;
		if (initiatingElement.name.indexOf('main') > -1) {
			// not an alternate view
			altView = false;
			pageControllerObject.altViewSelected = 0;
						
			// get colorCode from swatchControl
			colorCode = pageControllerObject.curColorCode;  // holds value of currently selected swatch
		}
		else {
			pageControllerObject.altViewSelected = 1;	
		}
		
		// 
		
		// swap flash viewer image
		pageControllerObject.zoomControlObject.swap(colorCode, 1); 
		
		// show/hide swatches 
		showHideSwatches(altView);
		
		// reset all thumbnails
		resetThumbnails();
		
		// put border around image
		document.images[initiatingElement.name].style.border = '2px solid #2b624d';
		
		// hide anchor and show nolink
		document.getElementById(initiatingElement.name + ' anchor').style.display = 'none';
		document.getElementById(initiatingElement.name + ' nolink').style.display = 'block';
		initiatingElement.blur();
	}
	
	function showHideSwatches(altView) {
				
		// hide swatches or show the swatches
		if (altView == null) altView = false;
		if ( document.getElementById("zoomSwatches") ) {
			if ( altView  ) {
				// alternate view image selected, hide swatches
				document.getElementById("zoomSwatches").style.display = "none";
				document.getElementById('zoomSwatchesHolder').style.display = "block";
				
				// remove border form zoomContent
				document.getElementById('zoomContent').style.border = '1px solid #ffffff';
			} else {
				// main image selected, show swatches
				document.getElementById("zoomSwatches").style.display = "block";
				document.getElementById('zoomSwatchesHolder').style.display = "none";
				
				// add border form zoomContent
				document.getElementById('zoomContent').style.border = '1px solid #ccc';
			}
		}
	}
	
	
	function resetThumbnails() {
		
		var len = document.images.length;
		if (document.getElementById("zoomImages") ) {
			for(var i = 0; i < len; i++) {
				if(document.images[i].className == 'thumb') {
					document.images[i].style.border = '2px solid #fff';
					document.getElementById(document.images[i].name + ' anchor').style.display = 'block';
					document.getElementById(document.images[i].name + ' nolink').style.display = 'none';
				}
			}
		}
	}
	
	function selectMainThumbnail() {
		if (document.getElementById("zoomImages") ) {
			document.images['main'].style.border = '2px solid #2b624d';
			document.getElementById('main anchor').style.display = 'none';
			document.getElementById('main nolink').style.display = 'block';
		}
	}	
	
}


var prodTabController = {
	"currentTabIndex":1,
	
	"onTabClick": function (newTabIndex, newClassName) {
	
		if (newTabIndex==this.currentTabIndex) { return; }
		if ( (newClassName=='tabLabelBlank') || (newClassName=='tabLabelOn'))  { return; }
		
		this.setTab(this.currentTabIndex, 'Off');
		this.setTab(newTabIndex, 'On');
	  	this.currentTabIndex = newTabIndex;
		
		prodMetricObj.trackTabUsage(newTabIndex);
	  	
	  	var tabContainer = document.getElementById('tabContainer');
	  	tabContainer.scrollTop = 0;
	},
	
	"setTab": function (index, status) {
		var thisTabLabel = document.getElementById('tabLabel_' + index);
		var thisTabContent = document.getElementById('tabContent_' + index);
	
		thisTabLabel.className = 'tabLabel' + status;
//		if (status == 'On') {
//	  		thisTabContent.style.display='block';
//	  	} else {
//	  		thisTabContent.style.display='none';
//	  	}
	  	if (thisTabContent.className.indexOf("Style") == -1) {
	  		thisTabContent.className += " tab"+status+"Style";
		} else {
	  		thisTabContent.className = thisTabContent.className.replace(/tab\w{2,3}Style/ ,"tab"+status+"Style");
	  	}

	},
	
	"resizeTabContainer":function (tabHeightReferenceId, minimumHeight) {
	
		var tabHeightReferenceElement = document.getElementById(tabHeightReferenceId);
		var tabLabelContainerElement = document.getElementById("tabLabelContainer");
		var tabContainerElement = document.getElementById("tabContainer");
		
		//debug("version 9/18 15:16");
		
		var referenceHeight = tabHeightReferenceElement.offsetHeight;
		var labelHeight = tabLabelContainerElement.offsetHeight;
		
		if (referenceHeight < minimumHeight) {
			tabContainerElement.style.height = minimumHeight - labelHeight;
		} else {
			tabContainerElement.style.height = referenceHeight - labelHeight;
		}
	}
};

// This function hides the "email a friend" hyperlink on the product page if the currently selected color's main image is unavailable/broken
// conversely, this function makes the hyperlink visible when the main image loaded correctly. 
function setEmailFriendVisibility() {
	if ( document.productShot.src='http://www.llbean.com/images/sorry_prod.gif' ) {
		if ( getObject('emailLink') ) { 
			getObject('emailLink').style.display = 'none';
			getObject('emailLink2').style.display = 'none';
		}
	}
	else {
		if ( getObject('emailLink') ) { 
			getObject('emailLink').style.display = 'block';
			getObject('emailLink2').style.display = 'block';
		}
	}
}
