Rvlt = (typeof(Rvlt)=="undefined"?{}:Rvlt); //Namespace Revelate

/*---------------------------
Rollover layers
---------------------------*/
Rvlt.Layers = function () {
	var VisibleLayer;

	this.ShowLayer = function (LayerID, sender){
		var theLayer = document.getElementById(LayerID);
		Rvlt.Utils.ClearTimer(theLayer, 'RollOutTimer');
		if (VisibleLayer != null && VisibleLayer != theLayer) {
			 _InternalHideLayer(VisibleLayer)();
		}
		if (theLayer.style.visibility != 'visible') {
			PositionLayer (theLayer, sender); //Note: 'this' refers to the sender here
			theLayer.style.visibility = 'visible';
		}
		VisibleLayer = theLayer;
	}
	
	this.HideLayer = function (LayerID) {
		var theLayer;
		if (LayerID == null) {
			theLayer = VisibleLayer;
		}
		else {
			theLayer = document.getElementById('LayerID');
		}
		if (theLayer != null) {
			theLayer.RollOutTimer = window.setTimeout(_InternalHideLayer(theLayer), 200);
		}
	}
	
	function _InternalHideLayer(theLayer){
		return function (){
			if (VisibleLayer == theLayer) {
				VisibleLayer = null;
			}
			theLayer.style.visibility = 'hidden';
		}
	}

	function PositionLayer (theLayer, theThumb) {				
		var OffsetX = -10;
		var OffsetY = 60;
		var theContainer = document.getElementById("PageContainer")
		var ContainerLeft = Rvlt.Utils.AbsoluteOffset(theContainer, 'Left'); 
		var ContainerWidth = theContainer.offsetWidth;
		var ContainerRight = ContainerLeft + ContainerWidth;
		var ThumbLeft = Rvlt.Utils.AbsoluteOffset(theThumb, 'Left');
		var ThumbTop = Rvlt.Utils.AbsoluteOffset(theThumb, 'Top');
		
		theLayer.style.left = GetPos (ThumbLeft, theThumb.offsetWidth, theLayer.offsetWidth,  ContainerLeft, ContainerRight, OffsetX) + "px"
		theLayer.style.top = GetPos (ThumbTop, theThumb.offsetHeight, theLayer.offsetHeight, Rvlt.Utils.getWinTop(), Rvlt.Utils.getWinBottom(), OffsetY) + "px"
	}
	
	function GetPos (SenderMin, SenderLength, TargetLength, MinPos, MaxPos, Offset) {
		var thePos = 0;
		if (SenderMin - MinPos <= (MaxPos - MinPos) / 2) {//Sender in first half of boundaries
			thePos = SenderMin + SenderLength - Offset;
			if (thePos + TargetLength > MaxPos) {//Further than max pos
				thePos = MaxPos - TargetLength; //-> Align at edge
			}
		}
		else {//Sender in second half of boundaries
			thePos = SenderMin - TargetLength + Offset;
		}
		if (thePos < MinPos){// Target larger than available space -> Align with min 
			thePos = MinPos;
		}
		
		return thePos;
	}
}

 
/**
 * @param   MenuID      	id of the Div which contains the Menu to be built
 * @param   MenuItems      	JSON array of menu items
 * @param   RolloverImages  [optional] Boolean: Do we switch menu images with an version with '_over' at the end;
MenuItems Format:
[
	{
		"Label" : "Home",
		"Url" : "http://eu.broxo.com" ,
		(optional) "SubNav" : [ {"Label" : "xyz", etc} ] 
	}
	or
	{
		"LinkHTML" : "<a href='http://eu.broxo.com'>European Store</a>",
		(optional) "SubNav" : [ {"Label" : "xyz", etc} ] 
	}
]	
 */ 
Rvlt.BuildMenu = function (MenuID, MenuItems, RolloverImages) {

	RolloverImages === false ? false : true;
	
	var MenuObj = document.getElementById(MenuID);
	var TopList = MenuObj.getElementsByTagName('li');
	if (RolloverImages) {
		PreloadTopImages(); 
	}
	MenuObj.onmouseover = MouseOverListener;
	MenuObj.onmouseout = MouseOutListener;

	// Build the nav. We could probably do without this initial loop if we built the entire menu in JS
	for (var i=0;i<TopList.length;i++) {
		TopList[i].ParentItem = MenuObj;
		if (MenuItems[i].SubNav != null) {
			TopList[i].SubNav = BuildLayer(MenuItems[i].SubNav, TopList[i], "horizontal"); 
		}
	}
	
	function BuildLayer (theNavArray, ParentItem, Tile) { //horizontal tile --> will display under the listitem. Otherwise next to it.
		Tile = Tile || "vertical";
		var theDiv = document.createElement('div');
		var theList = document.createElement('ul');
		var theListItem;

		for (var i=0;i<theNavArray.length;i++){
			theListItem = document.createElement('li');
			
			if (theNavArray[i].SubNav != null) {
				theListItem.SubNav = BuildLayer (theNavArray[i].SubNav, theListItem); 	
				theListItem.className = "WithSubNav";
			}
			
			if (theNavArray[i].LinkHTML != null){
				theListItem.innerHTML = theNavArray[i].LinkHTML;
			}
			else { //This might be a bad idea (Link HTML is more flexible)
				theListItem.innerHTML = '<a href="' + theNavArray[i].Url + '">' + theNavArray[i].Label + '</a>';
			}
			
			theListItem.ParentItem = theDiv;
			theList.appendChild(theListItem)
		}
		theDiv.appendChild(theList);
		theDiv.className = "NavLayer VerticalNav";
		theDiv.style.display = 'none';
		theDiv.ParentItem = ParentItem;
		theDiv.onmouseover = MouseOverListener;
		theDiv.onmouseout = MouseOutListener;
		theDiv.onclick = MouseClickListener;
		theDiv.Tile = Tile;
		document.body.appendChild(theDiv);
		return theDiv;
	}
	
	
	function toggleActive (ListItem, direction) { 
		var theImg = Rvlt.Utils.FindElementByTagName(ListItem, 'img', 'children'); 
		if (direction == 'on') {
			if (theImg != null && RolloverImages == true) theImg.src = theImg.src.indexOf('_over') > -1 ? theImg.src : theImg.src.replace('.gif','_over.gif');
			Rvlt.Utils.AddCssClass(ListItem, 'over');
		}
		else {
			if (theImg != null && RolloverImages == true) theImg.src = theImg.src.replace('_over','');
			Rvlt.Utils.RemoveCssClass(ListItem, 'over');
		}
	}
	
	function MouseOverListener(e) {
		var el = Rvlt.Utils.FindElementByTagName(Rvlt.Utils.GetEventTarget(e), 'li', 'parent');
		if (el != null) { 					//target contained in a list item
			Rollover(el);
		} 
		else if (this.ParentItem != null) { //'this.' refers to the owner of the event handler, i.e. the div layer
			Rollover (this.ParentItem); 	//keep the parent list item selected
		} 
	}
	
	function MouseClickListener(e) { 
		Rollout(this.ParentItem)();
	}
	
	function MouseOutListener (e){
		var el = Rvlt.Utils.FindElementByTagName(Rvlt.Utils.GetEventTarget(e), 'li', 'parent') || this.ParentItem; //'this.' = the div layer
		while (el != null) { 					
			el.RollOutTimer = window.setTimeout(Rollout(el), 200); 
			el = el.ParentItem;		//Also rollout the parents. If they are subsequently rolled over, they will be kept alive.
		}  
	}
	
	function Rollover (el) { //We only really need to rollover the li's, but we also do the div's to follow the lineage (li's are children of divs who are children of li's)
		var LeftPos = Rvlt.Utils.AbsoluteOffset(el, "Left");
		var TopPos =  Rvlt.Utils.AbsoluteOffset(el, "Top");
		if (el.ParentItem != null && el.ParentItem.CurrentActive != null && el.ParentItem.CurrentActive != el) {
			Rollout(el.ParentItem.CurrentActive)(); 					//Hide the currently visible menu immediately
		}
		Rvlt.Utils.ClearTimer(el, 'RollOutTimer'); 
		if (el.tagName.toLowerCase() == 'li') toggleActive(el, 'on'); 	//show active state
		if (el.SubNav != null) { 										//show child
			/*
				POSITIONING: 
				Some effort is made so that menu items do not end up off the screens, but
				some edge cases are not covered. For example a hypothetical third level would not know
				that it's parent is to the left of it's parent, so it would go right and cover it's grandad.
				A way to work around this would be to add a DisplayedRight property to the parent.
			*/
			if (el.SubNav.Tile == 'horizontal') { 									//'Horizontal' --> displays under the item
				if (LeftPos + el.SubNav.offsetWidth > Rvlt.Utils.winWidth) {					//Falls out of window
					LeftPos = LeftPos - el.SubNav.offsetWidth + el.offsetWidth; 	// --> Align with right edge of item
				}
				el.SubNav.style.top = TopPos + el.offsetHeight + 1 + "px";
				el.SubNav.style.left = LeftPos + "px";
			}
			else {																	//'Vertical' --> displays next to the item
				LeftPos = LeftPos + el.offsetWidth + 1;
				if (LeftPos + el.SubNav.offsetWidth > Rvlt.Utils.winWidth) { 					//Falls out of window
					LeftPos = LeftPos - el.offsetWidth - el.SubNav.offsetWidth - 2; //-- > display to the left of the item
				} 
				if (TopPos + el.SubNav.offsetHeight > Rvlt.Utils.winHeight){
					TopPos = Rvlt.Utils.winHeight - el.SubNav.offsetHeight;
				}
				el.SubNav.style.top = TopPos + "px";
				el.SubNav.style.left = LeftPos + "px";
			}
			el.SubNav.style.display = 'block';
		}
		if (el.ParentItem != null) {
			el.ParentItem.CurrentActive = el;
			Rollover (el.ParentItem); //Keep parents active
		}
	}
	
	function Rollout (el){
		return function () { //we return a function so it can be used on SetTimeout. To execute direct, call with (), so Rollout(el)();
			Rvlt.Utils.ClearTimer(el, 'RollOutTimer'); 
			if (el.tagName.toLowerCase() == 'li') toggleActive(el, 'off');
			if (el.CurrentActive != null) {
				Rollout(el.CurrentActive)();
			}
			if (el.SubNav != null) {
				el.SubNav.style.display = 'none';
			}
			if (el.ParentItem != null && el.ParentItem.CurrentActive == el) {
				el.ParentItem.CurrentActive = null;
			}
		}
	}
	
	function PreloadTopImages () {
		var imgArray = MenuObj.getElementsByTagName('img');
		var preLoadArray = [];
		for (var i=0;i<imgArray.length;i++) {
			preLoadArray[i] = new Image();
			preLoadArray[i].src = imgArray[i].src.replace('.gif','_over.gif');
		}
	}
}


/*---------------------------
Shared utilities (static functions)
---------------------------*/

Rvlt.Utils = {}

/**
 * Returns a single node, or the node itself if it has the tag name. 
 * If more than one child with that name is present, returns null.
 * Useful for: Event delegation
 * @param   el      		DOM object to to start with
 * @param   tagName         Name of tag to search for. Lowercase.
 * @param   searchFor       Accepts "parent" or "child"
 */
Rvlt.Utils.FindElementByTagName = function (el, tagName, searchFor) { //
	var ChildElements;
	if (el.tagName.toLowerCase() == tagName) {
		return el;
	}
	if (searchFor == "parent") {
		while (el != null && el.tagName.toLowerCase() != tagName) {
			el = el.parentNode.tagName != null ? el.parentNode : null;
		}
		return el;
	}
	else {
		ChildElements = el.getElementsByTagName(tagName);
		return ChildElements.length == 1 ? ChildElements[0] : null;
	}
}


/**
 * Finds next sibling of a particular tag
 * @param   el      		DOM object to to start with
 * @param   tagName         Name of tag to search for. Lowercase.
 */
Rvlt.Utils.FindNextSiblingByTagName = function (el, tagName) { //
	while (el.nextSibling != null) {
		if (el.nextSibling.tagName !=null && el.nextSibling.tagName.toLowerCase() == tagName) {
			return el.nextSibling;
		}
		else {
			el = el.nextSibling;
		}
	}
	return null;
}

/**
 * @param   e      			DOM Event
 */
Rvlt.Utils.GetEventTarget = function (e) { //Cross browser malarkey
	e = e || window.event;
	return e.target || e.srcElement;
}

/**
 * The "raison d'etre" of these functions is that an object can have
 * several classes seperated by a space in the className 
 * @param   el      		DOM element to add class to
 * @param   theClass        Class to be added (string)
 */
Rvlt.Utils.AddCssClass = function (el, theClass){
	el.className = el.className.indexOf(theClass) > -1 ? el.className : (el.className ? el.className + ' ' : '') + theClass;
}

/**
 * @param   el      		DOM element to add class to
 * @param   theClass        Class to be removed (string)
 */
Rvlt.Utils.RemoveCssClass = function (el, theClass){
	var classArray = el.className.split(' ');
	var classString = "";
	for (var i=0;i<classArray.length-1;i++) {
		if (classArray[i] != theClass) classString += classArray[i] + ' ';
	}
	el.className  = classString.substr(0, classString.length -1);
}

/**
 * @param   el      		HTML element to find offset f
 * @param   which       	 'Top' or 'Left' (case sensitive)
 * @return  int       		Returns position from edge of screen.
 */
Rvlt.Utils.AbsoluteOffset = function (el, which) { 
	return el.offsetParent ? el['offset' + which] + Rvlt.Utils.AbsoluteOffset(el.offsetParent, which) : el['offset' + which];
}

/** !! UNTESTED!!
 * @param   Coord      		'x' or 'y'
 * @param   e       	 	Event
 */
Rvlt.Utils.GetMousePos = function (Coord, e) {
	if (e.pageX || e.pageY) {
		return (Coord == 'x') ?  e.pageX : e.pageY; 
	}
	else if (e.clientX || e.clientY) {
		return (Coord == 'x') ? e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft : e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	}
}

/**
 * @param   el      		HTML element to clear timer of
 * @param   TimerName       Name of timer	
 */
Rvlt.Utils.ClearTimer = function (el, TimerName) {
	if (el[TimerName]!= null) {
		window.clearTimeout(el[TimerName]);
		el[TimerName] = null;
	}
}

/**
 * Cross browser window information
 */
Rvlt.Utils.getWinWidth = function () {return window.innerWidth || document.documentElement.clientWidth - 15; } //the -15 is to account for scrollbars
Rvlt.Utils.getWinLeft = function () {return window.pageXOffset || document.documentElement.scrollLeft;}
Rvlt.Utils.getWinRight = function () {return Rvlt.Utils.getWinLeft() + Rvlt.Utils.getWinWidth();}
Rvlt.Utils.getWinHeight = function () {return window.innerHeight || document.documentElement.clientHeight;}
Rvlt.Utils.getWinTop = function () {return window.pageYOffset || document.documentElement.scrollTop;}
Rvlt.Utils.getWinBottom = function () {return Rvlt.Utils.getWinTop() + Rvlt.Utils.getWinHeight();} 
	
Rvlt.Utils.SetCookie = function (Name, Value) {
	var date = new Date();
	date.setTime(date.getTime()+(365*24*60*60*1000)); // now + 1 year
	document.cookie = Name + "=" + Value + "; expires=" + date.toGMTString() + "; path=/";
	return true;
}	