/*  Scrollable div prototype.js 1.4.0 extention, version 0.0.2
 *  (c) 2006 OXYS.net - Julien Bidoret, David Charbonnier <contact@oxys.net>
 *
 *  OXScroll is freely distributable under the terms of an MIT-style license.
 *
/*--------------------------------------------------------------------------*/

	  
var OXScroll = Class.create();
OXScroll.prototype = {
	
	//Configure those values
	wellMouseSpeed: 10,
	buttonOverSpeed: 0, // 0 to disable
	buttonDownSpeed: 8,
	menuLinkMouseEvent: 'down', // down, over, up
	spinner: "<img src='img/spinner.gif' />", // Display while loading data	
	displayButtons: true, 
	onlyDisableScroll: false,
	
	//Do not modify after this
	
	pos_y:0,
	slider_mouse_down:false,
	slider_mouse_over:false,
	
	  initialize: function(scroll_div,menu_div,tag_menu) {
  	
  	//Did we need to populate menu link dynamicaly based on html tag
  	if(menu_div!=undefined&&tag_menu!=undefined&&tag_menu!='') { 
	  	this.menu_div=$(menu_div);
	  	this.tag_menu=tag_menu;
  	}
  	
  	//Scroll div name
  	this.scroll_div=scroll_div;
  	
  	//Scroll element
  	this.scroll=$(scroll_div);
  	
  	if(!this.scroll) {
			alert('Scroll div not found');
		} else {
			//Define styles
	  	this.scroll.style.overflow='hidden';
	  	
	  	//Used for links
			this.scroll.object=this;
			
			
			//Create new html structure to support scroll
			this.scroll.innerHTML="<div id='"+this.scroll_div+"_container' class='OXScroll_container'>"+this.scroll.innerHTML+"</div>";
			this.scroll_container = $(this.scroll_div+"_container");
			
			html ="<div id='"+this.scroll_div+"_scroller' style='visibility: hidden; display: none;' class='OXScroll_scroller' onselectstart='return false'>\n";
			html+="	<div id='"+this.scroll_div+"_up_button' class='OXScroll_up_button'>\n";
			html+="		<a href='#up' onselectstart='return false'>up</a>\n";
			html+="	</div>\n";
			html+="	<div id='"+this.scroll_div+"_slider_container' onselectstart='return false' class='OXScroll_slider_container'>\n";
			html+="		<div id='"+this.scroll_div+"_slider' onselectstart='return false' class='OXScroll_slider'>\n";
			html+="			<div id='"+this.scroll_div+"_slider_top' onselectstart='return false' class='OXScroll_slider_top'>&nbsp;</div>\n";
			html+="			<div id='"+this.scroll_div+"_slider_body' onselectstart='return false' class='OXScroll_slider_body'>scroll</div>\n";
			html+="			<div id='"+this.scroll_div+"_slider_bottom' onselectstart='return false' class='OXScroll_slider_bottom'>&nbsp;</div>\n";
			html+="		</div>\n";
			html+="	</div>\n";
			html+="	<div id='"+this.scroll_div+"_down_button' class='OXScroll_down_button'>\n";
			html+="		<a href='#down' onselectstart='return false'>down</a>\n";
			html+="	</div>\n";
			html+="</div>\n";
		
			new Insertion.Before(this.scroll_container,html);
			
			//Register divs as object properties
			this.scroller=$(scroll_div+"_scroller");
			this.up_button=$(scroll_div+"_up_button");
			this.down_button=$(scroll_div+"_down_button");
			this.slider_container=$(scroll_div+"_slider_container");
			this.slider=$(scroll_div+"_slider");
			this.slider_top=$(scroll_div+"_slider_top");
			this.slider_body=$(scroll_div+"_slider_body");
			this.slider_bottom=$(scroll_div+"_slider_bottom");
			
			this.scroller.style.display='block';
			
			ScrollContainerOffset=Position.cumulativeOffset(this.scroll_container);
						
			this.scroller.style.height=(Element.getHeight(this.scroll)+2)+'px';
			this.scroller.style.top=(ScrollContainerOffset[1]-1)+'px';
			this.view_height=Element.getHeight(this.scroll);
			
			this.scroller.style.display='none';
			
			//Register events
			Event.observe(document, 'mouseup', this.WindowMouseUp.bindAsEventListener(this), false);
			Event.observe(this.scroll,'mousewheel',this.WheelEvent.bind(this));
			
			this.slider.onmouseover = this.SliderEvent.bindAsEventListener(this);
			this.slider.onmouseout  = this.SliderEvent.bindAsEventListener(this);
			this.slider.onmousedown = this.SliderEvent.bindAsEventListener(this);
			this.slider.onmouseup   = this.SliderEvent.bindAsEventListener(this);
   		
   		this.up_button.onmouseover = this.ButtonUpEvent.bindAsEventListener(this);
			this.up_button.onmouseout  = this.ButtonUpEvent.bindAsEventListener(this);
			this.up_button.onmousedown = this.ButtonUpEvent.bindAsEventListener(this);
			this.up_button.onmouseup   = this.ButtonUpEvent.bindAsEventListener(this);
   		
   		this.down_button.onmouseover = this.ButtonDownEvent.bindAsEventListener(this);
			this.down_button.onmouseout  = this.ButtonDownEvent.bindAsEventListener(this);
			this.down_button.onmousedown = this.ButtonDownEvent.bindAsEventListener(this);
			this.down_button.onmouseup   = this.ButtonDownEvent.bindAsEventListener(this);
   		
   		this.DragSliderObserver=this.DragSlider.bindAsEventListener(this);

			this.slider_container.onmouseup   = this.ScrollBarEvent.bindAsEventListener(this);
			this.slider_container.onmousedown = this.ScrollBarEvent.bindAsEventListener(this);
			
			this.InitLoad();

		}
	},
	
		InitLoad : function () {
			if(this.menu_div!=undefined) {
				html_links='';
				var titles = this.scroll_container.getElementsByTagName(this.tag_menu);
				titles = $A(titles);
				for(i=0;i<titles.length;i++) {
					html_links+="<li><a href='#OXScroll' onmouse"+this.menuLinkMouseEvent+"='$(\""+this.scroll_div+"\").object.position="+(Position.cumulativeOffset(titles[i])[1]-Position.cumulativeOffset(this.scroll_container)[1])+";$(\""+this.scroll_div+"\").object.SetViewportLocation(false);return false;'>"+titles[i].innerHTML+"</a></li>";
				};
				this.menu_div.innerHTML='<ul>'+html_links+'</ul>';
			}	
			this.SetScrollHeight();
			this.FixScrollPos(0,false);
		},
			
		WheelEvent: function (scroll_div, wheel_count) {			
			this.FixScrollPos(wheel_count*-this.wellMouseSpeed,true);	
		},
	
	   
		ScrollBarEvent: function(evt) {
	   	if(evt.type == 'mousedown') {
	   		if(Event.pointerY(evt)<this.pos_y+this.max_top) {
	   			diff=(Event.pointerY(evt)-(this.pos_y+this.max_top))/2;
	   			if (diff>-10) diff=-10;
	   			this.FixScrollPos(diff,true);
	   		}
	   		if(Event.pointerY(evt)>this.pos_y+this.max_top+this.slider_height+Element.getHeight(this.slider_top)+Element.getHeight(this.slider_bottom)) {
	   			diff=(Event.pointerY(evt)-(this.pos_y+this.max_top+this.slider_height+Element.getHeight(this.slider_top)+Element.getHeight(this.slider_bottom)))/2;
	   			if (diff<10) diff=10;
	   			this.FixScrollPos(diff,true);
	   		}
	   		return false;
	  	} 
	   },
	
		 Slide: function() {
		 	sign=(this.direction=='down')?1:-1;
		 	speed=(this.slider.timer.action=='over')?this.buttonOverSpeed:this.buttonDownSpeed;
		 	this.FixScrollPos(speed*sign,true);		 	
		 },
		 	
		 ButtonUpEvent: function(evt) {
		 	this.direction='up';
		 	this.ButtonEvent(evt);
		 },	
	   
	   ButtonDownEvent: function(evt) {
		 	this.direction='down';
		 	this.ButtonEvent(evt);
		 },
	   
	   ButtonEvent: function(evt) {
	   	if(evt.type == 'mousedown') {
	   		if(this.slider.timer) {
	   			this.slider.timer.currentlyExecuting=false;
	   			this.slider.timer.action='down';
	   			this.slider.timer.direction=this.direction;
	  		} else {
	  			this.slider.timer = new PeriodicalExecuter(this.Slide.bindAsEventListener(this),0.1);
	  			this.slider.timer.action='down';
	  			this.slider.timer.direction=this.direction;
	  		}
	   		return false; //Disable Select
	  	} else if (evt.type == 'mouseover') {
	  			if(this.slider.timer) {
		  			this.slider.timer.currentlyExecuting=false;
	  				this.slider.timer.action='over';
	  				this.slider.timer.direction=this.direction;
		  		} else {
	  				this.slider.timer = new PeriodicalExecuter(this.Slide.bindAsEventListener(this),0.1);
		  			this.slider.timer.action='over';
		  			this.slider.timer.direction=this.direction;
	  			}
	  	} else if (evt.type == 'mouseout') {
	  		this.slider.timer.currentlyExecuting=true;
	  	} else if (evt.type == 'mouseup') {
	  		if(this.slider.timer&&!this.slider.timer.currentlyExecuting) 
	  			this.slider.timer.action='over';
	  	}
	   },
	
		
	   SliderEvent: function(evt) {	   	
	   	if(evt.type == 'mousedown') {
	   		this.slider_mouse_down=true;
	   		this.FixSliderClass();
	   		$offsets=Position.cumulativeOffset(this.slider); 
	   		this.slider.offset_y_start=Event.pointerY(evt)-$offsets[1];
	   		Event.observe(document, 'mousemove', this.DragSliderObserver, false);
	   		return false; //Disable select
		  } else if(evt.type == 'mouseup') {
		  	this.slider_mouse_down=false;
		  	this.FixSliderClass();
	   		Event.stopObserving(document, 'mousemove', this.DragSliderObserver, false);
	   		return false;
			} else if(evt.type == 'mouseover') {
				this.slider_mouse_over=true;
				this.FixSliderClass();
			} else if(evt.type == 'mouseout') {
				this.slider_mouse_over=false;
				this.FixSliderClass();
			}
	   },
	   FixSliderClass:function() {
	   	if(this.slider_mouse_down) {
		   	this.slider.className='OXScroll_slider OXScroll_slider_down';
		  } else if(this.slider_mouse_over) {
			 	this.slider.className='OXScroll_slider OXScroll_slider_over';
		  } else {
			 	this.slider.className='OXScroll_slider';
		  }
	   },
	   
	   DragSlider: function(evt) {
	   	scrollToPos=(Event.pointerY(evt)-this.slider.offset_y_start-this.max_top);
			this.FixScrollPos(scrollToPos,false);
		 },


	FixScrollPos: function (scrollToPos,relative) {
		if(relative)
			scrollToPos=this.pos_y+scrollToPos;
		scrollToPos=Math.round(scrollToPos);
		if(scrollToPos>this.max_height-this.slider_height)
			scrollToPos=this.max_height-this.slider_height;
		if(scrollToPos<0) scrollToPos=0;
		position=Math.round((this.content_height/this.max_height)*scrollToPos);
		if(position>this.content_height-this.view_height)
			position=this.content_height-this.view_height
		if(position<0) position=0;
		this.position=position;
		this.SetViewportLocation(true);
		this.scroll_container.style.top=-position+'px';	
		this.pos_y=scrollToPos;
		this.slider.style.top=this.pos_y+'px';		
	},
	
	ScrollViewportLocation: function() {
		this.scroll_container.currentpos-=((this.scroll_container.currentpos-this.position)/4);
		this.scroll_container.style.top=-this.scroll_container.currentpos+'px';
		this.pos_y=Math.round(this.scroll_container.currentpos/(this.content_height/this.max_height));
		this.slider.style.top=this.pos_y+'px';			
		if(this.scroll_container.style.top==this.position) this.scroll_container.timer.currentlyExecuting=true;
	},
	
	SetViewportLocation: function(immediate) {
		if(this.slider.style.visibility!='hidden') {
			if(this.position>this.content_height-this.view_height)
				this.position=this.content_height-this.view_height
			if(immediate) {
				if(this.scroll_container.timer) {
					this.scroll_container.timer.currentlyExecuting=true;
   			}
				this.scroll_container.style.top=-this.position+'px';	
				this.scroll_container.currentpos=this.position;
			} else {
				this.scroll_container.position=this.position;
				if(!this.scroll_container.timer||this.scroll_container.timer.currentlyExecuting) {
  				this.scroll_container.timer = new PeriodicalExecuter(this.ScrollViewportLocation.bind(this),0.01);
  				this.scroll_container.timer.currentlyExecuting=false;
  			}
			}} else {
				this.position=0;
			}	  
	},
	
	SetScrollHeight: function() {		
		if(this.displayButtons) {
			this.up_button.style.display='block';
			this.down_button.style.display='block';
		} else {
			this.up_button.style.display='none';
			this.down_button.style.display='none';
		}
		this.content_height=Element.getDimensions(this.scroll_container).height;
		if(this.view_height>this.content_height) {
			if(!this.onlyDisableScroll) {
				this.scroller.style.visibility='hidden';
				this.scroller.style.display='none';
			}
			this.slider.style.visibility='hidden';
		}
		else {			
			this.scroller.style.display='block';
			this.slider.style.visibility='visible';
			ScrollContainerOffset=Position.cumulativeOffset(this.scroll_container);
			
			this.slider_container.style.height=(Element.getHeight(this.scroll)-Element.getHeight(this.up_button)-Element.getHeight(this.down_button))+'px';
			this.max_top    =ScrollContainerOffset[1]+Element.getHeight(this.up_button)+2;
			this.max_bottom =ScrollContainerOffset[1]+Element.getHeight(this.scroll)-Element.getHeight(this.down_button);
			this.max_height =this.max_bottom-this.max_top-Element.getHeight(this.slider_top)-Element.getHeight(this.slider_bottom)+2;
		
		
			this.scroll_container.style.width=(Element.getDimensions(this.scroll).width-Element.getDimensions(this.slider).width-3)+'px';
			this.content_height=Element.getDimensions(this.scroll_container).height;
		
			if(this.content_height>0) {
				this.slider_height=Math.round((this.view_height/this.content_height)*this.max_height);
				if(this.slider_height<1) this.slider_height=1;
				this.slider_body.style.height=this.slider_height+'px';
			}			
			this.scroll_container.style.width=(Element.getDimensions(this.scroll).width-Element.getDimensions(this.slider).width-3)+'px';
			this.scroller.style.visibility='visible';			
		}			
	},
	
	
		
		WindowMouseUp: function (evt) {
			this.slider_mouse_down=false;
		  this.FixSliderClass();	   		
			Event.stopObserving(document, 'mousemove', this.DragSliderObserver, false);
		},
		
		Load: function (url) {
			this.FixScrollPos(0);
			this.scroll_container.innerHTML = this.spinner;
			var myAjax = new Ajax.Request(
			url, 
			{
				method: 'post', 
				parameters: '', 
				onComplete: this.ShowResponse.bind(this)
			});
			
		},
		
		ShowResponse: function (originalRequest) {
			if(originalRequest.responseIsFailure) {
				this.scroll_container.innerHTML = 'erreur de communcation avec le serveur';
			} else {
				resultat=JSON.parse(originalRequest.responseText);
				if(resultat.actions!=undefined) {
				 eval(resultat.actions);
				}
				this.scroll_container.innerHTML = resultat.html;
				this.InitLoad();
			}
		}
}