// Menu v4.3 - February 2009

// Copyright (c) 2008 Luca Reghellin - http://www.reghellin.com
// MIT-style license.



var Menu = new Class({

	Implements:Options,
	
	options:{
		menuId:"mainMenu",
		type:'bar',
		morph:false,
		fx:'default',
		props:{
			overProps:{'color':'','backgroundPosition':'0 0','backgroundColor':'','backgroundRepeat':'','backgroundImage':''},
			outProps:{'color':'','backgroundPosition':'0 0','backgroundColor':'','backgroundRepeat':'','backgroundImage':''},
			activeProps:{'color':'','backgroundPosition':'0 0','backgroundColor':'','backgroundRepeat':'','backgroundImage':''},
			subOverProps:{'color':'','backgroundPosition':'0 0','backgroundColor':'','backgroundRepeat':'','backgroundImage':''},
			subOutProps:{'color':'','backgroundPosition':'0 0','backgroundColor':'','backgroundRepeat':'','backgroundImage':''},
			subActiveProps:{'color':'','backgroundPosition':'0 0','backgroundColor':'','backgroundRepeat':'','backgroundImage':''}
		},
		preventDefault:true
	},

	initialize:function(options){
		
		this.setOptions(options);
		var o = this.options;
		this.menuId = o.menuId;
		this.type = o.type;
		this.morph = o.morph;
		this.fx = o.fx;
		this.preventDefault = o.preventDefault;
				
		this.intId1 = null;
		this.mainButtons = null;
		this.subs = null;
		this.activeButton = null;
		this.busy = null;

		//stato openOnOver: serve a gestire l'apertura di submenu onmouseover
		//viene impostato a true:
		//- al primo click.
		//- alla chiusura di un menu.
		//- da un'eventuale funzione di ripristino dell'active originale.
		//B
		this.openOnOver = false; 
		this.startButton = null; //l'elemento da ripristinare settato in setActiveButton()  
		this.openSub = false; //se tengo aperto il 2o livello > serve se type == 'bar' e il 2o livello è verticale
		//B

		//this.closeActive = o.closeActive; //se chiudo i pulsanti cliccati o no (es. )
		this.currentState = null; //monitor per l'ultimo evento scatenato;
		this.overButton = null;
		this.outButton = null;
		this.clickButton = null;
		this.currentOpener = null;
		//console.log(this.closeActive)

		//shortcuts
		var p=o.props;
		this.outProps = p.outProps;
		this.overProps = p.overProps;
		this.activeProps = p.activeProps;
		this.subOverProps = p.subOverProps;
		this.subOutProps = p.subOutProps;
		this.subActiveProps = p.subActiveProps;
		
		this.initMenu();
		
		this.fxOptions = {}; 
		this.fxFunction = this.setFx();
	},
	
	initMenu:function(){
		var mainMenu = $(this.menuId).getChildren();
		
		//console.log(mainMenu);
		
		//rilevo primo livello
		this.mainButtons = $$(mainMenu.map(function(li){ return li.getElement('a') } ));
		
		//rilevo i submenu > prepareFadeFx e simili
		this.subs = $$(mainMenu.map(function(li){
				var sub = li.getElement('ul');
				var div = li.getElement('div');
				if(sub){
					if(!div){ 
						sub.setStyles({'visibility':'hidden','display':'block'});//temporaneo per rilevare gli stili*
						var p = $H(sub.getStyles('top','left'));
						var dim = sub.getSize();
						if(this.type != 'accordion'){ p.extend({ 'position':'absolute','width':dim.x }) }
						var d = new Element('div');
						d.setStyles(p);
						d.wraps(sub);
						sub.setStyles({'visibility':'visible','display':'none','position':'static'});//ripristino*
					}
					return sub;
				}
		}.bind(this)));

		//console.log(this.subs)

		//rilevo sub e setto fx per livello 1
		this.mainButtons.each(function(b){
			b.sub = b.getParent().getElement('ul');
			
			if(b.sub){//i pulsanti con sub sono active solo se viene cliccato un sub!
				var submenu = b.sub.getElements('li a');
				$$(submenu).addEvents({
					'click':function(e){
						b.change(this.activeProps);
						b.store('active',true);//check
						this.activeButton = b;
						this.openOnOver = false;
						this.stopCloseTimer();
					}.bindWithEvent(this),
					
					'mouseover':function(e){
						var b_sub=($(e.target).match('a')) ? $(e.target) : $(e.target).getParent('a');
						if(!b_sub.retrieve('active')){ b_sub.setStyles(this.subOverProps); }
					}.bindWithEvent(this),
					
					'mouseout':function(e){
						var b_sub=($(e.target).match('a')) ? $(e.target) : $(e.target).getParent('a');
						if(!b_sub.retrieve('active')){ b_sub.setStyles(this.subOutProps); }
					}.bindWithEvent(this)
					
				});
			}
			
			if(this.morph){
				b.set('morph',{duration:'short',transition:'linear',link:'cancel'});
				b.change = this.morphFx;
			} else { b.change = this.styleFx; }
			
			
		},this);
		
		//assegno eventi
		this.mainButtons.addEvents({
			'click':function(e){
				//alert('ok')
				var b=($(e.target).match('a')) ? $(e.target) : $(e.target).getParent('a');
				this.currentState = 'click';
					
				if($chk(b.sub) && this.preventDefault){ e.preventDefault(); }//TODO: estendere a tutti: navigazione tutta via js.
					
				if(b == this.activeButton && b != this.startButton){//&& b != this.startButton xché può non essere aperto il menu.
					return; 
				} else if( b == this.currentOpener ){//b == this.currentOpener solo se ha aperto un sub
					this.closeMenu(b);
					this.openOnOver = false;
					this.currentOpener = null;
				} else {
					this.openMenu(b);
					if($chk(b.sub) && this.type == "bar"){ 
						this.openOnOver = true; 
					} else { this.openOnOver = false; }
				}
				
				this.clickButton = b;

			}.bindWithEvent(this),
			
			'mouseover':function(e){
				var b=($(e.target).match('a')) ? $(e.target) : $(e.target).getParent('a');
								
				if(b == this.activeButton){ return; }
				
				this.currentState = 'over';

				//NOTA: dato che openOnOver c'è solo con 'bar', forse si può toliere il check.
				if(this.type == 'bar' && this.openOnOver){ this.openMenu(b); }
				else{ b.change(this.overProps); }
				
				this.overButton = b;

			}.bindWithEvent(this),
			
			'mouseout':function(e){				
				var b=($(e.target).match('a')) ? $(e.target) : $(e.target).getParent('a');
				
				this.currentState = 'out';
				
				//l'out non va fatto se:  || (this.type == 'bar' && $chk(b.sub) ) 
				if(b == this.activeButton || (this.type == 'bar' && $chk(b.sub) && this.openOnOver == true) ){ 
					return;
				} else { b.change(this.outProps); }
				
				this.outButton = b;
				
			}.bindWithEvent(this)
		});
		
	},//FINE INITMENU
	
	
	/* **** GESTIONE MENU **** */

	//OPEN
	openMenu:function(b){

		if(this.currentState == 'click'){

			if(this.activeButton){
				this.closeMenu(this.activeButton);
			}

			if($chk(b.sub)){
				this.fxFunction(b.sub,1);
				b.change(this.overProps);
				this.currentOpener = b;
				this.startCloseTimer(b);
			} 

			//se type == "accordion", il cliccato è sempre active, 
			//anche se non ha sub o i sub non sono stati cliccati
			if(!$chk(b.sub) || this.type == "accordion"){
				this.stopCloseTimer();
				b.change(this.activeProps);
				this.activeButton = b;
			}			
		}
		
		if(this.currentState == 'over'){
		
			if($chk(this.currentOpener) && this.currentOpener != b && this.currentOpener != this.activeButton){
				this.closeMenu(this.currentOpener,false);
			}
			
			if($chk(b.sub) && this.openOnOver){
				this.fxFunction(b.sub,1);
				this.currentOpener = b;
				this.startCloseTimer(b);
			}
			
			b.change(this.overProps);
		}
				
	},
	
	closeMenu:function(b,timerCall){//timerCall:Boolean, passato via delay() in openMenu

		//se closeMenu arriva dal timer
		if(timerCall){
			this.fxFunction(b.sub,0);
			this.currentOpener = null; //
			this.activeButton = null;
			this.openOnOver = false;
		}

		//se closeMenu arriva da un click
		if(this.currentState == 'click'){

			if($chk(b.sub)){ 
				this.stopCloseTimer();
				this.fxFunction(b.sub,0);
				this.currentOpener = null; //
			}
						
			this.activeButton = null;
		}
		
		//se closeMenu arriva da un over, è solo per chiudere un sub.
		if(this.currentState == 'over'){
			this.fxFunction(b.sub,0);
			this.currentOpener = null;
		}
		
		//in ogni caso, setta l'out
		//if(b != this.startButton){
		b.change(this.outProps);
		//}
	},
	
	startCloseTimer:function(b){
		if(this.type == 'bar'){
			//elimino eventuali intervalli aperti
			this.stopCloseTimer();			
			
			//attivo spegnimento temporizzato
			this.intId1 = this.closeMenu.delay(5000,this,[b,true]);
		}	
	},
	
	stopCloseTimer:function(b){
		if(this.type == 'bar'){
			//elimino eventuali intervalli aperti
			if($chk(this.intId1)){ $clear(this.intId1); }
		}	
	},
		
	/* **** EFFETTI **** */
	
	// - EFFETTI MENU - //
	morphFx:function(props){ this.morph(props); },
	styleFx:function(props){ this.setStyles(props); },

	// - EFFETTI SUB - //
	defaultFx:function(sub,type){
		if(type == 1){ sub.setStyle('display','block'); }
		else{ sub.setStyle('display','none'); }
	},

	fadeFx:function(sub,type){
		if(type == 1){ sub.tween('opacity',1); }
		else{ 
			if(this.type == 'bar'){ sub.tween('opacity',0); }
			//il fade con l'accordion non è piacevole in chiusura
			else { sub.setStyles({'opacity':0,'display':'none'}); }
		}
	},
	
	slideFx:function(sub,type){
		//console.log('slide');
		if(type == 1){ sub.slide('in'); }
		else{ sub.slide('out'); }
	},
	
	blindFx:function(sub,type){
		if(type == 1){ sub.tween('height',sub.h); }
		else{ sub.tween('height',0); }
	},
	
	prepareFadeFx:function(){
		this.fxOptions = { 
				'link':'cancel',
				'transition':'sine:out',
				'onStart':function(){ if(this.element.getStyle('opacity') == 0){ this.element.setStyle('display','block') }; },
				'onComplete':function(){ if(this.element.getStyle('opacity') == 0){ this.element.setStyle('display','none') }; }
		}//fine options
		//resetto opacity dei subs - display va resettato onStart/Complete
		//perché altrimenti l'accordion non viene visualizzato correttamente		
		this.subs.setStyles({'opacity':0});
		this.subs.set('tween',this.fxOptions);
	},
	
	prepareSlideFx:function(){
		this.fxOptions = { 'link':'cancel','transition':'sine:out', 'duration':'short' }
		this.subs.set('slide',this.fxOptions);
		this.subs.setStyles({'visibility':'hidden','display':'block'});
		this.subs.slide('hide').setStyle('visibility','visible');
	},
	
	prepareBlindFx:function(){
		this.fxOptions = { 'link':'cancel','transition':'quint:out' }
		this.subs.set('tween',this.fxOptions);
		//setto overflow:hidden
		this.subs.setStyles({'overflow':'hidden','display':'block'});
		//rilevo altezza e salvo in sub.h per blindFx()
		this.subs.each(function(s){ s.h = s.getSize().y; /*console.log(s.h)*/ });
		//inizializzo resettando l'altezza
		this.subs.setStyle('height',0);
	},
	
	
	setFx:function(){
		switch(this.fx){
			case 'fade':
				this.prepareFadeFx();
				return this.fadeFx;
				break;
			case 'slide':
				this.prepareSlideFx();
				return this.slideFx;
				break;
			case 'blind':
				this.prepareBlindFx();
				return this.blindFx;
				break;
			default:
				this.fxtype = 'default';
				return this.defaultFx;
		}
	},

	/*
	setFx:function(fxtype,duration){
		this.fxFunction = this.routeFx(fxtype);
		this.fxDuration = (duration) ? duration : this.fxDuration;
	},
	*/
	
	/*
	setFxDuration:function(duration){
		this.fxDuration = (duration) ? duration : this.fxDuration;
	},
	*/
	
	//SET STARTBUTTON
	setStartButton:function(o){//object: mainIndex:number, subIndex:number, openSub:boolean
		
		var b= ($chk(o.mainIndex)) ? this.mainButtons[o.mainIndex] : ($chk(this.activeButton)) ? this.activeButton : null;
		if(b == null){ alert('Error: mainMenu :: setStartButton : options error'); return; }
		this.startButton = b;////
		
		var subIndex = ($chk(o.subIndex)) ? o.subIndex : null;
		
		if(b.sub && subIndex != null){
			var b_sub = b.sub.getElements('a')[subIndex];
			b_sub.setStyles(this.subActiveProps);
			b_sub.store('active',true);
		}
		
		if($chk(o.openSub)){
			this.fxFunction(b.sub,1);
			b.change(this.overProps);
			this.currentOpener = b;
			this.openSub = true;///
		}
		
		else { 
			b.change(this.activeProps);
		}
		
		this.activeButton = b;////
	}
	
	///////
});//END MENU



