var neighborhoodAdjustments = 
	{
	'about': ['/collateral/customer-profiles/list'],
	'products': ['/collateral/hardware/comparison/'],
	'solutions': ['/collateral/hardware/technical-documentation/esrp-tech-docs.htm', '/collateral/solutions/']
	}
var navigationFolder = '/_admin/navigation';
var neighborhoodFiles = ['about','leadership','partners','products','services','solutions','support-training','themes'];
var labelClasses = [null, 'leftMenuTitle', 'leftMenuTitle2', 'leftMenuItemOuter', 'leftMenuItem', 'leftMenuItemInner'];
var containerClasses = [null, null, 'leftMenuOuter', 'leftMenuItem', 'leftMenuItemInner'];
var globalHostnames = ['www.emc.com', 'preview.emc.com', 'wip-oneemc.isus.emc.com', 'stage.emc.com', 'preview-stage.emc.com', 'wip-stage-oneemc.isus.emc.com', 'dev.emc.com', 'us.emc.com', 'live.emc.com'];
var localHostnames = [];
var navHttpRequest = null;
var navigationTree = null;
var neighborhoodTree = null;
var neighborhoodName = null;
var localization1 = null;
var localization2 = null;
var navigationState = 0;
var fallbackLevels = 0;
var loadingXML = false;
var vanityMode = false;
var folderRegExp = new RegExp('^/?([^/]+).*');
// Character replacements for sorting purposes
var sortReplacements = 'à:a~,â:a,á:a~,ã:a~,ä:ae,è:e~,é:e~,ê:e,ë:e,î:i,ï:i,í:i~,ñ:n~,ó:o~,õ:o~,ô:o,œ:oe,ö:oe,ù:u~,ú:u~,û:u,ü:ue,ÿ:y,ç:c~,ß:ss';
var sortReplacementArray = [];

var parts = sortReplacements.split(',');
for (var i=0, l=parts.length; i<l; ++i)
	sortReplacementArray.push(parts[i].split(':'));

// Return name of the neighborhood for the given href
function getNeighborhoodName(href)
	{			
	var i, l;

	var name = null;

	// priority 1: URL parameter
	var searchPos = href.indexOf('?');
	if (searchPos != -1)
		{
		var parameters = href.substr(searchPos+1).split('&');
		for (i=0, l=parameters.length; i<l; ++i)
			if (parameters[i].indexOf('neighborhood=') == 0)
				return parameters[i].substr(13);
		}
	// priority 2: variable on page
	if (typeof neighborhood != 'undefined')
		return neighborhood;
	// priority 3: global neighborhood adjustments
	for (var adjustedNeighborhood in neighborhoodAdjustments)
		for (i=0, l=neighborhoodAdjustments[adjustedNeighborhood].length; i<l; ++i)
			if (href.indexOf(neighborhoodAdjustments[adjustedNeighborhood][i]) == 0)
				return adjustedNeighborhood;
	// priority 4: name of top level folder
	return href.replace(new RegExp('^/?([^/]+).*'), '$1');
	}

// Return path to the navigation file for the given neighborhoodName
function getNavigationFile(neighborhoodName)
	{
	if (!inArray(neighborhoodFiles, neighborhoodName))
		neighborhoodName = 'other';
	return navigationFolder+'/'+neighborhoodName+'.xml';
	}

// Extract neighborhood tree from global navigationTree and return neighborhood root node
function getNeighborhood(neighborhoodName)
	{
	var folder, i, l;
	
	if (!neighborhoodName)
		return null
	var neighborhoods = navigationTree.getElementsByTagName('neighborhood');
	for (i=0, l=neighborhoods.length; i<l; ++i)
		{
		folder = neighborhoods[i].getAttribute('folder');
		if (folder && (folder.replace(folderRegExp, '$1') == neighborhoodName))
			return neighborhoods[i];
		}
	// No neighborhood found
	if (inArray(neighborhoodFiles, neighborhoodName))
		return navigationTree;
	return null;
	}

// Modify global neighborhoodTree according to the <alter>, <insert>, and <remove> tags found in localization.
// If restrictFallback is true, also remove all <menuitems> with restrict_fallback="true" attribute. 
function localizeNeighborhood(localization, restrictFallback)
	{
	// These variables get initialized multiple times but we want to define them only once
	var i, j, k, l, m, n, href, id, name, folder, position, nodes, removeNodes, alterNodes, insertNodes, targetNodes, targetNode, referenceNode, alterNode, insertNode;
	
	var hasRules = false;
	if (localization)
		{
		removeNodes = localization.getElementsByTagName('remove');
		alterNodes = localization.getElementsByTagName('alter');	
		insertNodes = localization.getElementsByTagName('insert');
		if (removeNodes.length + alterNodes.length + insertNodes.length > 0)
			hasRules = true;
		}

	if (neighborhoodTree && (hasRules || restrictFallback))
		nodes = neighborhoodTree.getElementsByTagName('menuitem');
		
	if (nodes && hasRules)
		{
		// We have some rules, so let's build the maps
		var hrefMap = {};
		var idMap = {};
		var nameMap = {};	
		
		for (i=0, l=nodes.length; i<l; ++i)
			{
			href = nodes[i].getAttribute('href');
			if (href)
				{
				if (!hrefMap[href])
					hrefMap[href] = [];
				hrefMap[href].push(nodes[i]); 
				}
			id = nodes[i].getAttribute('id');
			if (id)
				{
				if (!idMap[id])
					idMap[id] = [];
				idMap[id].push(nodes[i]);
				}
			name = nodes[i].getAttribute('name');
			if (name)
				{
				if (!nameMap[name])
					nameMap[name] = [];
				nameMap[name].push(nodes[i]);
				}
			}
		}
		
	// <alter> attributes of menuitems
	if (nodes && alterNodes)
		for (i=0, l=alterNodes.length; i<l; ++i)
			{
			alterNode = alterNodes[i];
			href = alterNode.getAttribute('search_href');
			id = alterNode.getAttribute('search_id');
			name = alterNode.getAttribute('search_name');
			if (hrefMap[href] || idMap[id] || nameMap[name])
				{
				targetNodes = (hrefMap[href] ? hrefMap[href] : (idMap[id] ? idMap[id] : nameMap[name]));
				for (j=0, m=targetNodes.length; j<m; ++j)
					for (k=0, n=alterNode.attributes.length; k<n; ++k)
						targetNodes[j].setAttribute(alterNode.attributes[k].nodeName, alterNode.attributes[k].nodeValue);
				}
			}
	
	// Restrict fallback
	if (nodes && restrictFallback)
		for (i=0, l=nodes.length; i<l; ++i)
			if (nodes[i].getAttribute('restrict_fallback') == 'true')
				setAttributeInSubTree(nodes[i], 'is_removed', 'true');
	
	// <remove> unwanted menuitems
	if (nodes && removeNodes)
		for (i=0, l=removeNodes.length; i<l; ++i)
			{
			href = removeNodes[i].getAttribute('search_href');
			id = removeNodes[i].getAttribute('search_id');
			name = removeNodes[i].getAttribute('search_name');
			if (href && hrefMap[href])
				for (j=0, m=hrefMap[href].length; j<m; ++j)
					setAttributeInSubTree(hrefMap[href][j], 'is_removed', 'true');
			else if (id && idMap[id])
				for (j=0, m=idMap[id].length; j<m; ++j)
					setAttributeInSubTree(idMap[id][j], 'is_removed', 'true');
			else if (name && nameMap[name])
				for (j=0, m=nameMap[name].length; j<m; ++j)
					setAttributeInSubTree(nameMap[name][j], 'is_removed', 'true');
			}
		
	// <insert> additional menuitems 
	if (insertNodes)
		for (i=0, l=insertNodes.length; i<l; ++i)
			{
			targetNodes = null;
			insertNode = insertNodes[i];
			folder = insertNode.getAttribute('search_neighborhood');
			if (folder)
				{
				if (folder.replace(folderRegExp, '$1') == neighborhoodName)
					{
					if (!neighborhoodTree && navigationTree)	// new neighborhood
						{
						var siteConfiguration = navigationTree.getElementsByTagName('site_configuration');
						if (siteConfiguration.length)
							{
							neighborhoodTree = navigationTree.createElement('neighborhood');
							siteConfiguration[0].appendChild(neighborhoodTree);	
							}
						}		
					targetNodes = [neighborhoodTree];
					position = 'top';
					}
				}
			else if (nodes)
				{
				href = insertNode.getAttribute('search_href');
				id = insertNode.getAttribute('search_id');
				name = insertNode.getAttribute('search_name');
				position = insertNode.getAttribute('position');
				targetNodes = (hrefMap[href] ? hrefMap[href] : (idMap[id] ? idMap[id] : (nameMap[name] ? nameMap[name] : null)));
				}
			if (targetNodes)
				for (j=0, m=targetNodes.length; j<m; ++j)
					{
					targetNode = targetNodes[j];
					referenceNode = targetNode.firstChild;	// insert as first child per default
					if (position == 'bottom')
						referenceNode = null;				
					else if (position == 'before')
						{
						referenceNode = targetNode;
						targetNode = targetNode.parentNode;
						}				
					else if (position == 'after')
						{
						referenceNode = targetNode.nextSibling;
						targetNode = targetNode.parentNode;
						}					
					for (k=0, n=insertNode.childNodes.length; k<n; ++k)
						if (insertNode.childNodes[k].nodeType == 1)	// only insert element nodes
							targetNode.insertBefore(insertNode.childNodes[k].cloneNode(true), referenceNode);
					}
			}
	}

// Extract menu tree for the provided URL from global neighborhoodTree and return menu root node
function getMenu(url)
	{
	var i, j, l, m, href, baseHref, parentFolder, nextMenuNode, peerNodes, childNodes, suppressPeers;
	
	var hrefMap = {};
	var baseHrefMap = {};
	var removedHrefMap = {};
	var parameterRegExp = new RegExp('/$|/?(\\?|#).*$');
	var indexRegExp = new RegExp('/index\\.(esp|html?)*$');
	
	var nodes = neighborhoodTree.getElementsByTagName('menuitem');	
	for (j=0, m=nodes.length; j<m; ++j)
		{
		href = nodes[j].getAttribute('href');
		if (!href || (href.charAt(href.length-1) == '*'))
			nodes[j].setAttribute('label_only', 'true');
		if (href)
			if ((nodes[j].getAttribute('is_removed') == 'true') && !removedHrefMap[href])
				removedHrefMap[href] = nodes[j];
			else if (!hrefMap[href])
				{
				hrefMap[href] = nodes[j];
				baseHref = href.replace(parameterRegExp, '');
				if ((baseHref != href) && !baseHrefMap[baseHref])
					baseHrefMap[baseHref] = nodes[j];
				baseHref = baseHref.replace(indexRegExp, '');					
				if ((baseHref != href) && !baseHrefMap[baseHref])
					baseHrefMap[baseHref] = nodes[j];
				}
		}
	// Append hrefs without parameters and hrefs without index.htm
	for (var href in baseHrefMap)
		if (!hrefMap[href])
			hrefMap[href] = baseHrefMap[href];
	// Append removed menuitems as we want to fall back to them if we don't have anything else
	baseHrefMap = {};	// Empty baseHrefMap
	for (var href in removedHrefMap)
		if (!hrefMap[href])
			{
			hrefMap[href] = removedHrefMap[href];
			baseHref = href.replace(parameterRegExp, '');
			if ((baseHref != href) && !baseHrefMap[baseHref])
				baseHrefMap[baseHref] = removedHrefMap[href];
			baseHref = baseHref.replace(indexRegExp, '');
			if ((baseHref != href) && !baseHrefMap[baseHref])
				baseHrefMap[baseHref] = removedHrefMap[href];
			}
	// Append removed hrefs without parameters 
	for (var href in baseHrefMap)
		if (!hrefMap[href])
			hrefMap[href] = baseHrefMap[href];
	
	// Find best matching href in menu tree
	var selectedNode = null;
	var isDirectHit = true;
	var baseHref = url.replace(parameterRegExp, '');
	var baseHrefNoIndex = baseHref.replace(indexRegExp, '');
	if (hrefMap[url])
		selectedNode = hrefMap[url]; 
	else if (hrefMap[baseHref])
		selectedNode = hrefMap[baseHref]; 
	else if (hrefMap[baseHrefNoIndex])
		selectedNode = hrefMap[baseHrefNoIndex]; 
	else
		{
		isDirectHit = false;
		do 
			{
			baseHref = baseHref.substring(0, baseHref.lastIndexOf('/'));
			parentFolder = baseHref.substr(baseHref.lastIndexOf('/'));
			if (hrefMap[baseHref])
				selectedNode = hrefMap[baseHref]; 
			else if (hrefMap[baseHref+'/'])
				selectedNode = hrefMap[baseHref+'/']; 
			else if (hrefMap[baseHref+'/*'])
				{
				selectedNode = hrefMap[baseHref+'/*']; 
				isDirectHit = true;
				}
			else if (hrefMap[baseHref+'/index.esp'])
				selectedNode = hrefMap[baseHref+'/index.esp'];
			else if (hrefMap[baseHref+'/index.htm'])
				selectedNode = hrefMap[baseHref+'/index.htm']; 
			else if (hrefMap[baseHref+'/'+parentFolder+'.htm'])
				selectedNode = hrefMap[baseHref+'/'+parentFolder+'.esp'];
			else if (hrefMap[baseHref+'/'+parentFolder+'.htm'])
				selectedNode = hrefMap[baseHref+'/'+parentFolder+'.htm'];
			else if (hrefMap[baseHref+'/local.htm'])
				selectedNode = hrefMap[baseHref+'/local.htm'];
			}
		while (!selectedNode && (baseHref.lastIndexOf('/') > 0));
		}
	if (!selectedNode)
		return null;
	if (isDirectHit)
		selectedNode.setAttribute('is_direct_hit', 'true');

	// Build menu tree corresponding to selected node
	var menu = navigationTree.createElement('leftmenu');
	menuNode = menu;
	var activeNodes = [selectedNode];
	var parentNode = selectedNode.parentNode;
	while (parentNode && (parentNode.nodeName == 'menuitem'))
		{
		parentNode.setAttribute('is_parent', 'true');
		activeNodes.unshift(parentNode);
		parentNode = parentNode.parentNode;
		}
	var activeNode = null; 
	for (i=0, l=activeNodes.length; i<=l; ++i)
		{
		if (i<l)
			{
			activeNode = activeNodes[i];
			peerNodes = activeNode.parentNode.childNodes;
			suppressPeers = ((i==0) || (i<l-3) || (activeNode.getAttribute('suppress_peers') == 'true') || (activeNode.parentNode.getAttribute('suppress_children') == 'true'));
			}
		else	// children
			{
			if (selectedNode.getAttribute('suppress_children') == 'true')
				break;
			activeNode = null;		
			peerNodes = selectedNode.childNodes;
			suppressPeers = false;
			}
		currentMenuNode = menuNode;		
		for (j=0, m=peerNodes.length; j<m; ++j)
			{
			peerNode = peerNodes[j];
			if (peerNode == activeNode)
				{
				currentMenuNode.appendChild(peerNode.cloneNode(false));
				menuNode = menuNode.lastChild;
				}
			else if (!suppressPeers && (peerNode.nodeType == 1) && (peerNode.nodeName == 'menuitem') && (peerNode.getAttribute('label_only') != 'true') && (peerNode.getAttribute('is_removed') != 'true'))
				currentMenuNode.appendChild(peerNode.cloneNode(false));
			}
		}
	return menu;
	}

// Change labels in menuTree according to the <rename> tags found in localization.
function localizeMenu(menuTree, localization)
	{
	var i, j, l, m, id, href, name, newName, wildcardLeft, wildcardRight, expression, replacement;

	if (!menuTree || !localization)
		return;
	
	// Store renamings in idMap, hrefMap, nameMap and regularExpressions Array
	var idMap = {};
	var hrefMap = {};
	var nameMap = {};
	var keepMap = {};
	var regularExpressions = [];
	
	// Escape special RegEx chars in search string
	var specialChars = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'];
	var specialCharsRegEx = new RegExp('(\\' + specialChars.join('|\\') + ')', 'g');

	var nodes = localization.getElementsByTagName('rename');
	for (i=0, l=nodes.length; i<l; ++i)
		{	
		id   = nodes[i].getAttribute('search_id');
		href = nodes[i].getAttribute('search_href');
		name = nodes[i].getAttribute('search_name');
		newName = nodes[i].getAttribute('name');
		if (!newName)
			{
			if (id)																							
				keepMap[id] = true;
			else if (href)																					
				keepMap[href] = true;
			else if (name)
				keepMap[name] = true;
			}
		else
			{
			if (id)																						// id -> 'B'
				idMap[id] = newName;
			else if (href)																				// href -> 'B'
				hrefMap[href] = newName;
			else if (name)
				{
				if ((name.charAt(0) != '*') && (name.charAt(name.length-1) != '*'))
					nameMap[name] = newName;															// 'A' -> 'B'
				else
					{
					wildcardLeft = (newName.charAt(0) == '*');
					if (wildcardLeft)
						newName = newName.substr(1);
					wildcardRight = (newName.charAt(newName.length-1) == '*');
					if (wildcardRight)
						newName = newName.substr(0, newName.length-1);

					expression = '^'+name+'$';							
					replacement = newName;
					if ((name.charAt(0) == '*') && (name.charAt(name.length-1) == '*'))					
						expression = name.substr(1, name.length-2).replace(specialCharsRegEx, '\\$1');	// '* A *' -> '* B *'
					else if (name.charAt(0) == '*')
						{
						expression = name.substr(1).replace(specialCharsRegEx, '\\$1')+'$';				// '* A' -> '* B'
						if (!wildcardLeft)								
							{
							expression = '(.*)'+expression;
							if (wildcardRight)
								replacement += '$1';													// '* A' -> 'B *'
							}
						}
					else // name.charAt(name.length-1) == '*'
						{									
						expression = '^'+name.substr(0, name.length-1).replace(specialCharsRegEx, '\\$1');	// 'A *' -> 'B *'
						if (!wildcardRight)
							{
							expression += '(.*)';
							if (wildcardLeft)
								replacement = '$1'+replacement;											// 'A *' -> '* B'
							}
						}
					regularExpressions.push([new RegExp(expression, 'g'), replacement]); 
					}
				}
			}
		}
	if (nodes.length)	// do we have at least one rename rule?
		{
		nodes = menuTree.getElementsByTagName('menuitem');
		for (i=0, l=nodes.length; i<l; ++i)
			{
			id   = nodes[i].getAttribute('id');
			href = nodes[i].getAttribute('href');
			name = nodes[i].getAttribute('name');
			if (!keepMap[id] && !keepMap[href] && !keepMap[name])
				{
				newName = name;
				if (idMap[id])
					newName = idMap[id];
				else if (hrefMap[href])
					newName = hrefMap[href];
				else if (nameMap[name])
					newName = nameMap[name];
				else if (newName)
					for (j=0, m=regularExpressions.length; j<m; ++j)
						newName = newName.replace(regularExpressions[j][0], regularExpressions[j][1]);
				if (newName != name)	
					{
					nodes[i].setAttribute('name', newName);
					if (!nodes[i].getAttribute('old_name'))
						nodes[i].setAttribute('old_name', name);				
					}
				}
			}
		}
	}

// Build HTML representation of menu tree and return it as string.
function menuToHtml(currentNode, level)
	{
	var i, j, l, m, compareName;
		
	var prefix = '';
	var result = '';
	var suffix = '';
	var childNodes = currentNode.childNodes;		
	var orderingOption = currentNode.getAttribute('ordering_option');
	if ((childNodes.length > 1) && (orderingOption && (orderingOption == 'alpha')))
		{
		childNodes = [];	// convert childNodes from HTMLCollection to Array in order to sort() them
		for (i=0, l=currentNode.childNodes.length; i<l; ++i)
			{
			compareName = currentNode.childNodes[i].getAttribute('name');
			compareName = compareName.toLowerCase();
			for (j=0, m=sortReplacementArray.length; j<m; ++j)
				compareName = compareName.replace(sortReplacementArray[j][0], sortReplacementArray[j][1]);
			currentNode.childNodes[i].setAttribute('compare_name', compareName);
			childNodes.push(currentNode.childNodes[i]);
			}
		childNodes.sort(compareNodes);
		}

	for (i=0, l=childNodes.length; i<l; ++i)
		result += menuToHtml(childNodes[i], level+1);

	var label = currentNode.getAttribute('name');
	if (level && label)
		{
		var labelOnly = (currentNode.getAttribute('label_only') == 'true');
		var href = currentNode.getAttribute('href');
		if (!href || (href.charAt(href.length-1) == '*'))
			labelOnly = true;
		var target = currentNode.getAttribute('target');
		var onClick = currentNode.getAttribute('onclick');
		if (!onClick)
			onClick = currentNode.getAttribute('onClick');	// allow both notations of onclick
		if (currentNode.getAttribute('is_direct_hit') == 'true')
			label = '<span class="leftMenuBlue">'+label+'</span>';		
		else if (!labelOnly)
			label = '<a href="'+href+'"'+(target ? ' target="'+target+'"' : '')+(onClick ? ' onClick="'+onClick+'"' : '')+'>'+label+'</a>';
		if ((currentNode.getAttribute('is_parent') == 'true') && (level > 2))
			label = '<div class="leftMenuItemWithArrows"><img class="verticalMiddle" src="/images/common/icon_left_nav_arrows.gif"/>'+label+'</div>';
		
		var labelIndex = Math.min(level, labelClasses.length-1);
		var containerIndex = Math.min(labelIndex, containerClasses.length-1);
		var labelClass = (labelClasses[labelIndex] ? labelClasses[labelIndex] : '');
		var tagName = (containerClasses[containerIndex-1] != null ? 'li' : 'div');
		
		prefix = '<'+tagName+' class="'+labelClass+'">'+label;
		if (containerClasses[containerIndex-1] != null)
			suffix = '</'+tagName+'>';	// close after submenu
		else
			prefix += '</'+tagName+'>';	// close after label
		if (result && (containerClasses[containerIndex] != null))
			{
			prefix += '<ul class="'+containerClasses[containerIndex]+'">';
			suffix = '</ul>' + suffix;
			}
		}
	return prefix + result + suffix;			
	}

// Return true if searchArray contains value and false otherwise
function inArray(searchArray, value) 
	{
	for (var i=0, l=searchArray.length; i<l; ++i)
		if (searchArray[i] == value)
			return true;
	return false;
	}

function compareNodes(nodeA, nodeB)	// Used for Array.sort() in menuToHtml()
	{
	var a = nodeA.getAttribute('compare_name');
	var b = nodeB.getAttribute('compare_name');
	return ((a < b) ? -1 : ((a > b) ? 1 : 0));
	}

function loadXML(fileName, stateHandler)
	{
	if (navHttpRequest && !loadingXML)
		{
		loadingXML = true;
		navHttpRequest.open('GET', fileName, true);
		navHttpRequest.setRequestHeader('Cache-Control', 'max-stale=600');	// Cache responses for 10 minutes
		navHttpRequest.onreadystatechange = stateHandler;
		navHttpRequest.send(null);
		}
	}

function setAttributeInSubTree(subTree, name, value)
	{
	if (subTree.nodeType == 1)
		subTree.setAttribute(name, value);
	var nodes = subTree.getElementsByTagName('menuitem');	
	for (var j=0, l=nodes.length; j<l; ++j)
		nodes[j].setAttribute(name, value);
	}

function createXMLHttpRequest()
	{
	var request = null;
	if (typeof XMLHttpRequest != 'undefined') 
		request = new XMLHttpRequest();
	if (!request) 
		{
		try 
			{ request  = new ActiveXObject("Msxml2.XMLHTTP"); } 
		catch(e) 
			{
			try { request  = new ActiveXObject("Microsoft.XMLHTTP");	}
			catch(e) { }
			}
		}
	return request;
	}

// Return value of the cookie with provided name
function getCookie(cname)
 	{
	var str=document.cookie;
	if (str.length > 0)
		{
		var pos=str.indexOf(cname+"=");
		if (pos != -1)
			{
			var start = pos+cname.length+1;
			var end = str.indexOf(';', start);
			if (end == -1) 
				end = document.cookie.length;
			return unescape(str.substring(start,end));
			}
		}
	return "";
	}


/*
This is the main function. In a nutshell it does the following:
1) Load first localization file
2) Identify neighborhood
3) Load corresponding navigation file (e.g. about.xml)
4) Load second localization file
5) Extract neighborhood tree from navigation file
6) Localize neighborhood tree except label translations
7) Extract menu tree corresponding to the current URL
8) Translate labels in menu tree
9) Build HTML according to menu tree and show it.

Author: Maximilian
*/
function mainLoop()	
	{
	var i, l, newNavigationFile;
	
	if (loadingXML && (navHttpRequest.readyState != 4))
		return;
	loadingXML = false;
	
	switch (navigationState)
		{
		case 0:
			++navigationState;
			if (typeof activeHref == 'undefined')
				activeHref = window.location.href;
			if ((activeHref.substr(0,7) == 'http://') || (activeHref.substr(0,8) == 'https://'))	// remove host part
				{
				activeHref = activeHref.substr(8);
				activeHref = activeHref.substr(activeHref.indexOf('/'));
				}
			navHttpRequest = createXMLHttpRequest();
			if (!inArray(globalHostnames, window.location.hostname))
				{
				fallbackLevels = 1;
				loadXML(navigationFolder+'/localization-1.xml', mainLoop);
				break;
				}
		case 1:
			++navigationState;
			if (fallbackLevels > 0)
				localization1 = navHttpRequest.responseXML;
			neighborhoodName = getNeighborhoodName(activeHref);
			if (typeof navigationFile == 'undefined')
				navigationFile = getNavigationFile(neighborhoodName);
			loadXML(navigationFile, mainLoop);
			break;
		case 2:
			++navigationState;
			neighborhoodName = getNeighborhoodName(activeHref);	
			newNavigationFile = getNavigationFile(neighborhoodName);
			if (newNavigationFile != navigationFile)
				{
				// The neighborhood has changed and the navigation file we loaded was the wrong one. Now load the right one.
				navigationFile = newNavigationFile;
				loadXML(navigationFile, mainLoop);
				break;
				}
		case 3:
			++navigationState;
			navigationTree = navHttpRequest.responseXML;	
			neighborhoodTree = getNeighborhood(neighborhoodName);
			if (!vanityMode && localization1)
				{
				var siteLocalizations = localization1.getElementsByTagName('site_localization');
				if (siteLocalizations.length)
					{
					var hostnames = siteLocalizations[0].getAttribute('hostnames');
					hostnames = (hostnames ? hostnames.replace(new RegExp('\\s+', 'g'), '') : '');
					if (hostnames)
						localHostnames = hostnames.split(',');
					}
				if (!inArray(localHostnames, window.location.hostname))
					{
					fallbackLevels = 2;
					// TODO: We might run into a race condition if localizeNeighborhood() takes longer than loadXML()
					loadXML(navigationFolder+'/localization-2.xml', mainLoop);
					localizeNeighborhood(localization1, true);
					break;
					}
				}
			if (fallbackLevels > 0)
				localizeNeighborhood(localization1, true);
		case 4:
			++navigationState;
			if (!vanityMode && (fallbackLevels > 1))
				localization2 = navHttpRequest.responseXML;
			if(fallbackLevels > 1)
				localizeNeighborhood(localization2, (localHostnames.length > 0));
			var vanityHref = getCookie('vanity');
			if (!neighborhoodTree && !vanityMode && vanityHref && (vanityHref != activeHref))
				{
				activeHref = vanityHref;		
				neighborhoodName = getNeighborhoodName(activeHref);
				newNavigationFile = getNavigationFile(neighborhoodName);
				if (newNavigationFile != navigationFile)	// We have to load another navigation file.
					{
					vanityMode = true;
					navigationFile = newNavigationFile;
					navigationState = 3;
					loadXML(navigationFile, mainLoop);
					break;
					}
				neighborhoodTree = getNeighborhood(neighborhoodName);
				if (fallbackLevels > 0)
					localizeNeighborhood(localization1, true);
				if (fallbackLevels > 1)
					localizeNeighborhood(localization2, (localHostnames.length > 0));
				}

			var outputElement = document.getElementById('contentLeftMenu');
			if (outputElement && neighborhoodTree)
				{
				var menuTree = getMenu(activeHref);
				localizeMenu(menuTree, localization1);
				localizeMenu(menuTree, localization2);
				if (menuTree && ((typeof suppressNavigation == 'undefined') || (suppressNavigation != true)))
					outputElement.innerHTML = menuToHtml(menuTree, 0);
				}
		}
	}

mainLoop();

