//--------------------------------------------------------------------
// (c) Paragi 2005, written by Simon Riget at HTTP://www.Paragi.com
// Javascript Menues Version 0.82-Alpha
//
// You are free to use Javascript menues in your apps
// Please tell me if you have som improvements to this code
// The license to use this code are on the condition that a refferance to 
// HTTP://www.Paragi.com are plased on the site where it is used, where an
// external search engine can find it (usually a credit page)and that 
// copyrights are preserved. Otherwise the GNU Library GPL license apply.
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Note 1:
// All debug code below are marked with /*D*/ and should be 
//	removed for production systems.
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Note 2: 
// Many functions here use innerHTML as oppose to creating tags with
//	the DOM model. This is do to speed considerations, but it makes the 
//  code less object oriented.
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Firefox/IE
// FF dont take function foo.prototype.bar() use foo.prototype.bar=function()
//--------------------------------------------------------------------

//--------------------------------------------------------------------
// To do:
// - Make autoselect work with frames
// - Needs cleaning up and some rewriting 
//   (Make it all a part of one or two classes etc)
// - Submenushadow dosnt work
// - Add sound scheem
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Make global variables and classes
//--------------------------------------------------------------------
	
var jsmenu=Array();			// Array to store all menus
var jssubmenu=Array();	// Array containing activated submenus
var jssubmenu_tid;			// Generel timer. (Used to remove submenus)

// Menu class
function MenuClass(){
	this.TagId='';	  												// Id that identify the menu container
	this.Type=1;															// Future use. To select which function to use to display menu
	this.Action='location.href="#"';					// What to do when button is pressed. # will be replaced with whats in Item[1]
	this.SubMenuOnHover=true;									// Show submenu when hovering if true. else on select
	this.AutoSelected=true;										// Mark menu item as selected, when this pagename match menu item action.
	 																					// NB: Make it work with frames!!
	this.FloatingHints=true;									// Dispalys the hint at the cursor position in a nice little box
	this.StatusLineHints=false; 							// Dispalys the hint in the status line at the button of the window
	// Generic formatting
	this.SubmenuIconRight='4';								// Show arrow on buttons that activates submenus
	this.SubmenuIconDown='6';									// r,d = webdings: 4,6 windings: , , ,  , 
	this.SubIconInStatic=false;								// Show sumneu available icon in the the static menu items
	this.StylePrefix='menu';									// Set the prefix of style class names
	// Settings for static menu
	this.Orientation=0; 											// Display rows 0=vertical or 1=horisontal (menu bar)
	this.UniformWidth=true;										// If true; all buttons has the same width
	this.Dimensions=1; 												// Number of visable dimensions 1= menu bar 2= rows and columns
	this.RowSpacing=0;												// Space between columns in pixels. (Should be en css some where)	
	this.ColumnSpacing=0;											// Space between columns in pixels. (Should be en css some where)
	this.MenuBar=false;												// Buttons in a bar. only ends are terminated with ends.
	// Submenu settings
	this.SubmenuOrientation=0;								// Orientation of the submenu can be 0=down 1=horisontal 2=alternate
	this.SubmenuTimeout=100;									// Time out, time to  move mouse between submenu items
	this.Submenushadow=4;											// Make a semitransparent shadow behind the submenu (width)
	// data arrays 
	this.Items=Array();
	this.Images= new MenuImagesClass();
	// Internal variables set by build function
	this.container='';												// Pointer to menu container tag
	this.ItemWidth=0; 												// Used for uniform width
	this.SubmenuIconWidth=0;									// Used to calculate space to leave for submenu icons
	this.SubmenuIcon='';											// Character to use as submenu icon (Right or down)
	// Internal events (Functions)
	/*
	this.iselect=menu_iselect;
	this.ihover=menu_ihover;
	this.iunhover=menu_iunhover;
	*/
	//Programmer defined events (Functions)
	this.select='';
	this.hover='';
	this.unhover='';
}

// Menu image class
function MenuItemImagesClass(){
	// Button images in static menus
	this.Left='';
	this.Bg='';
	this.Right='';
	this.LeftHover='';
	this.BgHover='';
	this.RightHover='';
}
function MenuImagesClass(){
	this.Item =new MenuItemImagesClass();
	this.SubItem =new MenuItemImagesClass();
	// Surrounding graphics
	this.UpperLeft=''; 
	this.LowerLeft=''; 
	this.UpperRight=''; 
	this.LowerLeft=''; 
	this.top;					// top and bottom of vertical menus. (Both static and submenus?)
	this.botton;
}
// SubmenuClass
function SubmenuClass(tag_id,menu_id,parent_item_id){
	this.root_menu=jsmenu[menu_id];				// Referance to the menu object this submenu is a part of
																				// Use this, instead of the belowe, when posible
	this.active=false;
	this.timer_id=null;										// Timer identifyer uset to hide submenu when mouse is out
	this.container=null;									// Container node for displaying submenu
	this.tag_id=tag_id;										// Tag id for container
	this.parent_item_id=parent_item_id; 	// Id of menu item that holds the submenu
	this.menu_id=menu_id;									// ID of this submenu
	this.SubmenuIconWidth=0;							// Used to calculate space to leave for submenu icons
	this.SubmenuIcon='';									// Submeni icon to use
	this.MenuBar=false;										// Buttons in a bar. only ends are terminated with ends.
//	this.ItemWidth=0;
//	this.Orientation=0; 								// Display rows 0=vertical or 1=horisontal (menu bar)
//	this.UniformWidth=true;							// If true; all buttons has the same width (Horisontal only)
	this.FloatingHints=true;							// Dispalys the hint at the cursor position in a nice little box
	this.StatusLineHints=false; 					// Dispalys the hint in the status line at the button of the window
	this.StylePrefix=this.root_menu.StylePrefix;							// Set the prefix of style class names
}

// Function to return names of CSS class attributes and images used in static menu items
MenuClass.prototype.style_name= function (type){
	switch(type){
		case 'menu': return this.StylePrefix;
		case 'row': return this.StylePrefix+'_row';
		case 'item': return this.StylePrefix+'_item';
		case 'hover': return this.StylePrefix+'_hover';
		case 'selected': return this.StylePrefix+'_selected';
		case 'inactive': return this.StylePrefix+'_inactive';
		case 'label': return this.StylePrefix+'_label';
		case 'left': return this.StylePrefix+'_image_left';
		case 'right': return this.StylePrefix+'_image_right'
		case 'subicon': return this.StylePrefix+'_subicon';
		case 'subicon_h': return this.StylePrefix+'_subicon_hover';
		case 'image': return this.StylePrefix+'_img';
		default: 
// debug('style type:'+type+' not found'); return '';
	}
}

// Function to return names of CSS class attributes and images used in submenu items
SubmenuClass.prototype.style_name=function(type){
	switch(type){
		case 'menu': return this.StylePrefix+'_sub';
		case 'row': return this.StylePrefix+'_sub_row';
		case 'item': return this.StylePrefix+'_sub_item';
		case 'hover': return this.StylePrefix+'_sub_hover';
		case 'selected': return this.StylePrefix+'_sub_selected';
		case 'inactive': return this.StylePrefix+'_sub_inactive';
		case 'label': return this.StylePrefix+'_sub_label';
		case 'left': return this.StylePrefix+'_sub_image_left';
		case 'right': return this.StylePrefix+'_sub_image_right'
		case 'subicon': return this.StylePrefix+'_sub_subicon';
		case 'subicon_h': return this.StylePrefix+'_sub_subicon_hover';
		case 'image': return this.StylePrefix+'_sub_img';
		default:
//debug('style type:'+type+' not found');		return '';
	}
}

//--------------------------------------------------------------------
// Functions to access the menu classes
//--------------------------------------------------------------------
// Functions to access the menu class
function setMenu(id,item_name,val){
	eval('jsmenu['+id+'].'+item_name+'=val');
}
function getMenu(id,item_name){
	eval('return jsmenu['+id+'].'+item_name);
}
/* New functions:
MenuClass.prototype.set=function(item_name,val){
	eval('this.'+item_name+'=val');
}

MenuClass.prototype.get=function(item_name,val){
	eval('return this.'+item_name);
}
*/

// Functions to access images
// ! Include a path paramenter
function setMenuImages(){
	if(arguments<1) return;
	var path=arguments[1];
	if(path.length && path.charAt(path.length-1)!='/') path+='/';
	var ii=2;
	for(i in {'Bg':0,'Left':0,'Right':0,'BgHover':0,'LeftHover':0,'RightHover':0,'UpperLeft':0,'LowerLeft':0,'UpperRight':0,'LowerLeft':0}){
		if(arguments[ii]){
			jsmenu[arguments[0]].Images.Item[i]=new Image();
			jsmenu[arguments[0]].Images.Item[i].src=path+arguments[ii];
		}
		ii++;
		if(ii>=arguments.lenght) break;
	}
}

// ! Include a path paramenter
function setSubmenuImages(){
	if(arguments<1) return;
	var path=arguments[1];
	if(path.length && path.charAt(path.length-1)!='/') path+='/';
	var ii=2;
	for(i in {'Bg':0,'Left':0,'Right':0,'BgHover':0,'LeftHover':0,'RightHover':0,'UpperLeft':0,'LowerLeft':0,'UpperRight':0,'LowerLeft':0}){
		if(arguments[ii]){
			jsmenu[arguments[0]].Images.SubItem[i]=new Image();
			jsmenu[arguments[0]].Images.SubItem[i].src=path+arguments[ii];
		}
		ii++;
		if(ii>=arguments.lenght) break;
	}
}
function getMenuImages(id){ //Is this realy nessesary??
	var a;
	for(i in jsmenu[id].Images.Items)
		a[i]=jsmenu[id].Images.Items[i].src;
	for(i in jsmenu[id].SubImages.Items)
		a['Sub'+i]=jsmenu[id].SubImages.Items[i].src;
		return a;
}
	
//function menu_assign(menu) (copy)

// Copy sub objects aswell
MenuClass.prototype.Assign=function(menu){
    var i;
    for (i in menu){
			if(menu[i]=='object'){
				this.Assign(menu[i])
			}
			else	
				this[i] = menu[i];
		}	
}

//--------------------------------------------------------------------
// Functions to initialize the menu
// bool = menu_make(<tag_id>(string) [,<menu items>(Array)])
//--------------------------------------------------------------------
function menu_make(tag_id,items){
	var menu_id=jsmenu.length;
	// Attach menu to jsmenu array;
	jsmenu[menu_id]=new MenuClass();
	// Add Items and tag_id
	if(typeof(items=='object')) jsmenu[menu_id].Items=items;
	jsmenu[menu_id].TagId=tag_id;
	//Prepare to display menus on load (Once)
	// Brug _this=this; _this.init !!
	if(menu_id==0){
		if(window.attachEvent ) //IE4
			window.attachEvent('onload', menu_init, false);
		else if(window.addEventListener) //NS4
			window.addEventListener("load", menu_init, false);
		else if ( window.onload != null ) {
	  	var oldOnload = window.onload;
  	  window.onload = function ( e ) {
    		oldOnload( e );
      	window[menu_init]();
	    }
    }else
      window.onload = menu_init;
  }
	return menu_id;
}

// Mark this page as selected, if this page name exists in menu item action
// If more than one apply, choose the longest match
// First search for the page name without the path and extention in the item action field then search the action field in
// the page name. Then find the longest match of the item action filed, in the page name.
// Note: All this is to avoid mistakes if the item action field contain other data then a pagename.
function mark_selected_page(itm) {
	var selected_obj=null;
	var test_so=null;
	if(typeof(itm[0])!='object') return null;
	//search array for action string
	for(var i in itm){
		//If action is a submenu; go in. 
		if(typeof(itm[i][1])=='object')
			test_so=mark_selected_page(itm[i][1]);
		else{
			// find this page name without path and extention
			var p1=window.location.pathname.lastIndexOf('/'); 
			var p2=window.location.pathname.indexOf('.'); 
			if(p2<0) p2=window.location.pathname.lentgh;
			// search for page name without path and extention in action field
			if(itm[i][1].indexOf(window.location.pathname.substring(p1+1,p2))>0)
				// Search for action field in full page name
				if(window.location.pathname.indexOf(itm[i][1])>=0)
					test_so=itm[i];
		}
		//Choose the longest match
		if(test_so && (!selected_obj || selected_obj[1].length<test_so[1].length)){
			// Deselect previos bedst match
			if(selected_obj) selected_obj[3]=false;
			// Mark new bedst match
			selected_obj=test_so; 
			selected_obj[3]=true;
		}
	}
	return selected_obj;
}
			
//--------------------------------------------------------------------
// 														Internal functions
//--------------------------------------------------------------------
// Initialize trigger to display menu
function menu_init(){
	//look at document.ondatasetcomplete	
	for(var i in jsmenu){
		// Se if  most important images are loaded 
/* Dosnt work with FF
		for(var ii in {'Left':0,'Bg':0,'Right':0})
			if(jsmenu[i].Images.Item[ii].src && jsmenu[i].Images.Item[ii].readyState != "complete"){
				// Tell user that we are waiting
				window.status='Waiting for image to load: "'+jsmenu[i].Images.Item[ii].src+'"';
				// If not loaded; return here when it is.
				jsmenu[i].Images.Item[ii].onreadystatechange=menu_init;
				//jsmenu[i].Images.Item[ii].OnComplete = menu_init;
				return;	
		}
*/
		//Display menu	
		eval('jsmenu[i].build('+i+')');
		window.status='';
	}
	//Prepare submenu windows
}

//Display static menu
MenuClass.prototype.build=function(id){
	with(this){
		var have_submenus=false;
	 	container=document.getElementById(TagId);
		if(!container) return false;
		if(typeof(Items)!='object') return false; 
		// Set Uniform button width
		if(UniformWidth){
			var width=0;
			if(Dimensions<1)
				ItemWidth=get_text_width(Items[0][0]);
			else
				for(var i in Items){
					width=get_text_width(Items[i][0]);
					if(width>ItemWidth) ItemWidth=width;
					if(Dimensions>1 && typeof(Items[i][1])=='object')
						for(var ii in Items[i][1][ii]){
							width=get_text_width(Items[i][1][ii][0]);
							if(width>ItemWidth) ItemWidth=width;
							if(Items[i][1][ii][1]=='object') have_submenus=true;
						}
					else if(typeof(Items[i][1])=='object') have_submenus=true;
	 			}
		}
		// Find submenu icon to use and width of it
		if(have_submenus && SubIconInStatic){
			if(Orientation || Dimensions>1) 
				SubmenuIcon=SubmenuIconDown;
			else	
				SubmenuIcon=SubmenuIconRight;
			SubmenuIconWidth=get_text_width(SubmenuIcon,style_name('subicon'));
		}
		// Mark item with link to this page as selected
		if(AutoSelected) mark_selected_page(Items);
		//Start displaying menu
		html='<table class="'+style_name('menu')+'">';
		for(i in Items){
			if(!Orientation) html+='<tr class="'+style_name('row')+'">';
			if(typeof(Items[i][1])=='object' && Dimensions>1){
				for(ii in Items[i][1]){
					html+=menu_item_build_str(id,i+'.'+1+'.'+ii);
				}
			}else
			html+=menu_item_build_str(id,i);
		}		
		//End menu
		html+='</table>';
		container.innerHTML=html;
	}
	return true;
}

// HTML string = menu_item_build_str(<menu_id>(number),<Index of item>(string))
function menu_item_build_str(menu_id,ix){
	var img=Array();
	var html='';
	var event_str;
	//Validate
	if(!jsmenu[menu_id] || !ix) return '';
	//Make shure ix is a string
	ix=ix.toString();
	//Find the id of the for the button that activate submenu, if any
	var activator_id=menu_id+'-'+ix.substring(0,ix.lastIndexOf('.'));
	activator_id=activator_id.substring(0,activator_id.lastIndexOf('.'));
	//convert index from i.ii.. to [i][ii].. and get item
	eval('menu_item=jsmenu[menu_id].Items['+ix.toString().replace(/\./g,'][')+']');
	// Set css and image defaults
	with(jsmenu[menu_id]){
		if(jssubmenu['sm'+activator_id]){
			// Use submenu images
			img['left']=Images.SubItem.Left.src?Images.SubItem.Left.src:'';
			img['item']=Images.SubItem.Bg.src?Images.SubItem.Bg.src:'';
			img['right']=Images.SubItem.Right.src?Images.SubItem.Right.src:'';
			img['right_obj']=Images.SubItem.Right;
			var item_width=0;
			// Set object to use
			var obj=jssubmenu['sm'+activator_id];
		}else{
			// Use static menu images
			img['left']=Images.Item.Left.src?Images.Item.Left.src:'';
			img['item']=Images.Item.Bg.src?Images.Item.Bg.src:'';;
			img['right']=Images.Item.Right.src?Images.Item.Right.src:'';
			img['right_obj']=Images.Item.Right;
			var item_width=ItemWidth
			// Set object to use
			var obj=jsmenu[menu_id];
		}
	}
	with(obj){
		//Menu bar remove side images 
		if(obj.MenuBar && menu_item.length>1 && !menu_is_vertical(menu_id,ix)){
			var item_no=ix.substr(ix.lastIndexOf('.')+1);
			if(item_no>0) // remove left image
				img['left']='';
			if(item_no<=menu_item.length) // remove rigth image
				img['right']='';
		}
		// Show active item
		if(menu_item[1] && !menu_item[3]){ 
			// Make string of event attributes to use in all cells a button consists of
			event_str=' onMouseOver="change_item_state('+menu_id+',\''+ix+'\',true)"';	 
			event_str+=' onMouseOut="change_item_state('+menu_id+',\''+ix+'\',false)"';
			event_str+=' onclick="menu_iselect('+menu_id+',\''+ix+'\')"';
			if(FloatingHints && menu_item[2]) event_str+=' title="'+menu_item[2]+'"';
			// Left button image
			if(img['left']){
				html+='<td class="'+style_name('left')+'" id="id'+menu_id+'-'+ix+'l" '+event_str+'>';
				html+='<img class="'+style_name('image')+'" id="id'+menu_id+'-'+ix+'li" src="'+img['left']+'"></td>';
			}
			// Item
			html+='<td background="'+img['item']+'" class="'+style_name('item')+'" id="id'+menu_id+'-'+ix+'"'+event_str;
			if(item_width) html+=' width='+item_width;
			html+='>'+menu_item[0]+'</td>';
			// Submenu icon
			if(SubmenuIcon){
				html+='<td background="'+img['item']+'" class="'+style_name('subicon')+'" id="id'+menu_id+'-'+ix+'s"'+event_str;
				html+=' width='+SubmenuIconWidth+'>';
				if(typeof(menu_item[1])=='object') html+=SubmenuIcon; else html+='&nbsp;';
				html+='</td>';
			}
			// Right button image or submenu arrow icon
			if(img['right']){
				html+='<td class="'+style_name('right')+'"  id="id'+menu_id+'-'+ix+'r" '+event_str+'>';
				html+='<img class="'+style_name('image')+'" id="id'+menu_id+'-'+ix+'ri" src="'+img['right']+'"></td>';
			}
		}else{
			// Show inactive item
			// Left button image
			if(img['left']) html+='<td class="'+style_name('left')+'"><img class="'+style_name('image')+'" src="'+img['left']+'"></td>';
			// Item
			if(menu_item[3]) 
				ic=style_name('selected');
			else 
				ic=style_name('inactive');
			html+='<td background="'+img['item']+'" class="'+ic+'"';
			if(item_width) html+=' width='+item_width;
			html+='>'+menu_item[0]+'</td>';
			// Submenu icon
			if(SubmenuIcon){
				html+='<td background="'+img['item']+'" class="'+style_name('subicon')+'" width='+SubmenuIconWidth+'>';
				if(typeof(menu_item[1])=='object') html+=SubmenuIcon; else html+='&nbsp;';
				html+='</td>';
			}
			//Right button image
			if(img['right']) html+='<td class="'+style_name('right')+'"><img class="'+style_name('image')+'" src="'+img['right']+'"></td>';
		}
		// Label
		/*
			if(img.Left) html+='<td class="'+style_name('label')+'">';
			html+='<td class="'+style_name('label')+'">'+menu_item[0];
			if(img.Right) html+='<td class="'+style_name('label')+'">';
		*/
	}
//debug(html);	
	return html;
}

// Function called by HTML on mouse over/out events
function change_item_state(menu_id,ix,is_hover){
	var elm;
	var container_id;
	var css=Array();
	var img=Array();

	with(jsmenu[menu_id]){
		//If this item is a parent to an active submenu, dont unhover.
		if(jssubmenu['sm'+menu_id+'-'+ix] && jssubmenu['sm'+menu_id+'-'+ix].active)
			if(is_hover) 
				clearTimeout(jssubmenu['sm'+menu_id+'-'+ix].timer_id);
			else{		
				jssubmenu['sm'+menu_id+'-'+ix].timer_id=window.setTimeout('submenu_hide("sm'+menu_id+'-'+ix+'");',SubmenuTimeout);
				return;
			}
		//Find the id of the container for the button
		container_id=menu_id+'-'+ix.substring(0,ix.lastIndexOf('.'));
		container_id=container_id.substring(0,container_id.lastIndexOf('.'));
		//convert index from i.ii.. to [i][ii].. and get item
		eval('mi=Items['+ix.toString().replace(/\./g,'][')+']');
		// find style to use
		if(jssubmenu['sm'+container_id]){
			with(jssubmenu['sm'+container_id]){
				// Use submenu classes
				css['left']=style_name('left');
				css['item']=is_hover?style_name('hover'):style_name('item');
				css['subicon']=is_hover?style_name('subicon_h'):style_name('subicon');
				css['right']=style_name('subicon');
			}
			// Change button image
			if(is_hover && Images.SubItem.LeftHover.src) img['left']=Images.SubItem.LeftHover.src 
				else if(Images.SubItem.Left.src) img['left']=Images.SubItem.Left.src;
			if(is_hover && Images.SubItem.BgHover.src) img['item']=Images.SubItem.BgHover.src 
				else if(Images.SubItem.Bg.src) img['item']=Images.SubItem.Bg.src;
			if(is_hover && Images.SubItem.RightHover.src) img['right']=Images.SubItem.RightHover.src 
				else if(Images.SubItem.Right.src) img['right']=Images.SubItem.Right.src;
			var hs=jssubmenu['sm'+container_id].SubmenuIcon;
		}else{
			// Use static menu classes
			css['left']=style_name('left');
			css['item']=is_hover?style_name('hover'):style_name('item');
			css['subicon']=is_hover?style_name('subicon_h'):style_name('subicon');
			css['right']=style_name('right');
			// Change button image
			if(is_hover && Images.Item.LeftHover.src) img['left']=Images.Item.LeftHover.src 
				else if(Images.Item.Left.src) img['left']=Images.Item.Left.src;
			if(is_hover && Images.Item.BgHover.src) img['item']=Images.Item.BgHover.src 
				else if(Images.Item.Bg.src) img['item']=Images.Item.Bg.src;
			if(is_hover && Images.Item.RightHover.src) img['right']=Images.Item.RightHover.src 
				else if(Images.Item.Right.src) img['right']=Images.Item.Right.src;
			var hs=SubmenuIcon;
		}
		//(un)hover left image
		if(img['left']){
			elm=document.getElementById('id'+menu_id+'-'+ix+'li')
			if(elm)	elm.src=img['left'];
		}
		//(un)hover item
		elm=document.getElementById('id'+menu_id+'-'+ix);
		if(elm){
			elm.className =css['item'];
			elm.style.backgroundImage='url('+img['item']+')';
		}
		// (un)hover submenu icon
		if(hs){
			elm=document.getElementById('id'+menu_id+'-'+ix+'s')
			if(elm){
				elm.className =css['subicon'];
				elm.style.backgroundImage='url('+img['item']+')';
			}
		}
		//(un)hover right image
		if(img['right']){
			elm=document.getElementById('id'+menu_id+'-'+ix+'ri')
			if(elm)	elm.src=img['right'];
		}
		if(is_hover){
			//Display status line hint
			if(StatusLineHints){
				if(mi[2])
					window.status=mi[2];
				else if(mi[1])
					if(typeof(mi[1])!='object')
						window.status=mi[1];
					else	
						window.status='Submenu';
			}
			//Show submenu
			if(typeof(mi[1])=='object' && SubMenuOnHover){
				submenu_display(menu_id,ix);
			}
			// Fire programmers events (either function or eval string)
			if(typeof(hover)=='object') hover(menu_id,i);
			else if(this.hover)	eval(hover.replace(/#/,menu_id+',\''+ix+'\''));
		}else{
			// Remove hint
			if(StatusLineHints) window.status='';
			// Fire programmers events
			if(typeof(unhover)=='object') unhover(menu_id,i);
			else if(unhover)	eval(unhover.replace(/#/,menu_id+',\''+ix+'\''));
		}
	}
}

// Function called by HTML on click
function menu_iselect(id,ix){
	with(jsmenu[id]){
		//convert index from i.ii.. to [i][ii].. and get item
		eval('mi=Items['+ix.toString().replace(/\./g,'][')+']');
		if(typeof(mi[1])=='object' && !SubMenuOnHover)
			submenu_display(id,ix);
		else if(typeof(mi[1])=='string'){
			// Fire programmers events
			if(typeof(select)=='object') 
				select(id,i);
			else if(select)	
				eval(select.replace(/#/,id+',\''+i+'\''));	
			// Fire action
			if(Action) 
				eval(Action.replace(/#/,mi[1]));
			else	
				eval(mi[1]);
			submenu_hide();
		}
	}
}

/* -------------------------------------------------------------------------------------------
	Submenu functions
	Hide submenu when mouse is out of submenu.
	This is tricky, because when the mouse move into an item in the submenu, the mouseout event 
	is triggered, followed by a mouseover event, when the mouse is in the item.
	Further more, submenus can have submenus and the submenu must stay open when the mouse
	hover over the item that opened it.
	Therefor submenu_hide are called with a delay, so the mouseover event can cancel the hide,
	if the mouse moved to an other region, but not out of the submenu.
	To handle both submenus that have submenus and to hide all submenus when the mouse is somewhere 
	else, there are a timer delay to hide each submenu and a global one to hide all of them
------------------------------------------------------------------------------------------- */
function submenu_out(){
	// this reffers to the container	
	//Hide this submenu
	with(jsmenu[jssubmenu[this.id].menu_id]){
		jssubmenu[this.id].timer_id=window.setTimeout('submenu_hide("'+this.id+'");',SubmenuTimeout);
		//Hide all submenus
		jssubmenu_tid=window.setTimeout('submenu_hide();',SubmenuTimeout);
	}
}
function submenu_over(){
	var parent=String;
	//Clear global hide timer
	clearTimeout(jssubmenu_tid);
	// this reffers to the container
	if(jssubmenu[this.id])
		with(jssubmenu[this.id]){
			clearTimeout(timer_id);
			//Find the parent submenu if any, by going two indexes back
			parent='sm'+menu_id+'-'+parent_item_id.substring(0,parent_item_id.lastIndexOf('.'));
			parent=parent.substring(0,parent.lastIndexOf('.'));
			// Dont let the parent die
			if(jssubmenu[parent])
				clearTimeout(jssubmenu[parent].timer_id);
		}
}

function submenu_hide(submenu){
	var parent=String;
	//Hide specific submenu
	if(submenu && jssubmenu[submenu])
		with(jssubmenu[submenu]){
			clearTimeout(timer_id);
			if(active){
				container.style.visibility='hidden';
				container.style.zIndex=-1;
				active=false;
				// Unhover parent item 
				change_item_state(menu_id,parent_item_id,false);
			}
		}
	else{
		// Hide all submenus
		clearTimeout(jssubmenu_tid);
		for(var i in jssubmenu)
			with (jssubmenu[i]){
				if(active){
					container.style.visibility='hidden';
					container.style.zIndex=-1;
					active=false;
					change_item_state(menu_id,parent_item_id,false);
				}
			}
	}
}

// Submenu can be placed under og on right side of the item
function submenu_is_under(menu_id,ix){
	var level, under;
	// count menu level (2 '.' for each level)
	for(level=1,i=0;i<ix.length && i>=0;level++) i=ix.indexOf('.',i+1);
	level=level/2;
	// Find out which way to point to submenu
	with(jsmenu[menu_id]){
		under=Orientation; 
		if(SubmenuOrientation==2) 
			for(i=1;i<level;i++) under=!under;
		else
			under=((level>Dimensions?SubmenuOrientation:Dimensions+Orientation+1))%2;
		return under;
	}
}
function menu_is_vertical(menu_id,ix){
	var vertical, level, i;
	with(jsmenu[menu_id]){
		// count menu level (2 '.' for each level)
		for(level=1,i=0;i<ix.length && i>=0;level++) i=ix.indexOf('.',i+1);
		level=level/2;
		if(level>=Dimensions && SubmenuOrientation<2) return SubmenuOrientation;
		vertical=!Orientation;
		for(i=1;i<level;i++) vertical=!vertical;
		return vertical;
	}
}

function submenu_display(menu_id,ix){
	var parent_item;
	var p=Array();
	var orient=0;
	var place_under=0;
	var level=0;
	var top,left;
	//Stop timer
	clearTimeout(jssubmenu_tid);
	jssubmenu_tid=null;
	//Validate
	if(!jsmenu[menu_id] || !ix){
/*Ddebug('The submenu definition is invalid (menu_id='+menu_id+')');
*/
		return;
	}
	ix=ix.toString();
	// Get menu item 
	//convert index from i.ii.. to [i][ii].. and get item
	eval('mi=jsmenu[menu_id].Items['+ix.toString().replace(/\./g,'][')+']');
	if(typeof(mi[1])!='object') {
/*Ddebug('The submenu action is not an array (menu item index='+ix+')');
*/
		return;
	}
	var tag_id='sm'+menu_id+'-'+ix;
	//Create container object. if it already exists in the DOM, reuse it. 
	if(!jssubmenu[tag_id]){
		// Create submenu
		jssubmenu[tag_id]=new SubmenuClass(tag_id,menu_id,ix);
		with(jssubmenu[tag_id]){
			// Create submenu container div as a child of the BODY element
			container=document.createElement("DIV");
			document.getElementsByTagName("body").item(0).appendChild(container);
			container.id=tag_id;
			container.onmouseout=submenu_out; 
			container.onmouseover=submenu_over;
			// Find menu orientation
			Orientation=menu_is_vertical(menu_id,ix);
			// Find submenu icon to use and width of it
			for(i in mi[1]){
				if(typeof(mi[1][i][1])=='object'){
					if(Orientation) 
						SubmenuIcon=jsmenu[menu_id].SubmenuIconDown;
					else	
						SubmenuIcon=jsmenu[menu_id].SubmenuIconRight;
					SubmenuIconWidth=get_text_width(SubmenuIcon,style_name('subicon'));
					break;
				}
			}
			// Set positioning to absolute
			container.style.position='absolute';
			// Fill menu
			var html='';
			html='<table class="'+style_name('menu')+'">';
			if(Orientation) html+='<tr class="'+style_name('row')+'">';
			for(i in mi[1]){
				if(!Orientation) html+='<tr class="'+style_name('row')+'">';
				html+=menu_item_build_str(menu_id,ix+'.1.'+i);
			}		
			//End menu
			html+='</table>';
			container.innerHTML=html;
		}
	}

	with(jssubmenu[tag_id]){
		// Find absolute position and size of parent button (Might change do to scroll)
		parent_item=document.getElementById('id'+menu_id+'-'+ix);
		p['top']=get_toppos(parent_item);
		p['left']=get_leftpos(parent_item);
		p['height']=get_height(parent_item);
		p['width']=get_width(parent_item);
		// If button consists of left graphics, add the width of that too
		parent_item=document.getElementById('id'+menu_id+'-'+ix+'l');
		if(parent_item){
			p['left']=get_leftpos(parent_item);
			p['width']+=get_width(parent_item);
		}
		// If button consists of right graphics, add the width of that too
		parent_item=document.getElementById('id'+menu_id+'-'+ix+'r');
		if(parent_item)	p['width']+=get_width(parent_item);
		// If button consists of submenu marker, add the width of that too
		parent_item=document.getElementById('id'+menu_id+'-'+ix+'s');
		if(parent_item)	p['width']+=get_width(parent_item);
		// Set submenu position 
		if(submenu_is_under(menu_id,ix)){
			// Place submenu below
			top=p['top']+p['height'];
			left=p['left'];
		}else{
			// Place submenu on the right side
			top=p['top'];
			left=p['left']+p['width'];
		}
/* This dosen't work with IE7+
		// Make shure submenu is inside window
		if(window.innerHeight){
			//window.pageYOffset 
			if(top+container.innerHeight > window.pageYOffset+window.innerHeight)
				top=window.pageYOffset+window.innerHeight-container.innerHeight;
		}else if(document.body.clientHeight){ //IE
			if(top+container.clientHeight > document.body.scrollTop+document.body.clientHeight)
				top=document.body.scrollTop+document.body.clientHeight-container.clientHeight;
		}
*/		// Set submenu position 
		container.style.top=top+'px';
		container.style.left=left+'px';

		//make this submenues active
		container.style.visibility='visible'; 
		container.style.zIndex=10049;
		active=true;
	}
}
//----------------------------------------------------
// Usefull functions to manipulate DOM
//----------------------------------------------------

// Functions to find absolute position of the tag by following path to an absolute parent positiom.
function get_leftpos(obj){
	var x=0;
	if(typeof(obj)!='object') return 0;
	if(obj.scrollLeft) x-=obj.scrollLeft;
	if(obj.x) return x+parseInt(obj.x); 
	if(obj.offsetParent) return parseInt(obj.offsetLeft)+x+get_leftpos(obj.offsetParent);
	return 0;
}		
function get_toppos(obj){
	var y=0;
	if(typeof(obj)!='object') return 0;
	if(obj.scrollTop) y-=obj.scrollTop;
	if(obj.y) return y+parseInt(obj.y);
	if(obj.offsetParent) return parseInt(obj.offsetTop)+y+get_toppos(obj.offsetParent);
	return 0;
}
// Functions to find width and height of object
function get_height(obj){
	if(typeof(obj)!='object') return false;
	if(obj.Height) return parseInt(obj.Height);
	if(obj.offsetHeight) return parseInt(obj.offsetHeight);
	return false;
}
function get_width(obj){
	if(typeof(obj)!='object') return false;
	if(obj.Width) return parseInt(obj.Width);
	if(obj.offsetWidth) return parseInt(obj.offsetWidth);
	if(obj.scrollWidth) return parseInt(obj.scrollWidth);
	return false;
}
function get_text_width(text,style){
	//Create a invisible span tag, print the text and mesure the width
	if(!this.container){
		// Create container div as a child of the BODY element
		this.container=document.createElement("SPAN");
		// Append tag to body
		document.getElementsByTagName("body")[0].appendChild(this.container);
		// Make a text node
		var textNode = document.createTextNode('');
  	this.container.appendChild(textNode);
		// Make it invisable
		this.container.style.position='absolute';
		this.container.style.visibility='hidden'; 
	}
	// Insert test subject
	this.container.className=style;
	this.container.childNodes[0].nodeValue=text;
	return get_width(this.container);
}

// --- unused functions 

// change a style and get a style attribute
function get_style(name){
	if(document.styleSheets[0].rules != undefined){ //IE 
		for(i = 0; document.styleSheets.length > i; i++)
			for(j = 0; document.styleSheets[i].rules.length > j; j++) {
				if(document.styleSheets[i].rules[j].selectorText.toLowerCase()==name) 
					return document.styleSheets[i].rules[j].style; 
}
	}else{  //Mozilla
		for(i = 0; document.styleSheets.length > i; i++)
			for(j = 0; document.styleSheets[i].cssRules.length > j; j++){ 
				if(document.styleSheets[i].cssRules[j].selectorText.toLowerCase()==name) 
					return document.styleSheets[i].cssRules[j].style; 
			}
	}
}		

function change_style(name,attrib,val){	
	get_style(name)[attrib] = val; 
}
//----------------------------------------------------
// Debug functions
//----------------------------------------------------
var dump_depth=0;
function dump_obj(obj,max_depth) {
	var result='';
	var tab='';
	if(typeof(obj)!='object') return obj;
	if(!max_depth) max_depth=0;
	for(i=0;i<dump_depth;i++) tab+='--';
	for(var i in obj){
		// Mozilla bug when accessing document.domConfig
		if(i=='domConfig') continue;
		if(typeof(obj[i])=='object'){
			result+=tab+'['+i+']=>(object)('+dump_depth+','+max_depth+')\r\n';
			if(dump_depth<max_depth) {
				dump_depth++;
				result+=dump_obj(obj[i],max_depth);
				dump_depth--;
			}
		}else if(typeof(obj[i])=='function')
			result+=tab+'['+i+']=>(Function)\r\n';
		else if(typeof(obj[i])=='unknown')
			result+=tab+'['+i+']=>(unknown type)\r\n';
		else{
			str=''+obj[i];
			result+=tab+'['+i+']=>'+str.replace(/\</g,'&lt;')+"\r\n";
		}
	}
	return result;
}
var debugWindow;
function debug(str,depth){
  if(!debugWindow || (debugWindow && debugWindow.closed)){
 		debugWindow=window.open("",'Debug',"menubar=yes,scrollbars=yes,resizable=yes,width=300,left=500,height=300");
		debugWindow.focus();
		debugWindow.document.writeln('<html><body>');
		debugWindow.document.title=' --- Debug ---';
		if( window.attachEvent ) //IE4
			window.attachEvent('onunload', debug_close, false);
		else if(window.addEventListener) //NS4
			window.addEventListener("unload", debug_close, false);
	} 
	debugWindow.focus();
	if(typeof(str)=='object')
		str=dump_obj(str,depth);
	if(typeof(str)=='string'){	
		str=str.toString().replace(/\</g,'&lt;');
		str=str.toString().replace(/\r/g,'');
		str=str.toString().replace(/\n/g,'<br>\r\n');
	}
	debugWindow.document.writeln(str+'<br>');
}
function debug_close(){
	if(debugWindow && !debugWindow.closed)
		debugWindow.window.close();
}

// By Trevor McCauley at http://www.senocular.com
function str2hex(str){
    var r="";
    var e=str.length;
    var c=0;
    var h;
    while(c<e){
        h=str.charCodeAt(c++).toString(16);
        while(h.length<3) h="0"+h;
        r+=h;
    }
    return r;
}
function hex2str(str){
    var r="";
    var e=str.length;
    var s;
    while(e>=0){
        s=e-3;
        r=String.fromCharCode("0x"+str.substring(s,e))+r;
        e=s;
    }
    return r;
}
