var jsmenu = function(mainul,menumode) {

	//funzioni
	
	/*
	//style.float non funziona in js float Ã¨ una parola riservata
	//ma ie e ff hanno scelto due nomi diversi :(
	this.set_style = function(obj,name,value)
	{
		if(typeof obj == 'string')
			obj = document.getElementById(startel);
		
		if(name=='float')
		{
			if (document.all) {
			  var name = "styleFloat"; //ie
			} else {
			  var name = "cssFloat"; //firefox
			}
		}
		
		obj.style[name] = value;
	}
	*/

	this.parent_tag = function(startel,tagname)
	{
		if(typeof startel == 'string')
			startel = document.getElementById(startel);
		while(startel)
		{
			if( typeof startel.nodeName!='undefined' && startel.nodeName==tagname.toUpperCase() )
				return startel;
			startel = startel.parentNode;
		}
	}
	
	this.current_style = function(el)
	{
		if(typeof el == 'string')
			el = document.getElementById(el);
			
		var currstyle = el.currentStyle;
		if(!currstyle || typeof currstyle == 'undefined')
			currstyle = el.ownerDocument.defaultView.getComputedStyle(el, null);

		return currstyle;
	}
	
	//ritrona 0 in caso di undefined o robe strane
	this.getInt = function(v)
	{
		if(typeof v == 'number')
			return v;
		else if(typeof v == 'undefined')
			return 0;
		else
		{
			v = ""+v;
			v = parseInt(v);
			if( isNaN(v) )
				return 0;
			else
				return v;
		}
	}
	
	this.getposinfo = function(e)
	{
		if(typeof e == 'string')
			e = document.getElementById(e);
		
		var curr_style = this.current_style(e);
		
		//margin
		var m = {
			x: this.getInt(curr_style.marginLeft),
			y: this.getInt(curr_style.marginTop)
		}
		//padding
		var p = {
			x: this.getInt(curr_style.paddingLeft),
			y: this.getInt(curr_style.paddingTop)
		}
		//border
		var b = {
			x: this.getInt(curr_style.borderLeftWidth),
			y: this.getInt(curr_style.borderTopWidth)
		}

		/*		
		var ss = "m.x: "+m.x+"\nm.y: "+m.y+"\n\n";
		ss += "p.x: "+p.x+"\np.y: "+p.y+"\n\n";
		ss += "b.x: "+b.x+"\nb.y: "+b.y;
		alert('curr_style:\n'+ss);
		*/
		
		return {border:b ,padding:p , margin:m};
	}
	
	this.getpos = function(e,angle)
	{
		if(typeof e == 'string')
			e = document.getElementById(e);
		
		var orig_e = e;
		
		//alert(orig_e.offsetHeight);

		var pos = {x:0,y:0};
		var s="";
		
		//mi sa che devo sommare anche dei bordi (top e left)
		//ma non so bene
		
		//while(e && e!=document.body) {
		while(e) {
			var o = {
				x: this.getInt(e.offsetLeft),
				y: this.getInt(e.offsetTop)
			}
			var c = {
				x: this.getInt(e.clientLeft),
				y: this.getInt(e.clientTop)
			}
			
			pos.x += o.x + c.x;
			pos.y += o.y + c.y;
			
			//e.style.border = "1px solid red";
			//s +=  e.nodeName+"\n  e.offsetLeft:"+e.offsetLeft+" e.clientLeft:"+e.clientLeft+"\n";
			//s += "  e.offsetTop:"+e.offsetTop+" e.clientTop:"+e.clientTop+"\n\n";
			e = e.offsetParent;
		}
		
		//s += "x: "+x+" y: "+y;
		//alert(s);

		//sottraggo i bordi top e left... per margin e padding??
		var pinfo = this.getposinfo(orig_e);
		pos.x -= pinfo.border.x;
		pos.y -= pinfo.border.y;
		
		//per ie?? ma 2px fissi???Ã¹
		//da dove arrivano?
		//e cambia da pc a pc???
		//monitor 15" -=2;
		//monitor 17" -=1;
		if(document.all)
		{
			pos.x -= 1;
			pos.y -= 1;
		}
		
		//gestione quattro angoli, di default 'tl'
		//offsetWidth e offsetHeight comprendono il bordo sia in ff che in ie
		if(!angle)
			angle = 'tl';
		if(typeof angle == 'string')
		{
			angle = angle.toLowerCase();
			if(angle.indexOf('r')>-1)
				pos.x += (typeof orig_e.offsetWidth=='undefined'?0:orig_e.offsetWidth);
			if(angle.indexOf('b')>-1)
				pos.y += (typeof orig_e.offsetHeight=='undefined'?0:orig_e.offsetHeight);
		}
		
		return pos;
	}
	
	this.setpos = function(e,pos)
	{
		if(typeof e == 'string')
			e = document.getElementById(e);
		
		e.style.position = 'absolute';
		e.style.left = pos.x+"px";
		e.style.top = pos.y+"px";
		
		//alert('left: '+e.style.left+'\ntop: '+e.style.top+'\npos: '+e.style.postion);
	}
	
	/*
	this.remove_element = function(el)
	{
		if(typeof el == 'string')
			el = document.getElementById(el);
		el.parentNode.removeChild(el);
	}
	*/
	
	this.hasclass = function(e,classname)
	{
		if(typeof e == 'string')
			e = document.getElementById(e);
		
		var rx = new RegExp("(^|\\s)" + classname + "(\\s|$)");
		return rx.test(e.className);
	}
	
	this.remclass = function(e,classname)
	{
		if(typeof e == 'string')
			e = document.getElementById(e);
		
		//alert( "hasclass: "+classname+">"+this.hasclass(e,classname) );
		
		if(!this.hasclass(e,classname))
			return false;
		
		var rx = new RegExp("(^|\\s)" + classname + "(\\s|$)");
		var sc = e.className;
		//alert("class: "+sc);
		if(typeof sc == 'string')
		{
			sc = sc.replace(rx,'','gis');
			//alert("new class: "+sc);
			e.className = sc;
			return true;
		}			
		return false;
	}
	
	this.addclass = function(e,classname)
	{
		if(typeof e == 'string')
			e = document.getElementById(e);
		
		this.remclass(e,classname);
		var sc = e.className;
		if(typeof sc != 'string')
			sc = "";
		sc += " "+classname+" ";
		e.className = sc;
		return true;
	}
	
	
	//ritorna l'indice o null usare ===null 
	this.arrayFindByVal = function(arr,val)
	{
		for(var i=0;i<arr.length;i++)
		{
			if(arr[i]===val)
				return i;
		}
		return null;
	}
	
	this.arrayRemoveByVal = function(arr,val)
	{
		for(var i=0;i<arr.length;i++)
		{
			if(arr[i]===val)
			{
				arr.splice(i,1);
				return true;
			}
		}
		return false;
	}
	
	this.arrayInsertUnique = function(arr,val)
	{
		if(this.arrayFindByVal(arr,val)===null)
		{
			arr.push(val);
			return true;
		}
		return false;
	}
	
	this.ul_on = function(ul)
	{
		//se il li a cui sta sotto non Ã¨ attivo
		if(!ul.parentli.mousein)
			return;
		
		this.arrayInsertUnique(this.path_uls,ul);
		this.addclass(ul.parentli,this.li_active_class);
		
		//remmato senÃ² cambiando dimensione e posizione alla finestra del browser
		//smaffa
		//if(!ul.popup_pos)
			ul.popup_pos = this.getpos(ul.parentli,ul.parentli.submenu_pos);
		//alert('x: '+subpos.x+'y: '+subpos.y);
		this.setpos(ul,ul.popup_pos);
		
		ul.style.display = 'block';
		ul.style.zIndex = this.submenu_z;
	}
	
	this.ul_off = function(ul)
	{
		//cancello il timeout per l'hide automatico
		clearTimeout(ul.hide_time_id);
		ul.hide_time_id = null;
		ul.timerdone = true;
		
		this.arrayRemoveByVal(this.path_uls,ul);
		this.remclass(ul.parentli,this.li_active_class);
		ul.style.display = 'none';
	}
	
	this.path_off = function()
	{
		var len = this.path_uls.length;
		for(var i=0;i<len;i++) {
			var curr_ul = this.path_uls[0];
			if(!curr_ul.parentli.mousein)
				this.ul_off(curr_ul);
		}
	}
	
	this.ulinpath = function(ul)
	{
		return this.arrayFindByVal(this.path_uls,ul)>-1?true:false;
	}
	
	this.clear_path_from_level = function(level)
	{
		//var level = level_ul.level;
		var len = this.path_uls.length;
		if(len>0)
		{
			for(var i=len-1;i>-1;i--)
			{
				var ul = this.path_uls[i];
				if(ul.level>=level)
					this.ul_off(ul);
				else
					break;
			}
		}
	}
	
	this.start_clearall = function()
	{
		this.stop_clearall();
		var self = this;
		this.hide_all_tid = setTimeout(function(){
			//console.log('nascondo da timer globale');
			self.path_off();
		},
		this.hide_timeout);
	}
	
	this.stop_clearall = function()
	{
		if(this.hide_all_tid)
			clearTimeout(this.hide_all_tid);
	}
	
	this.handle_li = function(curr_li)
	{
		//per ogni LI che dentro ha un UL setto l'evento onclick per visualizzarlo
		var sub_uls = curr_li.getElementsByTagName('UL');
		if( sub_uls.length>0 )
		{
			var subul = sub_uls[0];
			
			//clono , per ie6 doctype-transitional e li con overflow (ci rendiamo conto??)
			//clonando e appendendo al body perdo anche il gli stili settati ".jsmenu ul" :(((
			var subul_c = sub_uls[0].cloneNode(true);
			subul_c.className = 'jsmenu_subul';
			subul = document.body.appendChild(subul_c);
			//this.remove_element(sub_uls[0]);
			
			//metto dentro al li un reference al suo sottomenu (UL)
			curr_li.subul = subul;
			subul.parentli = curr_li;
			
			//per accesso a oggetto menu da callbacks
			var self = this;
			
			//setto gli eventi per settare attivo disattivo un popup (ul)
			subul.onmouseover = function() {
				if(!this.mactive)
				{
					this.mactive = true;
					self.stop_clearall();
				}
			}
			//se il mouse esce dall'ul
			subul.onmouseout = function() {
				this.mactive = false;
				//se il timer ha giÃ  finito o Ã¨ stato cancellato e non sono nel path
				if( this.timerdone && !self.ulinpath(this) )
					self.clear_path_from_level(this.level);
				self.start_clearall();
			}
			
			curr_li.onmouseover = function(event) {
				//cerco altri submenu nel sottomenu del li corrente
				//se non Ã¨ stato giÃ  fatto
				if(!this.sub_check)
				{
					self.handle_ul(this.subul,'tr',this.level+1);
					this.sub_check = true;
				}
				
				if(!this.mousein)
				{
					this.mousein = true;
					//aggiungo la classe "attiva" al li
					self.addclass(this,self.li_active_class);
					
					//disattivo gli ul nel path
					//se il path incomincia con un ul allo stesso livello di questo che sto per visualizzare
					//posso distruggere tutto il path corrente
					//in caso contarario parto dal punto del path allo stesso livello
					//e distruggo da li in poi
					self.clear_path_from_level(this.subul.level);
					
					//attivo il sottomenu
					self.ul_on(this.subul);
					
					//solo per i root
					//if(this.level == 1) {
					//per tutti
					if(true) {
						//setto un timeout per far ritornare nascosto il submenu
						var self_li = this;
						self_li.subul.timerdone = false;
						var tid = setTimeout(function() {
							self_li.subul.timerdone = true;
							//ho finito il timeout di visualizzazione su questo ul
							//quindi lo nascondo ma solo se:
							//1) non ha il mouse sopra
							//2) e non cÃ¨ il mouse sopra al sui parent li
							//3) e non Ã¨ nel path corrente e il path corrente ha piÃ¹ di un elemento
							if( !self_li.subul.mactive &&
								  !self_li.mousein &&
								  (
										( !self.ulinpath(self_li.subul)	&& self.path_uls.length>1 )
										||
										self.path_uls.length == 1
									)
							  )
							{
								//console.log('nascondo da timer: '+self_li.mousein);
								//nascondo il submenu
								self.ul_off(self_li.subul)
							}
						},
						self.hide_timeout);
						
						//metto l'id del timer in caso voglio terminarlo dentro al li e all'ul
						//clearTimeout(tid)
						self_li.hide_time_id = tid;
						self_li.subul.hide_time_id = tid;
					}
					
					
				}
				//fine mousein onece
			}
			//fine onmouseover
			
			curr_li.onmouseout = function(event) {
				this.mousein = false;
				//rimuovo la classe "attiva" al li
				//self.remclass(this,self.li_active_class);
				
				//se esco da un li il suo subul ha giÃ  ternimato il timer
				//o non Ã¨ stato proprio gestito il timer
				//lo nascondo ora
				if(this.subul.timerdone)
					self.ul_off(this.subul);
			}
			
			//ritorno l'ul creato
			return subul;
		}
		else
		{
			//per accesso a oggetto menu da callbacks
			var self = this;
			
			//per i li senza submenu metto solo un clear_path
			//o lo posso fare sul mouseout dei li che hanno un submenu??
			//TODO...
			curr_li.onmouseover = function(event) {
				if(!this.mousein)
				{
					this.mousein = true;
					//aggiungo la classe "attiva" al li
					self.addclass(this,self.li_active_class);
					
					self.clear_path_from_level(this.level+1);
				}
			}
			
			curr_li.onmouseout = function(event) {
				this.mousein = false;
				//rimuovo la classe "attiva" al li
				self.remclass(this,self.li_active_class);
			}
		}
		//fine gestione li sensa submenu
		
		return null;
	}
	//fine handle_li
	
	this.handle_ul = function(ul,posmode,level)
	{
		//setto il livello all'ul
		ul.level = level;
		//ciclo li principali sotto il primo ul che Ã¨ l'unico che non verrÃ  clonato
		var lis = ul.getElementsByTagName('LI');
		var nlis = lis.length;
		for(var i=0;i<nlis;i++)
		{
			var curr_li = lis[i];

			if(curr_li.parentNode == ul)
			{
				curr_li.level = level;
				curr_li.submenu_pos = posmode;
				var new_ul = this.handle_li(curr_li);
			}
		}
	}
	//fine hadle_ul
	
	this.addevent = function(obj, evType, fn)
	{
		if(obj.addEventListener)
		{
			obj.addEventListener(evType,fn,false);
			return true;
		}
		else if(obj.attachEvent)
		{
			var r = obj.attachEvent("on"+evType,fn);
			return r;
		}
		else
			return false;
	}
	
	this.addonload = function(fn)
	{
		this.addevent(window,'load',fn);
	}
	
	
	//costruttore

	//timeout per rinascondere i submenu
	this.hide_timeout = 800;
	
	//array ul aperti (visibili)
	this.path_uls = [];
	
	//zindex ul submenu
	this.submenu_z = 5;
	
	//classe attiva per i li
	this.li_active_class = 'jsmenu_active';
	
	//opzione menu verticale
	this.menumode = menumode;
	if(this.menumode!='v' && this.menumode!='h')
		this.menumode = 'h';
	menumode = null;
	
	var self_jsmenu = this;
	//aggiungo le azioni da fare sull'onload
	this.addonload(function(){
		if(!mainul)
			self_jsmenu.mainul = document.getElementById('jsmenu');
		else if(typeof mainul=='string')
			self_jsmenu.mainul = document.getElementById(mainul);
		else
			self_jsmenu.mainul = mainul;
		mainul = null;
	
		//tutti gli UL sotto quello principale vanno messi display:none e position absolute
		//perchÃ¨ verranno clonati
		var uls = self_jsmenu.mainul.getElementsByTagName('UL');
		var nuls = uls.length;
		for(var i=0;i<nuls;i++)
		{
			var curr_ul = uls[i];
			curr_ul.style.display = 'none';
		}
		
		var posmode = 'bl';
		if(menumode=='v')
			posmode = 'tr';
		
		self_jsmenu.handle_ul(self_jsmenu.mainul,posmode,1);
		
		//setto l'ul principale a visibile
		//(per non fare smaffi di vuislizzazione lo si puÃ² settare nascosto e poi jsmenu lo reimposterÃ )
		self_jsmenu.mainul.style.display = 'block';
		
		//imposto un evento per nascondere il menu sul click nell pagina:
		self_jsmenu.addevent(document.documentElement,'click',function(event){
			self_jsmenu.path_off();
		});
	});
	
	//fine costruttore
}


