	/*
	Class: Scroller
		Adds a scrollbar to a specific div. The scrollbar is implemented using a Script.aculo.us slider.
		The class reparents the original div, creates a slider and ties the reparented div to the slider,
		setting any properties necessary on the divs to make it all work. The scrollbar can be styled using
		CSS. The track of the scrollbar has class 'scroll-track', the thumb has class 'scroll-handle'.
		
	properties:
		myIndex - an integer used to generate a unique ID for use in, for example, div ids.
		outerBox - the div that holds the scrollpane + scrollbar
		innerBox - the div that holds the scrollpane
		innerHeight - the height of the inner box.
		viewportHeight - the height of the view onto the scrolled div.
		track - a div that holds the script.aculo.us slider (the scrollbar)
		trackHeight - the height of the slider
		handle - the div for the 'thumb' of the scrollbar
		handleHeight - the height of the thumb
		slider - the script.aculo.us slider itself
		ieDecreaseBy - a fudge factor used when calculating the width of innerBox
		
	*/
	var Scroller = Class.create();
	/* property: Scroller.ids - A cache of Scrollers indexed by the ID of the original div. */
	Scroller.ids = new Object();
	/* property: Scroller.i - A unique ID generator. */
	Scroller.i = 0;
	Scroller.prototype = {
		/* 	constructor: initialize	- Wrap the passed div in a scrollpane.
			parameters:	el - the div to add a scrollbar to.
		*/
	  initialize:function(el){
		  this.outerBox = el;
		  
			this.options = Object.extend({
				trackLeftMargin:0
				
			}, arguments[1] || {});





		  this.decorate();
	  },
	  
	  /* function: decorate - create the necessary elements to implement the scrollbar and wire up events. */
	  decorate:function() {
		Element.makePositioned(this.outerBox); // Fix IE
		
		// Seed a unique ID
		Scroller.i = Scroller.i + 1;
		this.myIndex = Scroller.i;
		
		
		
		this.lastInnerHeight = 0;
		this.lastHandleHeight = 0;

		//wrap the existing content in an intermediate inner box
		this.innerBox = document.createElement("DIV");
		this.innerBox.className="scrollInnerBox";
		Element.makePositioned(this.innerBox);	// Fix IE
		this.innerBox.style.cssFloat=this.innerBox.style.styleFloat='left';	// Need the scrollbar to appear next to the scrollpane
		this.innerBox.style.width = '100%';
		this.innerBox.id="scrollInnerBox"+Scroller.i;
		this.innerBox.innerHTML = this.outerBox.innerHTML;
		this.outerBox.innerHTML="";
		this.outerBox.appendChild(this.innerBox);
		
		//now build a slider, and put it next to the inner box
		this.track=document.createElement("DIV");
		this.track.className="scrollTrack";
		Element.makePositioned(this.track);	// Fix IE
		this.track.style.cssFloat=this.track.style.styleFloat='left';	// Need the scrollbar to appear next to the scrollpane
		this.track.id="scrollTrack"+Scroller.i;
		this.track.style.display = 'none';
		if(this.options.trackLeftMargin != 0) this.track.style.marginLeft = this.options.trackLeftMargin + 'px';
		
		// Save the size of our little window onto the content
		this.viewportHeight = this.getHeight(this.outerBox);
		
		this.trackHeight = this.viewportHeight;
		this.track.style.height=this.trackHeight+"px";
		
		// Now create the 'thumb' of the scrollbar
		this.handle=document.createElement("DIV");
		this.handle.className="scrollHandle";
		this.handle.id="scrollHandle"+Scroller.i;
		
		// Height of thumb is proportional, but minimum height is 10px
		this.innerHeight = this.getHeight(this.innerBox);			
		if (this.innerHeight > 0)
		{
			this.handleHeight = Math.round((this.trackHeight * this.viewportHeight) / this.innerHeight);
		}
		else
		{
			this.handleHeight = 10;
		}
		if(this.handleHeight < 10) this.handleHeight = 10;
		this.handle.style.height = this.handleHeight + "px";
		
		this.track.appendChild(this.handle);
		this.outerBox.appendChild(this.track);
		
		//turn off scrolling on the outer div
		this.outerBox.style.overflow="hidden";
		
		//layout complete.  if you exit here, you get nice looking box with an inactive scroll bar.
		//create the slider functionality
		this.slider = new Control.Slider(this.handle.id, this.track.id, {axis:'vertical', minimum:0, maximum:this.trackHeight});
		
		//scroll set up is complete. Work through the actual scrolling fuctions
		//run the same function while scrollin, and at the end of scrolling (handles jumping up/down)
		this.slider.options.onSlide = this.slider.options.onChange = this.onChange.bind(this);
	
		// Give the browser 10ms to render the DIVs and resolve their geometry.
		setTimeout(this.resetScrollbar.bind(this, false), 10);
	  },
	  
	  /*
	  function: resetScrollbar  
		Re-calculate the geometry of the scrollbar. Typically called from an event handler.
		args: full - if true, re-calculate the geometry of the scrollpane as well as the scrollbar.
	  */
	  resetScrollbar:function(full){
		// If its a full reset, set scrollbar to invisible.
		if(full) this.track.style.display = 'none';
		
		
		//need to get height of innerBox.
		this.innerHeight = this.getHeight(this.innerBox);
		
		this.viewportHeight = this.getHeight(this.outerBox);// Need to refetch height of outerbox too since it might've stretched.
		this.trackHeight = this.viewportHeight;				// One day trackHeight might be different than viewportHeight if we have scroll buttons too.
		this.slider.trackLength = this.trackHeight;			// Reset slider geometry
		this.track.style.height=this.trackHeight+"px";
		
		// Reset thumb geometry
		this.handleHeight = Math.round((this.trackHeight * this.viewportHeight) / this.innerHeight);
		if(this.handleHeight < 10) this.handleHeight = 10;
		
		//alert("("+this.trackHeight+" * "+this.viewportHeight+") / "+ this.innerHeight + " = " + ((this.trackHeight * this.viewportHeight) / this.innerHeight))
		//alert(this.handleHeight + " - " + typeof(this.handleHeight) + " - " + (this.handleHeight == Infinity))
		//-> DEBUG BY DDUPUIS
		if(this.handleHeight != Infinity)
		{
			this.handle.style.height = this.handleHeight + "px";
		}
		
		// Reset handle height
		this.slider.handleLength = this.handleHeight;
				
		if(this.handleHeight < this.trackHeight)
		{
			// detect if we add or remove item from content - is there a height difference
			if(this.lastInnerHeight != this.innerHeight)
			{
				//-> innerBox height increased
				if(this.lastInnerHeight < this.innerHeight)
				{
					/* the handle height decrease */
					//alert("add item to content")
				}
				
				//-> innerBox height decreased
				else
				{
					/* the handle height increase, must set Y new position for innerBox and handle */
					//alert("remove item to content");
					if(this.innerBox.offsetTop < 0)
					{
						this.innerBox.style.top = (this.innerBox.offsetTop + (this.lastInnerHeight - this.innerHeight)) + "px";
					}
					
					if(this.handle.offsetTop > 0)
					{
						this.handle.style.top = (this.handle.offsetTop - (this.handleHeight - this.lastHandleHeight)) + "px";
					}
				}
			}
			
			 // Scrollbar should be displayed.
			 if (Element.getStyle(this.track, "display") == 'none')
			 {
				 // If scrollbar was not previously displayed, we have to squeeze the viewport width by the width of the scrollbar
				this.track.style.display='inline';
				
				//now adjust the size of the inner box to make room for the slider
				//if the outer box has a border on it (common for scroll boxes) we need to compensate for different box models
				//fortunately, mozilla will work by default - so only if IE  has a border do we care.  Which is good, we can only check borders in IE...
				this.ieDecreaseBy=0;
				if (this.outerBox.currentStyle)
				{
					var borderWidth = this.outerBox.currentStyle["borderWidth"].replace("px","");	//no way to isolate left and right border (which is all we care about) so we'll just assume consistent border width
					if(!isNaN(borderWidth))
					{
						this.ieDecreaseBy=(borderWidth)*2;	//compensate for left and right border
					}
				}

				this.setWidth();			
				
			 }
			 else
			 {
				//alert("track is still visible") 
			 }		 
				
		}
		else
		{
			this.track.style.display = 'none';
			this.innerBox.style.width = '100%';
			this.innerBox.style.top = "0";
		}
		
		//-> finally register last innerHeight
		this.lastInnerHeight = this.innerHeight;
		this.lastHandleHeight = this.handleHeight;

	  },
	  
	  /* function: setWidth - Set the width of of the scrollpane (aka innerBox). */
	  setWidth:function()
	  {
		var newWidth = (this.getWidth(this.outerBox) - this.getWidth(this.track) - this.options.trackLeftMargin - this.ieDecreaseBy) + "px";
		this.innerBox.style.width = newWidth;
		
		// The sad thing is that all of this might change innerHeight, so need to schedule a refresh
		setTimeout(this.resetScrollbar.bind(this, false), 10);
	  },
	  
	  /*
	  function: getHeight  
		Get the height of the passed element.
		
		args:	
			el - the element to get the height of.
	   */
	  getHeight:function(el) {
		if (el.currentStyle){
			return el.offsetHeight;									//ie
		}else{
			return Element.getStyle(el,"height").replace("px","");	//moz
		}
	  },
	  
	  /*
	  function: getWidth  
		Get the width of the passed element.
		
		args:	
			el - the element to get the width of.
	   */
	  getWidth:function(el) {
		var w = "0";
		if (el.currentStyle){
			w = el.offsetWidth;									//ie
		} else {
			w = Element.getStyle(el,"width");
			if (w) {
				w = w.replace("px","");	//moz
			}
		}
		
		return w;
	  },
	  
	  /*
	  function: onChange  
		Called when the script.aculo.us slider has changed (i.e. when it has been dragged). Scroll the inner box.
		
		args:	
			val - not used.
	   */
	  onChange:function(val)
	  {
		if(this.track){
			//assume 100 ticks in the scrollbar
			//for each tick need to move:  The amount the inner box overruns the outer box, divided by 100
			var moveRatio = (this.innerHeight - this.getHeight(this.outerBox))/100;
			//move the box up (negative) for every TickVal, move the box by moveRatio
			this.innerBox.style.top = (val*100*moveRatio*-1) + "px";
		}
	  }
	}
	
	/* function: Scroller.setAll - Search for divs of the class 'makeScroll' and wrap them in a Scroller. */
	Scroller.setAll = function ()
	{
		//get all the boxes we want to scroll
		var sliderBoxes = document.getElementsByClassName("makeScroll");
		//build scroll functionality for each scrollable box
		for(i=0; i<sliderBoxes.length; i++)
		{
			//alert(sliderBoxes[i].id)
			Scroller.ids[sliderBoxes[i].id || ("outerBox"+i)] = new Scroller(sliderBoxes[i]);
		}

	}
	
	/* function: Scroller.reset - If the passed element has class 'makeScroll', wrap it in a Scroller. */
	Scroller.reset = function(bodyId) {
		if($(bodyId).hasClassName("makeScroll"))
		{
			Scroller.ids[bodyId] = new Scroller($(bodyId));
		}
		/*
		if($(body_id).className.match(new RegExp("(^|\\s)makeScroll(\\s|$)"))) {
			Scroller.ids[body_id] = new Scroller($(body_id));
		}
		*/
	}
	
	/* property: Scroller.updateAll - Reset all of the scrollbars. */
	Scroller.updateAll = function ()
	{
		for(var key in Scroller.ids){
			Scroller.ids[key].resetScrollbar(true);
		}
	}