// Menu v4 - luglio 2008
// Source code by Luca Reghellin - http://www.reghellin.com - email@reghellin.com

// Required: mootools.js 1.2 - http://www.mootools.net

//Options:
//menuId: String - id ul menu principale
//type: String - 'bar' o 'accordion'
//morph: Boolean - se viene usato il morphing per gli stati dei mainButtons
//fx: String - 'default', 'fade', 'slide', 'blind'
//props: oggetti js con le proprietà da settare per ogni evento
//propsNames: il nome con cui vengono mappate le proprietà in props, se diverse dai defaults

/* /// CLASSE MENU /// */

var u = new Utils();

var Menu = new Class({

	Implements:Options,
	
	options:{
		menuId:"mainMenu",
		type:'bar',
		morph:false,
		fx:'default',
		propsNames:{
			overProps:'overProps',
			outProps:'outProps',
			activeProps:'activeProps',
			subActiveProps:'subActiveProps'			
		},
		props:{
			overProps:{'color':'#000'},
			outProps:{'color':'#000'},
			activeProps:{'color':'#000'},
			subActiveProps:{'color':'#000'}
		}
	},

	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.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)
		
		//vedi options
		var n=o.propsNames;
		var p=o.props;
		this.outProps = p[n.outProps] || p.outProps;
		this.overProps = p[n.overProps] || p.overProps;
		this.activeProps = p[n.activeProps] || p.activeProps;
		this.subProps = p[n.subActiveProps] || p.subActiveProps;
		
		this.initMenu();
		
		this.fxOptions = {}; 
		this.fxFunction = this.setFx();
	},
	
	initMenu:function(){
		var mainMenu = $(this.menuId).getChildren();
		//rilevo primo livello
		this.mainButtons = $$(mainMenu.map(function(li){ return li.getElement('a') } ));
		//rilevo subs > prepareFadeFx e simili
		this.subs = $$(mainMenu.map(function(li){ return li.getElement('div ul') } ))

		//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).addEvent('click',function(e){
					b.change(this.activeProps)
					this.activeButton = b;
					this.openOnOver = false;
					this.stopCloseTimer();
				}.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){
				//console.log(e)
				var b=($(e.target).match('a')) ? $(e.target) : $(e.target).getParent('a');
				this.currentState = 'click';
					
				if($chk(b.sub)){ e.preventDefault(); }//TODO: estendere a tutti: navigazione tutta via js.
				
				//console.log( 'b == this.currentOpener: ' + this.currentOpener  )
				
				if(b == this.activeButton && b != this.startButton){//&& b != this.startButton xché può non essere aperto il menu.
					return; 
				} /*else if(b == this.activeButton && b == this.startButton && $chk(b.sub) ){
					if(b == this.currentOpener){
						this.closeMenu(b);
						this.openOnOver = false;
						this.currentOpener = null;
					} else {
						//apri sub
					}
				}*/ else if( b == this.currentOpener ){//b == this.currentOpener solo se ha aperto un sub
					//console.log(this.clickButton)
					//console.log('b == this.clickButton: '+(b == this.clickButton)); 
					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.activeButton = b; //!!!!!! NEW
				}
				
				this.clickButton = b;

			}.bindWithEvent(this),
			
			'mouseover':function(e){
				var b=($(e.target).match('a')) ? $(e.target) : $(e.target).getParent('a');
				
				//console.log('b == this.overButton: '+ (b == this.overButton))
				
				if(b == this.activeButton){ return; }
				//if(b == this.overButton && $chk(b.sub) ){ return; }
				
				this.currentState = 'over';
				//console.log('this.activeButton: '+$(this.activeButton).get('id'))				

				//NOTA: dato che openOnOver c'è solo con 'bar', forse si può toliere il check.
				if(this.type == 'bar' && this.openOnOver){ 
					//console.log('mouseover::openOnOver')
					this.openMenu(b); 
				}
				
				else{
					//console.log('mouseover:: !openOnOver')
					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) ){ 
					//console.log('mouseout::b == this.activeButton') 
					return;
				} else {
					b.change(this.outProps);
				}
				
				this.outButton = b;
				//this.overButton = null;
				
			}.bindWithEvent(this)
		})//fine addEvents
		
	},//FINE INITMENU
	
	
	/* **** GESTIONE MENU **** */
	
	//OPEN
	openMenu:function(b){
		//console.log(b)
		//console.log('openMenu: '+$(b).get('id') )

		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);
			} else {
				this.stopCloseTimer();
				b.change(this.activeProps);
				this.activeButton = b;
			}			
		}
		
		if(this.currentState == 'over'){
		
			//console.log('b '+b.get('id'), 'over '+this.overButton.get('id') )

			if($chk(this.currentOpener) && this.currentOpener != b && this.currentOpener != this.activeButton){
				//this.stopCloseTimer();
				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);
		}
				
	},
	
	//CLOSE
	closeMenu:function(b,timerCall){//timerCall:Boolean, passato via delay() in openMenu

		//console.log('closeMenu:b: '+$(b).get('id'))

		if(timerCall){
			this.fxFunction(b.sub,0);
			//b.change(this.outProps);
			this.currentOpener = null; //
			this.activeButton = null;
			this.openOnOver = false;
		}

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

			if($chk(b.sub)){ 
				this.stopCloseTimer();
				this.fxFunction(b.sub,0);
				this.currentOpener = null; //
			}
			
			//b.change(this.outProps);
			
			this.activeButton = null;
		}
		
		//se closeMenu arriva da un over, è solo per chiudere un sub.
		if(this.currentState == 'over'){
				//console.log('b == this.overButton: '+ (b == this.overButton))
				//this.stopCloseTimer();
				this.fxFunction(b.sub,0);
				this.currentOpener = null;
				
				//b.change(this.outProps);
		}
		
		b.change(this.outProps);
		
		if(this.type == 'accordion'){return;}
		
		//BAR
// 		if(timerCall){//dopo il close temporizzato, disabilito openOnOver
// 			//console.log('closeMenu::keepClose');
// 		
// 			this.openOnOver = false; 
// 			
// 			if(this.startButton){
// 				//se type == bar e ho lvl2 orizzontali
// 				if(this.openSub){ 
// 					//console.log('closeMenu::keepClose::this.original::this.open'); 
// 					this.openMenu(this.startButton);
// 				}//this.open: settato in setActiveButton
// 				
// 				//se type == bar e ho lvl2 verticali
// 				else{
// 					console.log('closeMenu::keepClose::this.original:: !this.open');
// 					this.startButton.setStyles(this.overProps); 
// 				}
// 				this.activeButton = this.startButton;
// 			}
// 		}
		//BAR
	},
	
	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){
		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' }
		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':
				//console.log('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=this.mainButtons[o.mainIndex];
		this.startButton = b;////
		
		var subIndex = ($chk(o.subIndex)) ? o.subIndex : null;
		
		if(b.sub && subIndex != null){
			b.sub.getElements('a')[subIndex].setStyles(this.subProps);
		}
		
		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


