
	/** 
	* @projectDescription Part of the core Arcadia JavaScript library - contains Methods and Properties used by all brands
	* @author Russ Back russell.back@arcadiagroup.co.uk
	* @version 1.12.1
	* @since 1.0.0
	*/

	
	var Arcadia = {
		
		version: "1.12.1",

		currentUrl : location.href.toLowerCase(),	// url of current page
		devDomain : "wcdev.arcadiagroup.ltd.uk",	// dev box domain name
		stagingDomain : "wcstage.arcadiagroup.ltd.uk",	// staging box domain name
		adminDomain : "wcadmin.arcadiagroup.ltd.uk",	// admin box domain name
		classNameRegExp : /[^\w]+/g,	// regular expression to use to add classnames to elements based on their value
		debugMode : false,	// set to true to record execution time of Arcadia{} Methods
		
		/** 
		 * Initiates all Arcadia library functionality - called from each Brand file (such as Topman.js)
		 */
		init : function() {
			
			if (Arcadia.debugMode) Util.debug("Arcadia.init");
			
			// break out of frames if site has been embedded in the frameset of an affiliate or rogue site (allows ECMC previews)
			if (top.location != location && Util.getUrlParam("ecmcFrame") == null) top.location.href = document.location.href;
			
			// quit if the load method failed
			if (typeof Brand != "object") return;		
			// quit if browser is too old (detect createTextNode for some versions of Opera)
			if (! document.getElementById || ! document.createTextNode) return;
			// caching to stop flicker bug in IE6
			if (typeof document.body.style.maxHeight == "undefined") { try { document.execCommand('BackgroundImageCache', false, true); } catch(e) { } }
			// initiate all functionality			
			Template.init(); // must be called before Behaviour.init
			Behaviour.init();
			CMS.init();
			if (typeof GoogleAnalytics == "object") GoogleAnalytics.init(); // fire if the script has been included
			
			if (Arcadia.debugMode) Util.debug("Arcadia.init", true);

			}
		
		};
	
	/** 
	* @projectDescription Utility functions of the core Arcadia JavaScript library - contains Methods and Properties used by all brands
	*/
	var Util = {
		
		/**
		 * Records execution time of a function. Call once to start timer and once to end timer and log to a console div.
		 * @param {String} fn The name of the function to record.
		 * @param {Boolean} end Set to true if this is the call to stop the timer. (Optional.)
		 */
		debug : function(fn, end) {
				// append console to body
				if ($("#debug_console").size() == 0) $(document.body).prepend("<div id=\"debug_console\"><h2>Ecommerce Systems JS logging</h2></div>");
				// if this is not an end of function call, record the current time for this function
				if (! end) {
					eval(fn + ".start = new Date()");
					}
				// otherwise record the current time and work out how long has elapsed since this function was started and append this to the console
				else{
					var now = new Date();
					$("#debug_console").append("<p>" + fn + ": " + eval(now.getTime() - eval(fn + ".start.getTime()")) + "ms</p>");					
					}
			},
		
		/**
		 * Add an event listener to an element. Taken from http://ejohn.org/projects/flexible-javascript-events/. 
		 * Deprecated in favour of jQuery methods.
		 * @param {Object} obj The DOM element to attach the event to.
		 * @param {String} type The type of event (such as "mouseover", "load", "click").
		 * @param {Object} fn The function to execute when the event occurs.
		 * @deprecated
		 */
		addEvent : function(obj, type, fn) {
			if ( obj.attachEvent ) {
				obj['e'+type+fn] = fn;
				obj[type+fn] = function(){obj['e'+type+fn]( window.event );};
				obj.attachEvent( 'on'+type, obj[type+fn] );
				} 
			else {
				obj.addEventListener( type, fn, false );
				}
			},
		
		/** 
		 * document.getElement(s)ById shortcut utility, taken from prototype.js.
		 * Deprecated in favour of jQuery methods.
		 * @deprecated
		 * @return {null, Object, Array} A DOM element or array of elements, or null if no elements were matched.
		 */
		$ : function() {
		  var els = new Array();
			for (var i = 0; i < arguments.length; i++) {
		  		var el = arguments[i];
		   		if (typeof el == "string") el = document.getElementById(el);
			  	if (arguments.length == 1) return el;
		    	els.push(el);
			  	}
			return els;
			},
		
		/**
		 * Returns an array of elements containing the given classname. 
		 * Can be narrowed down by providing element types to search for and the parent node to search from.
		 * Deprecated in favour of jQuery methods.
		 * @param {String} className The classname to search for (e.g. "active_element").
		 * @param {String} tag The element to seach for (e.g. "li").
		 * @param {Object, String} parent The DOM element to start from, or the ID of DOM element to start from (e.g. "lefthandbar").
		 * @return {Array} An array of DOM elements matching the parameters passed into the Method.
		 * @deprecated
		 */
		getElementsByClassName : function(className, tag, parent) {
			var els = (Util.$(parent) || document.body).getElementsByTagName((tag || "*")), matches = new Array();
			for (var i = 0; i < els.length; i++) { if (Util.hasClassName(els[i], className)) matches.push(els[i]); }
			return matches;
			},
		
		/**
		 * Checks to see if an element has a given classname.
		 * Deprecated in favour of jQuery methods.
		 * @param {Object, String} el A DOM element or the ID of a DOM element to check (e.g. "lefthandbar").
		 * @param {String} className The classname to check for (e.g. "active_element").
		 * @return {Boolean} True if the element has the given classname.
		 * @deprecated
		 */
		hasClassName : function(el, className) {
			var re = new RegExp("(^|\\s)" + className + "(\\s|$)");
			return Util.$(el).className.match(re);
			},

		/**
		 * Strips a querystring value from a given URL. Adapted from http://www.netlobo.com/url_query_string_javascript.html
		 * @param {String} param The parameter to return (e.g. "productId").
		 * @param {String} url The URL to use (e.g. "http://www.topshop.com/servlet/ProductDisplay?productId=20556"). Uses location.href if no URL is defined. (Optional.)
	 	 * @return {String, null} The querystring value (e.g. 20556, or "addToBag"), or null if not found.
		 */	
		getUrlParam : function(param, url) {
			url = (url || location.href).toLowerCase(); 
			param = param.toLowerCase().replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
		  	var regex = new RegExp("[\\?&]" + param + "=([^&#]*)");
		  	var results = regex.exec(url);
		  	if (results) return results[1];
		  	else return null;
			},				

		/**
		 * Cancel the default action of a user's click event.
		 * Deprecated in favour of jQuery methods.
		 * @param {Object} e The event object (internal user only).
		 * @deprecated
		 */
		cancelClick : function(e) {
			// if it's IE, cancel event bubbling and return false
			if (window.event) {
				window.event.cancelBubble = true;
				window.event.returnValue = false;
				}
			// or use Mozilla's alternative methods
			if (e && e.stopPropagation && e.preventDefault) {
				e.stopPropagation();
				e.preventDefault();
				}
			},
		
		/**
		 * Adds a css className or ID to every matching element in the DOM.
		 * For example this Method will add an ID (or className if and ID is already in place) on every LI element in 
		 * the DOM within the "content" element of WCS pages. ClassNames and IDs are applied numerically (li_1, li_2, etc).
		 * Deprecated - avoid using IDs and classNames applied by this Method wherever possible as this is not a reliable way to target DOM elements.
		 * Safe to remove?
		 * @param {String} element The type of element to alter (e.g. "li").
		 * @param {Array, null} childElements The child elements to work with (e.g. in the case of "tr", child elements would be ["th", "td"]).
		 * @param {Boolean} addId Set to true to add an ID rather than a className.
		 * @param {Object, String} parent The DOM element or ID of a DOM element to start from (e.g. "content").
		 * @param {Boolean} [directDescendentsOnly] Set to true to work with direct descendents only. This ensure nested elements, such as UL menus, are correctly labelled. (Optional.)
		 * @deprecated
		 */
		addCss : function(element, childElements, addId, parent, directDescendentsOnly) {
			// quit if we have no content
			if (! Util.$("content")) return;
			// get the starting element and each request element within it, and initialise a counter
			parent = parent || Util.$("content");
			var elements = parent.getElementsByTagName(element), css, counter = 1;
			// loop through each element			
			for (var i = 0; i < elements.length; i++) {
				// skip if this element is not a direct descendent of the parent if necessary
				// ie. to ensure correct handling of embedded markup, such as dl dd dl dd 
				// if we didn't skip here, the second dd in the example above could have class="dd_4 dd_1"
				if (directDescendentsOnly && elements[i].parentNode != parent) continue;				
				// create the css id or class to apply
				css = element + "_" + counter;
				// if we need to add an id
				if (addId  &! elements[i].id) elements[i].id = css;
				// otherwise add a className
				else $(elements[i]).addClass(css);
				// increment the counter to take account of any th/td colspans and add an additional class
				if (elements[i].colSpan > 1) {
					$(elements[i]).addClass("spanned_cell_" + counter);
					counter += elements[i].colSpan;
					}
				// or just add 1
				else counter ++;				
				// if we have childElements...
				if (childElements.length) {
					// loop through each child element
					for (var j = 0; j < childElements.length; j++) {
						// and add a className by calling this function again for this particular element
						// apply function to each th and td cell if we're working with rows (pass in false for last param as there 
	    		 	// shouldn't be any embedded tables knocking about
						if (childElements[j] == "tr") Util.addCss(childElements[j], ["th", "td"], false, elements[i], false);
						// otherwise do not pass in childElements as we'd end up with an infinite loop
						else Util.addCss(childElements[j], [], false, elements[i], true);
						}
					}
				}
			},
			
		/**
		 * Simple redirect function for feature folder redirects (called as a failsafe in case meta refreshes fail).
		 * @param {String} url The URL to redirect to.
		 * @param {Object} [delay] The number of milliseconds to wait until redirecting. (Optional.)
		 */
		redirect : function(url, delay) {
			// set timeout if there should be a delay before redirecting
			if (delay) {
				setTimeout( function() { location.href = url; }, delay);
				return;
				}
			// otherwise just redirect immediately
			location.href = url;
			},
			
		/**
		 * Sets a client-side cookie
		 * Based on createCookie() from http://www.quirksmode.org/js/cookies.html
		 * @param {String} name Name of the cookie.
		 * @param {String} value Value to be set.
		 * @param {Number} days Days from today to add to expiry date.
		 * @deprecated
		 */
		setCookie : function (name, value, days) {
			var date = new Date();
			date.setTime(date.getTime() + (days*24*60*60*1000));
			var expires = "; expires=" + date.toGMTString();
			document.cookie = name + "=" + value + expires + "; path=/";
			},

		/**
		 * Retrieves a client-side cookie
		 * Based on readCookie() from http://www.quirksmode.org/js/cookies.html
		 * @param {String} name The name of the cookie to retrieve
		 */
		getCookie : function (name) {
			var nameEQ = name + "=";
			var ca = document.cookie.split(';');
			for(var i=0;i < ca.length;i++) {
				var c = ca[i];
				while (c.charAt(0)==' ') c = c.substring(1,c.length);
				if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
				}
			return null;
			}

		};
		

	/** 
	* @projectDescription Applies fixes and additions to Websphere templates, to be removed as issues are resolved by IBM.
	*/
	var Template = {

		/**
		 * Initiate all template functions.
		 */
		init : function() {	
		
			if (Arcadia.debugMode) Util.debug("Template.init");
		
			// add an id to the body tag - must be called first
			Template.setPageParameters();
						
			// remove unwanted items from templates
			Template.removeTrackingLink();	// uses jquery
			
			// fix markup issues that exist on various pages
			Template.fixCategoryDisplay();

			// add new elements to pages
			Template.addActiveLinkClasses();	// uses jquery
			Template.addBookMarkLink();	// uses jquery
			Template.prefillSignup();	
			
			// add css ids and classes to content elements
			Template.addTemplateCss();
			
			// alert if not on live catalog
			Template.checkCatalogId();	// uses jquery
			
			// call methods specific to each brand
			Template.initBrandMethods();
			
			if (Arcadia.debugMode) Util.debug("Template.init", true);
					
			},

		/**
		 * Assigns various parameters according to the current URL.
		 * Applies:
		 * - the current servlet name as the ID of the body element and the value of the Template.id property;
		 * - the current URL in Template.currentURL property;
		 * - the classname "quersystring_encrypted" to the body of the page if no QS parameters can be found;
		 * - the current storeId QS parameter in Template.currentStoreId;
		 * - the current catalogId QS parameter in Template.currentCatalogId;
		 * - the current categoryId QS parameter in Template.currentCategoryId;
		 * - the current parent_category_rn QS parameter in Template.currentParentCategoryId;
		 * - the current productId QS parameter in Template.currentProductId;
		 * - the current identifierId QS parameter in Template.currentIdentifierId;
		 * - the current featureId QS parameter in Template.currentFeatureId;
		 * - the classname "error_page" if an error has occurred.
		 */
		setPageParameters : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.setPageParameters");
			
			Template.id = document.body.id;
			
			// assign the servlet name (in lower case) as a property 
			// note: always check for the property type as it will be defined manually in local development pages
			if (Arcadia.currentUrl.match("servlet")) {
				
				// also get current storeid from the current url
				var url = Arcadia.currentUrl;
				if (typeof Arcadia.currentStoreId == "undefined") {
					Arcadia.currentStoreId = Util.getUrlParam("storeid", url) || null;
					// if it doesn't contain it, try the breadcrumb as a fallback
					if (! Arcadia.currentStoreId) {
						url = $("#breadcrumb a:last").attr("href");
						// record the fact that we don't have a qs to use if necessary
						$(document.body).addClass("querystring_encrypted");
						}
					}

				// now get the params from the url
				if (typeof Arcadia.currentStoreId == "undefined") Arcadia.currentStoreId = Util.getUrlParam("storeid", url) || null;
				if (typeof Arcadia.currentCatalogId == "undefined") Arcadia.currentCatalogId = Util.getUrlParam("catalogid", url) || null;
				if (typeof Arcadia.currentCategoryId == "undefined") Arcadia.currentCategoryId = Util.getUrlParam("categoryid", url) || null;
				if (typeof Arcadia.currentParentCategoryId == "undefined") Arcadia.currentParentCategoryId = Util.getUrlParam("parent_category_rn", url) || null;
				if (typeof Arcadia.currentProductId == "undefined") Arcadia.currentProductId = Util.getUrlParam("productid", url) || null;
				if (typeof Arcadia.currentIdentifierId == "undefined") Arcadia.currentIdentifierId = Util.getUrlParam("identifier", url) || null;
				if (typeof Arcadia.currentFeatureId == "undefined") Arcadia.currentFeatureId = Util.getUrlParam("feature", url) || null;
				
				// add classname to container on category display if it's missing (defect to be fixed)
				if (Template.id == "categorydisplay") $("#container").addClass("category_" + Arcadia.currentCategoryId);

				}
				
				if (Arcadia.debugMode) Util.debug("Template.setPageParameters", true);
				
			},
		
		/**
		 * Creates an onclick event that sets store ID cookie to ID of chosen territory and continues to requested URL
		 * Used for stores with duplicate UK/US catalogs.
		 * @deprecated
		 */		
		enableTerritorySwitch : function() {
			
			},
			
			
		/**
		 * Removes the order tracking link for international orders on the order tracking template.
		 * URL is defined in the Brand.internationalTrackingUrl property.
		 */
		removeTrackingLink : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.removeTrackingLink");
			
			// quit if the internationalTrackingUrl is not defined			
			if (! Brand.internationalTrackingUrl) return;
			// get each link matching the tracking url
			$("p a[href*='" + Brand.internationalTrackingUrl + "']").each( function() {
				// and remove the parent paragraph
				$(this.parentNode).remove();																											
				});
			
			if (Arcadia.debugMode) Util.debug("Template.removeTrackingLink", true);
			
			},
			
		
		/**
		 * Loads CategoryDisplay{} file if required.
		 */
		fixCategoryDisplay : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.fixCategoryDisplay");
			
			// create an anonymous function to attach on page load (fails in IE if we attempt to use it using jquery.ready() function)
			// only called if this brand requires this functionality
			var func = function() {
				if (Brand.enableProdListerFormatting && $(".prodlistwrapper").length) $.getScript("/javascript/template/category_display.js");
				};
			// call the function on page load			
			Util.addEvent(window, "load", func);
			
			if (Arcadia.debugMode) Util.debug("Template.fixCategoryDisplay", true);
			
			},

		
			
		/**
		 * Adds a className to feature menu links that match the current browser location.
		 * If the Arcadia.currentIdentifierId or Arcadia.currentFeatureId properties match the identifierId or featureId 
		 * QS parameters in a link, the className "active" is added to that link.
		 * Links must be wrapped in an element with the className "feature_menu" to trigger this functionality (e.g. "<ul class='feature_menu'>").
		 */
		addActiveLinkClasses : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.addActiveLinkClasses");

			$("ul.feature_menu a, ol.feature_menu a, div.feature_menu a").each( function() {
				if (this.href.match("identifier=" + Arcadia.currentIdentifierId) || this.href.match("identifier=" + Arcadia.currentFeatureId)) $(this).parent().addClass("active");
				});
			
			if (Arcadia.debugMode) Util.debug("Template.addActiveLinkClasses", true);
			
			},
		
		/** 
		 * Initiates Util.addCSS() Method on paragraph, list and table elements.
		 * Deprecated - avoid using IDs and classNames applied by this Method wherever possible as this is not a reliable way to target DOM elements.
		 * Safe to remove?
		 * @deprecated
		 */
		addTemplateCss : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.addTemplateCss");
			
			// add id to each p
			Util.addCss("p", [], true, null, false);
			// add id to each ul and class to each li
			Util.addCss("ul", ["li"], true, null, false);
			// add id to each dl and classes to each dt and dd
			Util.addCss("dl", ["dt", "dd"], true, null, false);
			// add id to each table and class to each tr (th and tds are handled internally by Util.addCss()
			Util.addCss("table", ["tr"], true, null, false);
			
			if (Arcadia.debugMode) Util.debug("Template.addTemplateCss", true);
			
			},

		/**
		 * Prepends a warning image to the top of the page if we're viewing a page that's not using the live sales catalog, or we're on the US site.
		 * Live sales catalog ID is defined in the Brand.activeSalesCatalogId property.
		 */
		checkCatalogId : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.checkCatalogId");
			
			// quit if we're not on the dev or staging servers
			if (! Arcadia.currentUrl.match(Arcadia.devDomain) &! Arcadia.currentUrl.match(Arcadia.stagingDomain) &! Arcadia.currentUrl.match("localhost")) return;
			
			// if the current store id is the us store id...
			if (Arcadia.currentStoreId != null && Brand.isUSStore) {
				// append a new div element to the body with a warning background image
				$("body").prepend("<div id=\"catalog_alert\" style=\"width: 100%; height: 35px; background: url(/wcsstore/ConsumerDirectStorefrontAssetStore/images/colors/color" + Brand.directory + "/us_store_warning.gif) center center no-repeat #33F\"></div>");			
				}
				
			// if the current uk catalog id is not the live id...
			if (Arcadia.currentCatalogId != null && Arcadia.currentCatalogId != Brand.activeSalesCatalogId) {
				// append a new div element to the body with a warning background image
				$("body").prepend("<div id=\"catalog_alert\" style=\"width: 100%; height: 35px; background: url(/wcsstore/ConsumerDirectStorefrontAssetStore/images/colors/color" + Brand.directory + "/catalog_warning.gif) center center no-repeat #F00\"></div>");
				}
			
			
			if (Arcadia.debugMode) Util.debug("Template.checkCatalogId", true);
			
			},
			 
		/**
		 * Launches an AddThis bookmark page in a new window when user clicks on a link with the ID "add_this_link".
		 * Adapted from http://s9.addthis.com/js/widget.php?v=10.
		 * AddThis account name is defined in the Brand.addThisAccountName property.
		 * Move to Behaviour{}
		 */
		addBookMarkLink : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.addBookMarkLink");
			
			if (Brand.addThisLocation != ""){
				
				$(Brand.addThisLocation).append(Brand.addThisLink);
				
				$("#add_this_link").click( function() {	
				var addthis_pub = Brand.addThisAccountName, addthis_url = location.href, addthis_title = document.title;
				var aturl = "http://www.addthis.com/bookmark.php?v=1&pub=" + addthis_pub;
				aturl += "&url=" + encodeURIComponent(addthis_url) + "&title=" + encodeURIComponent(addthis_title);
				window.open(aturl,'addthis','scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100');
				return false;
				});
				
			}
			
			
			if (Arcadia.debugMode) Util.debug("Template.addBookMarkLink", true);
			
			},
			
		/**
		 * Grabs an email address from the URL and looks to prepopulate a form field with the email value.
		 * Expects someurl?email=email@email.com&firstname=someval&lastname=someotherval. 
		 * Looks to populate a field in the content with IDs "REPLY-TO", "emailid", "first_name", "last_name".
		 * To use, the form should use a get method - see unit test for details.
		 */
		prefillSignup : function() {
			
			if (Arcadia.debugMode) Util.debug("Template.prefillSignup");
			
			// grab the email address from the URL
			var email = Util.getUrlParam("email");
			// plus first and last name
			var firstName = Util.getUrlParam("firstname");
			var lastName = Util.getUrlParam("lastname");
			
			// update the email address field in the content of the page
			if (email) {
				$("#content #REPLY-TO").val(unescape(email));
				$("#content #emailid").val(unescape(email));
				}
				
			if (firstName) {
				$("#content #first_name").val(unescape(firstName));
				$("#content #forename").val(unescape(firstName));
				}
			if (lastName) {
				$("#content #last_name").val(unescape(lastName));
				$("#content #surname").val(unescape(lastName));
				}
				
			if (Arcadia.debugMode) Util.debug("Template.prefillSignup", true);	
				
			}

		};
	
	/** 
	* @projectDescription Methods defined here affect the behaviour layer of the WCS sites.
	*/	
	var Behaviour = {

		/**
		 * Initiate all behaviour functions.
		 */
		init : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.init");
			
			Behaviour.initStoreCategoriesMenu();
			Behaviour.initMercadoFilters();
			Behaviour.addTargets();
			Behaviour.addFormValidation();
			Behaviour.initAjax();
			Behaviour.initSwitchFeatures();
			Behaviour.initContentTabs();
			Behaviour.initContentScrollers();
			Behaviour.initContentCycles();
			Behaviour.initBrandMethods();
			Behaviour.clearSearchField();
			Behaviour.initToggleDetail();
			Behaviour.addCsrSearchFocus();
			
			if (Arcadia.debugMode) Util.debug("Behaviour.init", true);
			
			},
			
		/**
		 * Assigns toggle/hide event handlers to links in the store categories menu.
		 * Needs to be updated to use jQuery and potentially the Accordion plugin.
		 */
		initStoreCategoriesMenu : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initStoreCategoriesMenu");
						
			// get the menu element and each list item within it
			var menu = Util.$("top_level_categories");
			if (! menu) return;
			var els = menu.getElementsByTagName("li"), category;
			// assign the toggled element in the markup as the active element of it's parent menu
			var active = Util.getElementsByClassName("active_parent", "li", menu)[0];
			if (active) active.parentNode.activeElement = active;
			// loop through each element
			for (var i = 0; i < els.length; i ++) {
				// if this element has a child menu of subcategories...
				if (els[i].getElementsByTagName("ul").length) {
					// get the first category element (care here as if the system has an expanded menu the first child is a space...)
					category = els[i].firstChild;
					if (category.nodeType != 1) category = category.nextSibling;
					// if this element is a category feature, do nothing
					if (Util.hasClassName(els[i], "category_feature")) continue;
					// otherwise if the first element is a span, create a link for the user to interract with
					if (category.nodeName == "SPAN") {
						var linkElement = Util.createNode("a", [["title", category.firstChild.nodeValue],["href", "#"]], category.firstChild.nodeValue);
						// replace the span with the link
						els[i].replaceChild(linkElement, category);
						}
					// attach the function and cancel the default action of the link
					Util.addEvent(category, "click", Behaviour.toggleCategoryMenu);
					Util.addEvent(category, "click", Util.cancelClick);
					// update the title
					category.title += " - click to show/hide details";
					}
				}
				
				if (Arcadia.debugMode) Util.debug("Behaviour.initStoreCategoriesMenu", true);
				
			},
			
		/**
		 * Initiates slideToggle behaviour on Mercado search results filters.
		 * div#mercado_filters should be set to display: none in the CSS to support this
		 */	
		initMercadoFilters : function() {
			
			// quit if this isn't enabled on this brand
			if (! Brand.enableMercadoFilters) return;
			
			// grab the wrapper
			var wrapper = $("#mercado_header");
			
			// quit if not found
			if (! wrapper.size()) return;
					
			// replace the harcoded text of headline - this should be a dynamic text property
			var h2 = wrapper.find("h2"), h3, group, el;
			
			h2.text(Brand.mercadoFiltersH2)
			
			// create a tabs menu element
			var tabs_menu = $("<ul class=\"tabs_nav clear_fix\"></ul>");
			
			var filters = wrapper.find(".filter_group");
			
			// grab each filter block in the page...
			filters.each( function() {
				
				// set as a jQuery object		
				group = $(this);
				
				// record the H3 content and then remove the h3 element
				h3 = group.find("h3").remove();
				
				// create a new menu element for each group and append to the menu
				$("<li><a href=\"#" + group.attr("id") + "\" title=\"Click to filter by " + h3.text() + "\" rel=\"" + group.attr("id") + "\"><span>" + h3.text() + "</span></a></li>").click( function() {
					
					// record this as the current filter
					var selection = $(this), newFilter = $("#" + selection.find("a").attr("rel"));
					
					// update the active class in the menu
					tabs_menu.children("li").removeClass("active");
					selection.addClass("active");
					
					// hide the current filter and show the new one
					$(".filter_group").not(newFilter).hide();
					newFilter.slideDown();
					
					// cancel click
					return false;
					
					}).appendTo(tabs_menu);
								
				});

			// add active class and show first filter group
			filters.eq("0").show();
			tabs_menu.find("li:first").addClass("active");

			// insert the menu and make the first element active
			tabs_menu.insertAfter(h2);//.children(":first").addClass("active");

			// slide the whole thing into view
			wrapper.slideDown();

			},
		
		/**
		 * Adds and removes toggle classNames of categories within the category menu.
		 * Needs to be updated to use jQuery and potentially the Accordion plugin.
		 */	
		toggleCategoryMenu : function() { 
			// get the parent li and ul elements
			var li = this.parentNode, ul = li.parentNode;
			// if the active element within the parent element is not the one we've clicked on..
			if (ul.activeElement != li) {
				// remove active toggle class from the parent menu
				if (ul.activeElement) $(ul.activeElement).removeClass("focus");
				// remove the toggle class from the list element (do not remove from the active parent though...)
				if (ul.activeElement && Brand.collapseCategories &! Util.hasClassName(ul.activeElement, "active_parent")) $(ul.activeElement).removeClass("toggle");
				// and update the active element in the parent menu
				ul.activeElement = li;
				}
			// add or remove toggle classes from this element as required
			if (Util.hasClassName(li, "toggle")) $(li).removeClass("toggle");
			else {
				$(li).addClass("toggle");
				$(li).addClass("focus");
				}
			},
	
		/**
		 * Attaches the Template.popup() Method to a elements with the className "new_window".
		 */	
		addTargets : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.addTargets");
			
			// get all elements with class="new_window" (*** do NOT specify <a> only as <area> can also be used ***)
			$("a.new_window, area.new_window").each( function() {
				// update the title string
				this.title ? this.title += " (this link will open in a new browser window)" : this.title = "This link will open in a new browser window";
				$(this).click( function() {
					Behaviour.popup(this.href);
					return false;
					});
				});
				
			if (Arcadia.debugMode) Util.debug("Behaviour.addTargets", true);	
				
			},
						
		/**
		 * Spawns a new browser window and loads the required URL.
		 * This needs to be amended to either configure via the Brand{} Object or via inline rel attributes.
		 * @param {String} url The URL to launch in the new window.
		 */
		popup : function(url) {
			// declare width and height variables
			var w, h; 
			// detail view
			if (url.toLowerCase().match("/detailview/index.html")) w = 640, h = 670;
			// specific dimensions for multimap urls
			else if (url.toLowerCase().match("multimap.com")) w = 800, h = 460;
			// specific checkout urls
			else if (url.toLowerCase().match("checkout_popups")) w = 835, h = 635;
			// specific settings for topman crisis urls
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/topman/2006/pages/crisis/crisis.html")) w = 700, h = 520;
			// specific settings for topman fratellis window
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/topman/2006/pages/fratellis/fratellis.html")) w = 708, h = 556;
			// specific settings for topman register window
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/topman/2006/pages/fashionably/fashionablyregistration.html")) w = 690, h = 417;
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/topman/2006/pages/250card")) w = 700, h = 430;
			// Miss S
			else if (url.toLowerCase().match("arcadiashops.co.uk/promostores/miss/2004/signup")) w = 670, h = 762;
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/miss/recruitment/pages/new_stores.html")) w = 770, h = 654;			
			// DP
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/arcadia/giftvoucher/splash.html")) w = 790, h = 470;
			else if (url.toLowerCase().match("voucherexpress.co.uk/dorothyperkins")) w = 700, h = 420;
			else if (url.toLowerCase().match("portal.prepaytec.com/arcaccount/enquire?brand=dorothyperkins")) w = 700, h = 420;	
			else if (url.toLowerCase().match("portal.prepaytec.com/arcaccount/registration.jsp?brand=dorothyperkins")) w = 700, h = 420;	
			// (Topshop)
			else if (url.toLowerCase().match("f.chtah.com/s/18/911110775/topshop_registration.html")) w = 485, h = 600;
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/tops/pages/popups/form1/index.html")) w = 465, h = 650;
			else if (url.toLowerCase().match("/popups/christmas_stores.html")) w = 340, h = 480;
			else if (url.toLowerCase().match("/popups/terms_and_conditions.html")) w = 530, h = 430;
			else if (url.toLowerCase().match("/unique_show_popup/unique_show_flash.html")) w = 340, h = 265;
			else if (url.toLowerCase().match("/newyorkmap/newyorkmap.html")) w = 745, h = 394;
			else if (url.toLowerCase().match("/popups/km_store_list.html")) w = 500, h = 380;
			else if (url.match("f.chtah.com/s/9/1941655062/Christopher_Kane.html")) w = 436, h = 540;
			else if (url.match("f.chtah.com/s/9/1941655062/Windreamdresses.html")) w = 454, h = 816;
			
			// Wallis
			else if (url.toLowerCase().match("wallis_newsletter/index.html")) w = 745, h = 425;
			else if (url.toLowerCase().match("newsletter_popup/privacy_policy.html")) w = 830, h = 640;
			else if (url.toLowerCase().match("/vat_popup/vat_popup.html")) w = 400, h = 550;
			else if (url.toLowerCase().match("/popups/christmas_delivery.html")) w = 400, h = 375;
			
			// Evans
			else if (url.toLowerCase().match("http://www.voucherexpress.co.uk/evans/") || 
				url.toLowerCase().match("http://www.evans.co.uk/cgi-bin/topups.cgi") ||
				url.toLowerCase().match("https://portal.prepaytec.com/arcaccount/enquire?brand=evans") ||
				url.toLowerCase().match("https://portal.prepaytec.com/arcaccount/registration.jsp?brand=evans")) w = 730, h = 670;
			// specific settings for burton card urls
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/burton/gift_card/index.html")) w = 740, h = 480;
			// burton newsletter 
			else if (url.toLowerCase().match("arcadiashops.co.uk/promostores/burton/2007/pages/newsletter/index_new.html")) w = 640, h = 640;
			// specific settings for voucher express urls
			else if (url.toLowerCase().match("voucherexpress.co.uk")) w = 800, h = 600;
			// specific settings for prepaytec
			else if (url.toLowerCase().match("portal.prepaytec.com")) w = 660, h = 450;
			// topman
			else if (url.toLowerCase().match("arcadiagroup.co.uk/promostores/topman/forms/nme")) w = 688, h = 968;
			else if (url.toLowerCase().match("f.chtah.com/s/22/1186111932/topman_signup.html")) w = 492, h = 486;
			else if (url.toLowerCase().match("arcadia.peoplebank.com/pbank/owa/arcadia.topshoptopmancategories")) w = 630, h = 374;
			else if (url.match("/flash_content/music_player/topManPlayer.html")) w = 403, h = 155;
			
			
			// ProductDisplay large image display
			else if(url.toLowerCase().match("productlargerimagedisplay")) w = 620, h = 520;
			
			// build window attributes based on window specs above if required
			var attr = w ? "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=yes,resizable=yes" : "toolbar=yes,location=yes,status=yes,menubar=yes,scrollbars=yes,resizable=yes";
			// temporary DP override for scrollbars
			if (url.toLowerCase().match("www.plantmoretrees.net")) attr = "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes";	
			// temporary TM override for scrollbars on music player
			if (url.match("/flash_content/music_player/topManPlayer.html")) attr = "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=no,resizable=no";		
			// temporary TS override for scrollbars
			if (url.toLowerCase().match("/unique_show_popup/unique_show_flash.html")) attr = "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=no,resizable=no";		
			if (url.toLowerCase().match("/newyorkmap/newyorkmap.html")) attr = "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=no,resizable=no";
			if (url.toLowerCase().match("/popups/km_store_list.html")) attr = "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=no,resizable=no";
			if (url.match("f.chtah.com/s/9/1941655062/Christopher_Kane.html")) attr = "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=no,resizable=no";
			// temporary WL override on scrollbars
			if (url.toLowerCase().match("/vat_popup/vat_popup.html")) attr = "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=no,resizable=no";
			if (url.toLowerCase().match("/popups/christmas_delivery.html")) attr = "width=" + w + ",height=" + h + ",screenX=100,screenY=100,scrollbars=no,resizable=no";		
			// open url in new window, focus and return false to cancel underlying link element action
			var win = window.open(url, "Arcadia_popup", attr);
			// focus on the window in case it's already open
			win.focus();
			},
			
		/**
		 * Loads the FormValidation{} file if any forms are present with the className "validate".
		 * Consider deprecating in favour of jQuery Validate plugin
		 */
		addFormValidation : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.addFormValidation");
			
			if ($("form.validate").length) $.getScript("/javascript/behaviour/form_validation.js");			
			
			if (Arcadia.debugMode) Util.debug("Behaviour.addFormValidation", true);
			
			},	
		
		/**
		 * Loads the Ajax{} file if div elements are present with the className "ajax_wrapper".
		 */
		initAjax : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initAjax");

			if ($("div.ajax_wrapper").length) $.getScript("/javascript/behaviour/ajax.js");
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initAjax", true);
			
			},
			
		/**
		 * Loads the SwitchFeature{} file if elements are present with the className "switch_feature".
		 */
		initSwitchFeatures : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initSwitchFeatures");
			
			if ($(".switch_feature").length) $.getScript("/javascript/behaviour/switch_feature.js");	
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initSwitchFeatures", true);
			
			},
		
		/**
		 * Loads the ContentTabs{} file if elements are present with the className "content_tabs".
		 */	
		initContentTabs : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initContentTabs");
			
			if ($(".content_tabs").length) $.getScript("/javascript/behaviour/content_tabs.js");
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initContentTabs", true);
			
			},
		
		/**
		 * Loads the relevant scroller file if elements are present with the following classNames:
		 * "basic_scroller" loads BasicScroller{}. Deprecated in favour of CycleContent{}.
		 * "advanced_scroller" loads AdvancedScroller{}. Deprecated in favour of NewScroller{}.
		 * "new_scroller" loads NewScroller{}.
		 */
		initContentScrollers : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initContentScrollers");
			
			if ($(".basic_scroller").length) $.getScript("/javascript/behaviour/basic_scroller.js");
			if ($(".new_scroller").length) $.getScript("/javascript/behaviour/new_scroller.js");
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initContentScrollers", true);
			
			},
		
		/**
		 * Loads the CycleContent{} file if elements are present with the className "cycle_content".
		 */	
		initContentCycles : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initContentCycles");
			
			if ($(".cycle_content").length) $.getScript("/javascript/behaviour/cycle_content.js");
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initContentCycles", true);
			
			},
		
		/**
		 * Clears the search box value when a user focuses on the element.
		 */
		clearSearchField : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.clearSearchField");
			
			$("#searchtxt").click( function() {
				this.value = "";
				});
			
			$('#headersubsection form').submit( function() { 
					if($('input#searchtxt').val() == ""){
						return false;
					}
					else {
						return true;
					}
			});
			
			if (Arcadia.debugMode) Util.debug("Behaviour.clearSearchField", true);
			
			},
			
		/**
		 * Toggles the visibility of hidden elements within an element with the className "toggle_detail".
		 * Refer to Wiki page for full details.
		 */
		initToggleDetail : function() {
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initToggleDetail");
			
			if (! $(".toggle_detail").size()) return;
			// load easing plugin if necessary and bind events
			if (typeof jQuery.easing.easeInOutQuad == "undefined") $.getScript("/javascript/jquery/jquery.easing.js", Behaviour.bindToggleDetailEvents);
			else Behaviour.bindToggleDetailEvents();	
			
			if (Arcadia.debugMode) Util.debug("Behaviour.initToggleDetail", true);
			
			},
		
		/**
		 * Binds toggle detail events to elements
		 */
		bindToggleDetailEvents : function() {
			$(".toggle_detail").bind("mouseenter", function() {
				$(this).addClass("detail_active").find(".detail").slideDown(200, "easeOutQuad");
				});
			$(".toggle_detail").bind("mouseleave", function() {
				$(this).removeClass("detail_active").find(".detail").slideUp(200, "easeOutQuad");
				});	
			},
			
		/**
		 * If the CSR interface is in place, listens for ctrl + s combination and focuses on search text field if triggered
		 * Adapted from http://www.arraystudio.com/as-workshop/disable-ctrl-n-and-other-ctrl-key-combinations-in-javascript.html
		 */
		addCsrSearchFocus : function() {

			// if the csr interface is in place...
			if ($("#csformloginreset").size()) {
				
				// bind a keydown event to the window
				$(document).bind("keydown", function(e) {
					 
					 var key, isCtrl;
	
						// check if the ctrl key has been pressed
						if (window.event) { // IE
							key = window.event.keyCode;
							if (window.event.ctrlKey) isCtrl = true;
							else isCtrl = false;
							}
						else { // firefox
							key = e.which;
							if (e.ctrlKey) isCtrl = true;
							else isCtrl = false;
							}
		
						// if ctrl + s is pressed focus on the search form field
						if (isCtrl && String.fromCharCode(key).toLowerCase() == "s") {
								$("#searchtxt").focus().val("");
								return false; // cancel default browser save behaviour
								}
					 
					 });
					
				}
				
			}
			
		};
		
	var CMS = {
		
		/**
		 * Initiate all cms functions.
		 */
		init : function() {	
		
			if (Arcadia.debugMode) Util.debug("CMS.init");

			// init all page update functionality once all page assets are loaded
			$(window).load(CMS.initUpdatePageContent);
			
			if (Arcadia.debugMode) Util.debug("CMS.init", true);
					
			},
		
		/**
		 * Performs the equivalent of a SwitchContent function on a CMS page
		 * Works on a click event by default but can be performed on mouseover if overwridden 
		 * by class=onmouseover on the wrapper markup
		 * Use this only once all content is available in the browser (ie via Util.addEvent() rather than Arcadia.init()
		 */
		initUpdatePageContent : function() { 
		
			if (Arcadia.debugMode) Util.debug("CMS.init");

			$(".cms_update_page").each( function() {

				var wrapper = $(this);
				// default event is click but overriden if wrapper has class mouseover
				// revert activates mouseout resetting of content
				var eventType = "click";
				var revert = false;
				if (wrapper.hasClass("mouseover")) eventType = "mouseover"
				if (eventType == "mouseover" && wrapper.hasClass("mouseout")) revert = true;
				
				// get source and target wrappers
				var componentSource = wrapper.find(".component_source");
				var componentTarget = wrapper.find(".component_target");

				// quit if no source or target markup found
				if (componentSource.length != 1 || componentTarget.length != 1) return;
				
				var sourceLinks = componentSource.find("a");

				// bind switch function to each source link
				sourceLinks.bind(eventType, function() {
					// get the target id from the rel attribute of the link
					var targetId = this.rel || null;
					// quit if we don't have one
					if (targetId == null) return;
					// get the current active link and the element in the target that has a class matching the target id
					var currentTarget = componentTarget.find(".active");
					var newTarget = $('#' + targetId);
					// if the new target exists and is not the currently selected one, toggle the classes to make the new target active
					if (newTarget.length > 0 && newTarget != currentTarget) {
						currentTarget.removeClass('active');
						newTarget.addClass('active');
						}
					// cancel default event if this was a click event
					if (eventType == "click") return false;	
					});
				
				// quit if no mouseout is required
				if (! revert) return;
				
				// get the default target item and quit if we don't have one
				var defaultTarget = componentTarget.find(".default_view");
				if (! defaultTarget.length) return;
				
				// bind function to mouseout event to move active class to default element
				sourceLinks.mouseout( function() {
					componentTarget.find(".active").removeClass('active');
					defaultTarget.addClass('active');
					});
				
				});
				
			if (Arcadia.debugMode) Util.debug("CMS.init", true);
				
			}
		
		};
