/*
	Combination of code by:
	- jshallard: www.human-it.com
	- FREESTYLE MENUS v1.0 RC (c) 2001-2004 Angus Turnbull, http://www.twinhelix.com
	- cookiecrook: http://cookiecrook.com/bugtests/menus/menus_backup.htm
*/

var isDOM=document.getElementById?1:0,
 isIE=document.all?1:0,
 isNS4=navigator.appName=='Netscape'&&!isDOM?1:0,
 isOp=self.opera?1:0,
 isDyn=isDOM||isIE||isNS4;

function getRef(i, p)
{
 p=!p?document:p.navigator?p.document:p;
 return isIE ? p.all[i] :
  isDOM ? (p.getElementById?p:p.ownerDocument).getElementById(i) :
  isNS4 ? p.layers[i] : null;
};

function getSty(i, p)
{
 var r=getRef(i, p);
 return r?isNS4?r:r.style:null;
};

if (!self.LayerObj) var LayerObj = new Function('i', 'p',
 'this.ref=getRef(i, p); this.sty=getSty(i, p); return this');
function getLyr(i, p) { return new LayerObj(i, p) };

function LyrFn(n, f)
{
 LayerObj.prototype[n] = new Function('var a=arguments,p=a[0],px=isNS4||isOp?0:"px"; ' +
  'with (this) { '+f+' }');
};
LyrFn('x','if (!isNaN(p)) sty.left=p+px; else return parseInt(sty.left)');
LyrFn('y','if (!isNaN(p)) sty.top=p+px; else return parseInt(sty.top)');

function addEvent(o, n, f)
{
 var a='addEventListener', h='on'+n;
 if (o[a]) return o[a](n, f, false);
 if (o[h])
 {
  o._c |= 0;
  var b = '_b' + (++o._c);
  o[b] = o[h];
 }
 o[h] = function(e)
 {
  e=e||self.event;
  var r = true;
  if (o[b]) r = o[b](e) != false && r;
  o._f=f;
  r = o._f(e) != false && r;
  return r;
 }
};

// *** CORE MENU OBJECT AND FUNCTIONS ***
// This is the base object that users create.
// It stores menu properties, and has a 'menus' associative array to store a list of menu nodes,
// and allow timeouts to refer to nodes by name (e.g. menuObject.menus.nodeName).
function FSMenu(myName, nested, cssProp, cssVis, cssHid)
{
	 this.myName = myName;
	 this.nested = nested;
	 // Some CSS settings.
	 this.cssProp = cssProp;
	 this.cssVis = cssVis;
	 this.cssHid = cssHid;
	 this.cssLitClass_A = '';
	 this.cssUnLitClass_A = ''; /* james added */
	 this.css_yupee_LI = 'yupeeLI'; /* james added */
	 this.cssLitClass_Parent_LI = 'hasSubMenuActive'; /* james added */
	 this.cssUnLitClass_Parent_LI = 'hasSubMenu'; /* james added */
	 
	 // The 'root' menu doesn't actually exist; it's an imaginary node that acts as a parent to
	 // other menu nodes and shows/hides them as necessary.
	 this.menus = { root: new FSMenuNode('root', this) };
	 this.menuToShow = [];
	 this.mtsTimer = null;
	 this.showDelay = 0;
	 this.switchDelay = 125;
	 this.hideDelay = 500;
};

FSMenu.prototype.show = function(mN) { with (this)
{
 // Set menuToShow to the function parameters, and a timer to call the root menu over() function if
 // no other menu node picks up the show event. Use a loop to copy values so we don't leak memory.
 menuToShow.length = arguments.length;
 for (var i = 0; i < arguments.length; i++) menuToShow[i] = arguments[i];
 clearTimeout(mtsTimer);
 mtsTimer = setTimeout(myName + '.menus.root.over()', 10);
}};

FSMenu.prototype.hide = function(mN) 
{ 
	with (this)
	{
 	// Clear the above timer and route the hide event to the appropriate menu node.
 	clearTimeout(mtsTimer);
	if (menus[mN]) menus[mN].out();
	}
};


// Each menu is represented by a FSMenuNode object.
// This is the node constructor function, with the properties and functions needed by that node.
// It's passed its own name in the menus[] array, and a reference to the parent FSMenu object.
function FSMenuNode(id, obj)
{
 	this.id = id;
 	this.obj = obj;
 	this.lyr = this.child = this.par = this.timer = this.visible = null;
 	this.args = [];
 	var node = this;


 	// These next over/out functions are an example of 'closures' in JavaScript.
 	// Since they're instantiated here, they can use the node's variables as if they were their own.

	 this.over = function(evt) 
	 { 
		 with (node) with (obj)
		 {
		  // Basically, over() gets called when the onmouseover event reaches the menu container, which might
		  // be a DIV or UL tag in the document. The event starts with a tag inside that container that calls
		  // FSMenu.show() and sets the menuToShow array. Browsers will then 'bubble' the event upwards, so
		  // it calls this function, which picks up the menuToShow array and creates/shows the appropriate
		  // menu node as a child of this menu node. Otherwise, if no menu nodes pick up the event, the
		  // default 'mtsTimer' timeout will call upon the 'root' menu node to show the menu.
		
		
		  // Ensure NS4 calls the show/hide function within this layer first.
		  if (isNS4 && evt && lyr.ref) lyr.ref.routeEvent(evt);
		  // Stop this menu hiding itself.
		  clearTimeout(timer);
		  clearTimeout(mtsTimer);
		
		  if (menuToShow.length)
		  {
			   // Pull information out of menuToShow[], and clear the default root.show() timeout.
			   var a = menuToShow, m = a[0];
			   if (!menus[m] || !menus[m].lyr.ref) menus[m] = new FSMenuNode(m, obj);
			   var c = menus[m];
			   
			   // Just clear the menuToShow array and return if we're "showing" the current menu...!
			   if (c == node)
			   {
			    	menuToShow.length = 0;
			    	return
			   }
			   // Otherwise, stop any impending show/hide of the child menu, and check if it's a new child.
			   clearTimeout(c.timer);
			   if (c != child && c.lyr.ref)
			   {
			    	// We have a genuinely new child menu to show. Give it some properties, set a timer to show it.
			    	// Again, try and avoid memory leaks, but copy over the a/menuToShow arguments.
			    	c.args.length = a.length;
			    	for (var i = 0; i < a.length; i++) c.args[i] = a[i];
			    	// Decide which delay to use -- switchDelay if we already have a child menu, showDelay otherwise.
			    	var delay = child ? switchDelay : showDelay;
			    	c.timer = setTimeout('with(' + myName + ') { menus["' + c.id + '"].par = menus["' +
			     	node.id + '"]; menus["' + c.id + '"].show() }', delay ? delay : 1);
			   }
			   
		   // Try, try, try to avoid leaking memory...
		   menuToShow.length = 0;
	  	}
		
	  	// For non-nested menus, mimic event bubbling.
	  	if (!nested && par) par.over();
	 }
};
	
	 this.out = function(evt) { with (node) with (obj)
	 {
	  	// Basically the same as over(), this cancels impending events and sets a hide timer.
	  	if (isNS4 && evt && lyr && lyr.ref) lyr.ref.routeEvent(evt);
	  	clearTimeout(timer);
	  	timer = setTimeout(myName + '.menus["' + id + '"].hide()', hideDelay);
	  	if (!nested && par) par.out();
	 }
};


 // Finally, now we have created our menu node, get a layer object for the right ID'd element
 // in the page, and assign it onmouseout/onmouseover events.
 if (id != 'root') 
 	with (this) with (lyr = getLyr(id)) if (ref)
 	{
  		if (isNS4) ref.captureEvents(Event.MOUSEOVER | Event.MOUSEOUT);
  		addEvent(ref, 'mouseover', this.over);
  		addEvent(ref, 'mouseout', this.out);
 	}
};



FSMenuNode.prototype.show = function() 
{ 
	with (this) with (obj)
	{
 		if (!lyr || !lyr.ref) 
			return;
		
		 // This is called to show the menu node of which it's a method.
		 // It sets the parent's child to this, and hides any existing children of the parent node.
		 if (par.child && par.child != this) 
		 	par.child.hide();
		 par.child = this;
		
		 // This is the positioning routine, it can be deleted if you're not using it.
		 // It pulls values out of the stored args[] array, and uses the page.elmPos function in the
		 // cross-browser code to find the pixel position of the parent item + menu.
		 var offR = args[1];
		 var offX = args[2];
		 var offY = args[3];
		 var lX = 0, lY = 0;
		 var doX = ''+offX!='undefined';
		 var doY = ''+offY!='undefined';
		 
		 if (self.page && offR && (doX||doY))
		 {
	  		with (page.elmPos(offR, par.lyr ? par.lyr.ref : 0))
			{
		 		lX = x, lY = y;
	  		}
		
			if (doX) lyr.x(lX + eval(offX));
	  		if (doY) lyr.y(lY + eval(offY));
		 }
		
		 // Highlight the triggering element, if any.
		 if (offR) 
		 	lightParent(offR, 1);
		
		 // Show the menu and trigger any 'onshow' events.
		 visible = 1;
		 if (obj.onshow) 
		 	obj.onshow(id);
		 
		 setVis(1);
	}
};

FSMenuNode.prototype.hide = function() 
{ 
	with (this) with (obj)
	{
	 // Same as show() above, but this clears the child/parent settings and hides the menu.
	
	 if (!lyr || !lyr.ref) 
	 	return;
	
	 // This is an NS4 hack as its mouse events are notoriously unreliable. Remove as needed.
	 if (isNS4 && self.isMouseIn && isMouseIn(lyr.ref)) 
	 	return show();
	 
	 // Dim the triggering element.
	 if (args[1]) 
	 	lightParent(args[1], 0);
	
	 // Hide the menu node element, and trigger an 'onhide' event if set.
	 if (lyr)
	 {
	  	visible = 0;
	  	if (obj.onhide) obj.onhide(id);
	  	setVis(0);
 	 }	

	 // Route the hide call through any child nodes, and clear the par/child references.
	 if (child) 
	 {	
		child.hide();
	 }
	 
	 if (par && par.child == this) 
	 {
	 	par.child = null;
	 }
	 par = null;
	
	}
};



// Here are the functions that show/hide each menu node, and highlight the parent of a node.
// Both are called from the show() and hide() functions of FSMenuNode above.
// Feel free to override with flashier effects/animations (see the "extras" file for one).

// This is passed a reference to the parent triggering element, and whether it is lit or not.
FSMenuNode.prototype.lightParent = function(elm, lit) 
{ 
	with (this) with (obj)
	{
		//add any styles to li if nessesary
		var li = elm.parentNode;
		//check we really have a li 
		if(li.nodeName.toLowerCase() == 'li')
		{
			// By default the cssLitClass_Parent_LI value is appended/removed to any existing class
			if (lit)
			{
				//li.className = (li.className?' ':'') + cssLitClass_Parent_LI;
				//changed to speed up
				li.className = 	cssLitClass_Parent_LI;
	 		}
			else 
			{
				//li.className = li.className.replace(new RegExp('\\s*' + cssLitClass_Parent_LI + '$'), cssUnLitClass_Parent_LI);
				//changed to speed up
				li.className = 	cssUnLitClass_Parent_LI;
			}
		}
				
		//add any styles to a if nessesary
//		if (cssLitClass_A || !isNS4) 
//		{
//	 		// By default the cssLitClass_A value is appended/removed to any existing class
//			if (lit)
//			{
//				elm.className += (elm.className?' ':'') + cssLitClass_A;
//	 		}
//			else 
//			{
//				elm.className = elm.className.replace(new RegExp('\\s*' + cssLitClass_A + '$'), '');
//			}
//		}
	}
};

// This is passed one parameter, whether it's shown or not (boolean).
FSMenuNode.prototype.setVis = function(sh) 
{ 
	with (this) with (obj)
	{
 		// Sets the show/hide CSS property of the menu node, to controls its display.
 		lyr.sty[cssProp] = sh ? cssVis : cssHid;
	}
};


//james - added from compact menu
FSMenu.prototype.activateMenu=function(id,subIText)
{
	with(this)
	{
		//browser compatibility check
		if(!isDOM)
			return;
		
		var a, ul, li;
		var mRoot = getRef(id)
		var nodes, count=1;
		var lilist = mRoot.getElementsByTagName('li');
		var lists = mRoot.getElementsByTagName('ul');
		
		/* james added */
		//set all li elements to standard class
		for(var i=0;i<lilist.length;i++)
		{
			li = lilist[i];
			
			if(li.nodeName.toLowerCase()=='li')
			{
				li.className = css_yupee_LI;
			}
		}
		/* finish james added */
		
		
		//loop through uls
		for(var i=0;i<lists.length;i++)
		{
			//get ul
			li=ul=lists[i];
			
			//loop through contents of ul
			while(li)
			{
				//look for list items
				if(li.nodeName.toLowerCase()=='li')
					break;
				
				li=li.parentNode
			}
			
			//if no list item found continue
			if(!li)
			{
				continue;
			}			
			//li found so now look for link content
			a=null;
			for(var j=0;j<li.childNodes.length;j++)
			{
				if(li.childNodes[j].nodeName.toLowerCase()=='a')
					a=li.childNodes[j];
			}
			
			//if no link content found continue
			if(!a)	
				continue;
			
			var menuID = myName+'-id-'+count++;
			
			if(ul.id)
				menuID=ul.id;
			else 
				ul.setAttribute('id',menuID);
			
			addEvent(a,'mouseover', new Function('e', myName+'.show("'+menuID+'",this)'));
			addEvent(a,'mouseout', new Function('e', myName+'.hide("'+menuID+'")'));
			
			
			//add any special text or class should be applied to the A tag of 
			//a menu item with children
			li.className = cssUnLitClass_Parent_LI;
						
			//add any special text or class should be applied to the A tag of 
			//a menu item with children
			//if(subIText)
			//{
			//	var subI = document.createElement ? document.createElement('span'):0;
			//	
			//	if(subI)
			//	{
			//							
			//		subI.appendChild(document.createTextNode(subIText));
			//		//set to any class that a text needs to be appended to
			//		//subI.className='subind';
			//		a.insertBefore(subI,a.firstChild)
			//	}
			//}
		}
	}
}
