/***********************************************************************************************
* - SPaner - fluidspaner.js version 1.2, Fri Apr 10 13:32:57 -0200 2009
    Slide smoothly horizontal panes.
	 
 [ THIS IS A COPYRIGHTED WORKS - MIT STYLE LICENCE ]
 
 tocra.org
 Experimental work for future diffusion
 Copyright (c) 2003-2008 Sebastien Bremond | www.tocra.org
 
 web-medias.com
 Copyright (c) 2007-2008 Sebastien Bremond | www.web-medias.com
***********************************************************************************************/

/***********************************************************************************************
* Require:
* - Prototype framework V. > 1.8 ( http://www.prototypejs.org )
* - Scriptaculous Effect librarie ( http://script.aculo.us )
* - Modern Web browsers :)
***********************************************************************************************/
	if(typeof(console) == 'undefined'){var console={log:function(){ /*alert( $A(arguments).join(', ') );/**/ }};} /**/ // IE Console (µlite)
	
	var Spaner = {
			
		collection:{},
		version: 1.2,
		element_ref_id:null,
		
		create: function(element, options)
		{
			if( !$(element) )return;
			element_ref_id = $(element).readAttribute('id');
			this.id = element_ref_id;
			this.collection[element_ref_id] = {
				transition:'EaseFromTo', 
				ajaxloadmsg:"Loading content, please wait ...",
				ajaxloadclass:"spaner_ajaxloader",
				selectedclass:"selecteditem",
				
				basesize:0, 
				list:[],
				ajaxed:[],
				previous:null, 
				current:null, 
				focused:false,
				next:null, 
				height:null,
				prevnextloop:null,
				spaner:$(element_ref_id),
				box:null, 
				animating:false,
				options:options
			};
			var loader = $$('#'+element_ref_id+' .spaner_ajaxloader')[0];
			loader.show();
			
			this.build(element_ref_id);
			
			document.Spaner = this;

			loader.hide();
		},
		
		
		build: function(element_ref_id)
		{
			
			this.onKey = this.onKey.bindAsEventListener(this);

			Spaner.collection[element_ref_id].height = Spaner.collection[element_ref_id].spaner.up().getHeight() +'px';
			
			var boxspaner = $$('#'+element_ref_id+' .boxspaner')[0];
			//	boxspaner.setStyle({height:Spaner.collection[element_ref_id].height}); /* Unused if css height was set to 100% */
			Spaner.collection[element_ref_id].box = boxspaner;
						
			// Each spaner must have the same width, the content can be different.
			var spaners = $$('#'+element_ref_id+' .boxspaner .tabspaner');
			
			Spaner.collection[element_ref_id].list = [];
			spaners.each(function(item){
				Spaner.collection[element_ref_id].list.push(item.readAttribute('id'));
			//	item.setStyle({height:Spaner.collection[element_ref_id].height}); /* Unused if css height was set to 100% */
				
				// Check if the content must be loaded with ajax :)
				Spaner.collection[element_ref_id].ajaxed.push(item.readAttribute('id'));
				Spaner.collection[element_ref_id].ajaxed[item.readAttribute('id')] = {node:null, ajax:false, url:null, loaded:false, reloaded:false};
				var contentarea = $$('#'+item.readAttribute('id')+' .content')[0];
				if( $(contentarea).hasClassName('ajaxspaner') )
				{
					Spaner.collection[element_ref_id].ajaxed[item.readAttribute('id')].ajax = true;
					Spaner.collection[element_ref_id].ajaxed[item.readAttribute('id')].url = $(contentarea).readAttribute('title');
					if( $(contentarea).hasClassName('ajaxreloaded') )
					{
						Spaner.collection[element_ref_id].ajaxed[item.readAttribute('id')].reloaded = true;
					}
					$(contentarea).title = ''; // Destroy title for this node, unused and now stored in the stack !
					Spaner.collection[element_ref_id].ajaxed[item.readAttribute('id')].node = $(contentarea);
					
				}
				
			});
			
			if(Spaner.collection[element_ref_id].options.autowidth)
			{
				// Add a listener to adjust when the window is resized.
				Event.observe(window, 'resize', function(event) {
					Spaner.adjust(element_ref_id);
				});
			}
			Spaner.adjust(element_ref_id); // Re-initialisation on start to actualise current sizes.
			
			// Fix the width of the box who contains the spaners to the double width of a spaner.
			boxspaner.setStyle({width:(2*Spaner.collection[element_ref_id].basesize)+'px'});
		
			
			// Hide all spaners except the required.
			var required_spaner_id = 0;
			if( Spaner.isUrlHasHash(window.location.href) )
			{
				required_spaner_id = Spaner.getAnchorIndex( element_ref_id , Spaner.getAnchorFromHash( Spaner.getUrlHash(window.location.href) ) );
				if(required_spaner_id==null){required_spaner_id = 0;}
			}
			
			spaners.each(function(item,idx){
				if(idx!=required_spaner_id){item.hide();}
				else{
					Spaner.collection[element_ref_id].current = item.readAttribute('id');
				}
			});
			
			
			
			// Attach events on each controlers of this component.
			$$('a[href*="#"]').each(function(anchor){

				if(anchor.hasClassName('controler'))
				{
					anchor.observe('click', function(event) {
						Event.stop(event);
						// Detect where to slide (from the current, to hash target...)
						if( Event.element(event).tagName.toLowerCase() != "a")
						{ /*Warning ! You click on an inner html element of the a node like an img */ console.log("The A link contain a "+Event.element(event).tagName+" tag !"); }
						else{
							var pageAnchor = Event.element(event).href.split('#')[1];
							Spaner.slide(element_ref_id, pageAnchor);
						}
					});
				}
				
				// Set selectedclass when slide.
				if(anchor.tagName.toLowerCase() == "a" && anchor.hasClassName('controler') && String(anchor.getAttribute('href').split('#')[1]).toLowerCase().search(/previous|next/) == -1) 
				{
					if( anchor.getAttribute('href').split('#')[1] == this.collection[element_ref_id].current)
					{
						anchor.addClassName(this.collection[element_ref_id].selectedclass);
					}else{
					 	anchor.removeClassName(this.collection[element_ref_id].selectedclass);
					 }
				}
				
			}.bind(this));

			Spaner.adjust(element_ref_id); // Re-initialisation on start to actualise current sizes.
			
			if(Spaner.collection[element_ref_id].options.usewheel)
			{
			Event.observe($(element_ref_id), "mousewheel", Spaner.onRoll.bindAsEventListener(this,{id:element_ref_id}), false);
			Event.observe($(element_ref_id), "DOMMouseScroll", Spaner.onRoll.bindAsEventListener(this,{id:element_ref_id}), false); // Firefox
			}
			
			if(Spaner.collection[element_ref_id].options.usearrowkeys)
			{
			Event.observe($(element_ref_id), "mouseover", Spaner.doFocus.bindAsEventListener(this,{id:element_ref_id}), false);
			Event.observe($(element_ref_id), "mouseout", Spaner.doBlur.bindAsEventListener(this,{id:element_ref_id}), false);
			document.observe("keydown", Spaner.onKey.bindAsEventListener(this,{id:element_ref_id}), false);
			}
			
			
			// Fire when ready.
			$(document).fire("fluidspaner:ready", { fluidspaner: element_ref_id }); 

			return $(element_ref_id);
		},
		
		
		isUrlHasHash:function(url)
		{
			return ( String(url).lastIndexOf('#') != -1)? true:false;
		},

		getUrlHash:function(url)
		{
			return String(url).substring(String(url).lastIndexOf('#'));
		},
		
		getAnchorFromHash:function(hash)
		{
			return String(hash).split('#')[1];
		},
		
		getAnchorIndex:function(element_ref_id, anchor)
		{
			found = null;
			
			// Check now if the slide request in for a 'Next' or a 'Previous' command.
			if( anchor.toLowerCase() == 'next' || anchor.toLowerCase() == 'previous' )
			{
				// (In|De)crease index of the current pane and picks in the list if the new index does not an overflow on boundaries of the array.
				// /* Debug previous|next request */ console.log( 'getCurrentListIndex()', Spaner.getCurrentListIndex(element_ref_id) );
				destination_id = (anchor.toLowerCase() == 'previous')? Spaner.getCurrentListIndex(element_ref_id)-1:Spaner.getCurrentListIndex(element_ref_id)+1;
				
				// If destination is out of boundaries, return index over looping.				
				if(Spaner.collection[element_ref_id].options.prevnextloop==true)
				{
					if( destination_id < 0 ){ destination_id = Spaner.collection[element_ref_id].list.length-1; }
					if( destination_id > Spaner.collection[element_ref_id].list.length-1 ){ destination_id = 0; }
				}else{
					if( destination_id < 0 || destination_id > Spaner.collection[element_ref_id].list.length-1 ){return null;}
				}
				
				// Get the name at this index
				destination_anchor = Spaner.collection[element_ref_id].list[destination_id];
				// /* Debug previous|next request */ console.log( Spaner.collection[element_ref_id].list ," New pane is "+destination_anchor , " List index : "+destination_id);
				
				anchor = destination_anchor;
				return destination_id;
			}
			

			Spaner.collection[element_ref_id].list.each(function(o,i){
				if(o===anchor){found = i};
			});			
			return found;
		},
		
		
		getCurrentListIndex:function(element_ref_id)
		{
			anchor = this.collection[element_ref_id].current;
			index = 0;
			Spaner.collection[element_ref_id].list.each(function(o,i){
				
				if( o == anchor){index = i;}
			});
			return index;
		},
		
		getList:function(element_ref_id)
		{
			return Spaner.collection[element_ref_id].list;
		},
		
		getCurrentPane:function(element_ref_id)
		{
			indexPane = Spaner.getCurrentListIndex(element_ref_id);
			anchorPane = Spaner.collection[element_ref_id].list[indexPane];
			
			return {index:indexPane, anchor:anchorPane };
		},
		
		
		setTransition:function(element_ref_id,transition)
		{
			this.collection[element_ref_id].transition = transition;
		},
		
		
		buildBehavior:function(element_ref_id)
		{
			// Attach events on each controlers of this component.
			$$('a[href*="#"]').each(function(anchor){
				if(anchor.hasClassName('controler'))
				{
					// Ensure we have stopped observing on click handler.
					Event.stopObserving(anchor, 'click');
					anchor.stopObserving('click');
					
					// Apply a new click handler.
					anchor.observe('click', function(event) {
						Event.stop(event);
						// Detect where to slide (from the current, to hash target...)
						if( Event.element(event).tagName.toLowerCase() != "a")
						{ /*Warning ! You click on an inner html element of the a node like an img, not the link */ console.log("The A link contain a "+Event.element(event).tagName+" tag !"); }
						else{
							var pageAnchor = Event.element(event).href.split('#')[1];
							Spaner.slide(element_ref_id, pageAnchor);
						}
					});
				}
			});
		},
		
		slide:function(element_ref_id,to)
		{

			// Cleanup the destination.
			to = String(to);
			
			// Check if this anchor is a valid registered anchor.			
			if(Spaner.getAnchorIndex(element_ref_id, to) == null){/*unregisterd anchor !*/return;}
			else{ to = Spaner.collection[element_ref_id].list[Spaner.getAnchorIndex(element_ref_id, to)]; }
			
			from = this.collection[element_ref_id].current;
			if(from == to){/*console.log("Same target: don't slide");*/return;}
			
			if(Spaner.collection[element_ref_id].animating){ /*console.log('Oups! Animating...');*/return;}
			
			var loader = $$('#'+element_ref_id+' .spaner_ajaxloader')[0];
			if(loader){loader.show();}
			
			Spaner.collection[element_ref_id].animating = true;
			
			// Fire before slide.
			$(document).fire("fluidspaner:beforeSlide", { fluidspaner: element_ref_id }); 
			
			// Check if this tabspaner is an ajax content !
			if( Spaner.collection[element_ref_id].ajaxed[to].ajax )
			{
				load_content = (Spaner.collection[element_ref_id].ajaxed[to].loaded)? false:true;
				if( Spaner.collection[element_ref_id].ajaxed[to].reloaded ){ load_content = true; }
				
				if(load_content)
				{
					// We must load the content using ajax ... Set the loaded var to true when done.
					// console.log( "This tabspaner is an ajax content, load "+ Spaner.collection[element_ref_id].ajaxed[to].url );
					
					$(Spaner.collection[element_ref_id].ajaxed[to].node).update( '<div class="'+Spaner.collection[element_ref_id].ajaxloadclass+'" title="'+Spaner.collection[element_ref_id].ajaxloadmsg+'"></div>' );
					
					new Ajax.Request(Spaner.collection[element_ref_id].ajaxed[to].url, {
					  method: 'get',
					  onSuccess: function(transport) {
						  $(Spaner.collection[element_ref_id].ajaxed[to].node).update( transport.responseText );
						  Spaner.collection[element_ref_id].ajaxed[to].loaded = true;
						  
						  // In the case of the new loaded content contains Spaner navigation, we must reload the slide anchor behavior.
						  // Otherwize, behavior are lost. (The DOM nodes were replace by a new DOM tree, this is a normal mechanism)
						  Spaner.buildBehavior(element_ref_id);
					  }
					});
					/**/
				}
			}
			
			var offset = 0,bound_down,bound_up;
			// Panes set distribution. (twm)
			(Spaner.collection[element_ref_id].list).each(function(o,i){
				if( o == from || o == to ){ $(o).show(); }else{ $(o).hide(); }
				if( o == from ){ bound_down = i; }
				if( o == to ){ bound_up = i; }
				
			});
			
			offset = (bound_up>bound_down)? '0px':'-'+Spaner.collection[element_ref_id].basesize+'px';
			newoffset = (bound_up>bound_down)? '-'+Spaner.collection[element_ref_id].basesize:'0';
			Spaner.collection[element_ref_id].box.setStyle( {marginLeft:offset} );
			
			//  --> Effect.Transitions.SwingFromTo
			//  --> Effect.Transitions.sinoidal
			new Effect.Morph(Spaner.collection[element_ref_id].box.readAttribute('id'), {
				style:'margin-left:'+newoffset+'px',
				duration: 1.0,
				transition: Effect.Transitions[Spaner.collection[element_ref_id].transition],
				afterFinish: function(){
				//	console.log("oki, animation terminated");
				//	window.location.hash = '#'+to;
					Spaner.collection[element_ref_id].animating = false;
				}
			});
			// 
			Spaner.collection[element_ref_id].previous = Spaner.collection[element_ref_id].current;
			Spaner.collection[element_ref_id].current = to;
			
			loader.hide();
			
			// Set selectedclass when slide.
			$$('a[href*="#"]').each(function(anchor){
				if(anchor.tagName.toLowerCase() == "a" && anchor.hasClassName('controler') && String(anchor.getAttribute('href').split('#')[1]).toLowerCase().search(/previous|next/) == -1) 
				{
					if( anchor.getAttribute('href').split('#')[1] == this.collection[element_ref_id].current)
					{
						anchor.addClassName(this.collection[element_ref_id].selectedclass);
					}else{
					 	anchor.removeClassName(this.collection[element_ref_id].selectedclass);
					 }
				}
			}.bind(this));


			// Fire after slide.
			$(document).fire("fluidspaner:afterSlide", { fluidspaner: element_ref_id });
		},
		
		adjust:function(element_ref_id)
		{
		
			// Adjust the width to its container.
			Spaner.collection[element_ref_id].basesize = Spaner.collection[element_ref_id].spaner.up().getWidth(); // store to retreive to margin morph.
			offset = (parseInt(Spaner.collection[element_ref_id].box.getStyle('marginLeft').replace(/px/g,""))<0)? '-100%':'0px';
			
			Spaner.collection[element_ref_id].spaner.setStyle( {width:'100%'} );
			Spaner.collection[element_ref_id].box.setStyle( {width:'200%' , marginLeft:offset} );
			
		},
		
		
		/* 15/06/2009 : Implementation onRoll */
		onRoll:function(event)
		{
			
			var data = $A(arguments);
			data.shift();
			
			if( Event.roll(event) != null )
			{
				direction = (Event.roll(event) == 'rollDown')? 'Previous':( (Event.roll(event) == 'rollUp')? 'Next':null );
				Spaner.slide(data[0].id,direction);
			}
		},
				
				
		/* 30/06/2009 : Implementation onKey */
		doFocus:function(event)
		{
			var data = $A(arguments);
			data.shift();
			Spaner.collection[data[0].id].focused = true;
		},
		
		doBlur:function(event)
		{
			var data = $A(arguments);
			data.shift();
			Spaner.collection[data[0].id].focused = false;
		},
		
		onKey:function(event)
		{
			
			var data = $A(arguments);
			data.shift();

			if( Event.arrows(event) != null && Spaner.collection[this.id].focused )
			{
				direction = (Event.arrows(event) == 'keyLeft')? 'Previous':( (Event.arrows(event) == 'keyRight')? 'Next':null );
				Spaner.slide(this.id,direction);
			}

			
		}
		
	};

	Object.extend(Event, {
			arrows:function (event){

				var keycode = event.keyCode;
				var key = String.fromCharCode(keycode).toLowerCase();
				
				direction = null;
				
				if ( keycode == 37){ // ← (left key)
					Event.stop(event);
					direction = 'keyLeft';
				} else if ( keycode == 38){ // ↑ (up key)
					Event.stop(event);
					direction = 'keyUp';
				} else if ( keycode == 39){ // → (right key)
					Event.stop(event);
					direction = 'keyRight';
				} else if ( keycode == 40){ // ↓ (down key)
					Event.stop(event);
					direction = 'keyDown';
				}else{ direction = null; }
				
			//	Event.stop(event);
				return direction;
			}
	});

	Object.extend(Event, {
			roll:function (event){

				var delta = 0;
				if (!event) event = window.event;
				
				if (event.wheelDelta)
				{
					delta = event.wheelDelta/120; 
					if (window.opera) delta = -delta;
				} else if (event.detail)
				{
					delta = -event.detail/3;
				}
				
				
				if (delta)
				{
					Event.stop(event);
					return ((delta<0)? 'rollDown':'rollUp')
				}else{ return null; }
				
			}
	});
