/*  A custom scrollbar UI element.
 *  (c) 2007 hl-studios
 *
 *  Requires the Prototype JavaScript library and a browser sniffer.
 *
/*--------------------------------------------------------------------------*/

if( !Prototype ) {

	alert( "UIScrollbar requires Prototype!" );
	
} else {
		
	Object.extend(Event, {
		wheel: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;	}
			return Math.round(delta); //Safari Round
		}
	});

	UIScrollbar = Class.create();
	
	UIScrollbar.prototype = {
		
		initialize: function( target, options ) {
			if( !$( target )) return;
			this.target = $( target );
			this.setOptions( options );
			//
			this.target.style.overflow = "hidden";
			this.target.style.width = ( this.target.style.width.substr(0, this.target.style.width.length-2) - this.options.width - this.options.marginHorizontal ) + "px";
			//
			document.rootElement = document.body.parentNode;
			
			this.draw();
			this.update();
			this.attachBehaviours();
			
			this.int_update = setInterval(( function() {
				this.update();
			} ).bind( this ), 50 );
		},
		
		setOptions: function( options ) {
			this.options = {
				width: 20,
				marginHorizontal: 0,
				marginVertical: 0,
				innerMargin: 1,
				stepSize: 20,
				areaActiveBorder: "1px solid #aaaaaa",
				areaActiveBg: "",
				areaDisabledBorder: "1px solid #dddddd",
				areaDisabledBg: "",
				sliderActiveBorder: "",
				sliderActiveBg: "#aaaaaa",
				sliderDisabledBorder: "",
				sliderDisabledBg: "#dddddd",
				btnUpActive: "",
				btnUpDisabled: "",
				btnDownActive: "",
				btnDownDisabled: ""
			}
			Object.extend( this.options, options || {} );
		},
		
		draw: function() {
			// Area
			this.area = document.createElement( "div" );
			this.target.parentNode.insertBefore( this.area, this.target );
			this.area.style.border = this.options.areaDisabledBorder;
			this.area.style.width = this.options.width + "px";
			//this.area.style.width = ( parseInt( this.area.style.width ) - ( this.area.offsetWidth - parseInt( this.area.style.width ))) + "px";
			this.area.style.width = ( parseInt( this.area.style.width ) - ( 16 - parseInt( this.area.style.width ))) + "px";
			this.area.style.overflow = "hidden";
			this.area.style.position = "absolute";
			//this.area.style.left = ( this.target.offsetLeft + this.target.offsetWidth + this.options.marginHorizontal ) + "px";
			this.area.style.left = ( parseInt( this.target.style.left ) + parseInt(this.target.style.width)+  (2 * parseInt(this.target.style.padding)) + this.options.marginHorizontal ) + "px";
			//this.area.style.top = ( this.target.offsetTop + this.options.marginVertical ) + "px";
			this.area.style.top = ( parseInt(this.target.style.top) + this.options.marginVertical ) + "px";
			// Slide area
			this.slideArea = { top: this.options.innerMargin, bottom: this.options.innerMargin };
			// Up-button
			if( this.options.btnUpActive != "" ) {
				this.btnUp = document.createElement( "div" );
				this.area.appendChild( this.btnUp );
				this.btnUp.style.width = this.btnUp.style.height = this.area.style.width;
				this.btnUp.style.position = "absolute";
				this.btnUp.style.left = this.btnUp.style.top = "0px";
				this.slideArea.top += parseInt( this.btnUp.style.height );
			}
			// Down-button
			if( this.options.btnDownActive != "" ) {
				this.btnDown = document.createElement( "div" );
				this.area.appendChild( this.btnDown );
				this.btnDown.style.width = this.btnDown.style.height = this.area.style.width;
				this.btnDown.style.position = "absolute";
				this.btnDown.style.left = "0px";
				this.slideArea.bottom += parseInt( this.btnDown.style.height );
			}
			// Slider
			this.slider = document.createElement( "div" );
			this.area.appendChild( this.slider );
			this.slider.style.width = ( parseInt( this.area.style.width ) - this.options.innerMargin * 2 ) + "px";
			this.slider.style.position = "absolute";
			this.slider.style.left = this.options.innerMargin + "px";
			this.slider.style.top = this.slideArea.top + "px";
			//
			this.slider.minHeight = 20;
			this.slider.maxHeight = null;
		},
		
		update: function() {
			if( this.target.offsetHeight != this.target._offsetHeight || this.target._offsetHeight == undefined ) {
				this.target._offsetHeight = this.target.offsetHeight;
				this.area.style.height = this.target.offsetHeight + "px";
				this.area.style.height = ( parseInt( this.area.style.height ) - ( this.area.offsetHeight - parseInt( this.area.style.height ))) + "px";
				this.btnDown.style.top = ( parseInt( this.area.style.height ) - parseInt( this.btnDown.style.height )) + "px";
				this.slider.maxHeight = parseInt( this.area.style.height ) - this.slideArea.top - this.slideArea.bottom;
			}
			if( this.target.scrollHeight != this.target._scrollHeight || this.slider.maxHeight != this.slider._maxHeight || this.target._scrollHeight == undefined ) {
				this.target._scrollHeight = this.target.scrollHeight;
				this.slider._maxHeight = this.slider.maxHeight;
				if( this.target.scrollHeight - this.target.offsetHeight > 0 ) {
					if( this.disabled || this.disabled == undefined ) this.enable();
				} else {
					if( !this.disabled || this.disabled == undefined ) this.disable();
				}
				// Adjust slider
				var h = this.target.scrollHeight > 0 ? Math.round( this.slider.maxHeight * ( this.target.offsetHeight / this.target.scrollHeight )) : this.slider.maxHeight;
				h = h < this.slider.minHeight ? this.slider.minHeight : ( h > this.slider.maxHeight ? this.slider.maxHeight : h );
				this.slider.style.height = h + "px";
				if( this.target.scrollHeight > this.target.offsetHeight ) {
					var t = ( this.target.scrollTop / ( this.target.scrollHeight - this.target.offsetHeight )) * ( this.slider.maxHeight - h );
				} else {
					var t = 0;
				}
				this.slider.style.top = ( this.slideArea.top + t ) + "px";
				//
				this.slider.minTop = this.slideArea.top;
				this.slider.maxTop = parseInt( this.area.style.height ) - this.slideArea.bottom - this.slider.offsetHeight;
			}
		},
		
		disable: function() {
			this.disabled = true;
			this.area.style.border = this.options.areaDisabledBorder;
			this.area.style.background = this.options.areaDisabledBg;
			this.btnUp.style.background = "url( " + this.options.btnUpDisabled + " )";
			this.btnUp.style.cursor = "";
			this.btnDown.style.background = "url( " + this.options.btnDownDisabled + " )";
			this.btnDown.style.cursor = "";
			this.slider.style.border = this.options.sliderDisabledBorder;
			this.slider.style.background = this.options.sliderDisabledBg;
			this.slider.style.cursor = "";
		},
		
		enable: function() {
			this.disabled = false;
			this.area.style.border = this.options.areaActiveBorder;
			this.area.style.background = this.options.areaActiveBg;
			this.btnUp.style.background = "url( " + this.options.btnUpActive + " )";
			this.btnUp.style.cursor = "pointer";
			this.btnDown.style.background = "url( " + this.options.btnDownActive + " )";
			this.btnDown.style.cursor = "pointer";
			this.slider.style.border = this.options.sliderActiveBorder;
			this.slider.style.background = this.options.sliderActiveBg;
			this.slider.style.cursor = "pointer";
		},
		
		startDrag: function( evt ) {
			this.mouseOffset = { x: parseInt( this.slider.style.left ) - Event.pointerX( evt ), y: parseInt( this.slider.style.top ) - Event.pointerY( evt ) };
			this._mouseMoveListener = this.doDrag.bindAsEventListener( this );
			Event.observe( document, "mousemove", this._mouseMoveListener );
			this._mouseUpListener = this.stopDrag.bindAsEventListener( this );
			Event.observe( document, "mouseup", this._mouseUpListener );
			this._mouseOutListener = this.stopDrag.bindAsEventListener( this );
			Event.observe( document.rootElement, "mouseout", this._mouseOutListener );
			return false;
		},
		
		stopDrag: function( evt ) {
			if( evt.type == "mouseout" && Event.element( evt ) != document.rootElement ) return false;
			Event.stopObserving( document, "mousemove", this._mouseMoveListener );
			Event.stopObserving( document, "mouseup", this._mouseUpListener );
			Event.stopObserving( document.rootElement, "mouseout", this._mouseOutListener );
			Event.stop( evt );
		},
		
		doDrag: function( evt ) {
			var t = Event.pointerY( evt ) + this.mouseOffset.y;
			t = t < this.slider.minTop ? this.slider.minTop : ( t > this.slider.maxTop ? this.slider.maxTop : t );
			this.slider.style.top = t + "px";
			this.target.scrollTop = (( t - this.slider.minTop ) / ( this.slider.maxTop - this.slider.minTop )) * ( this.target.scrollHeight - this.target.offsetHeight );
			return false;
		},
		
		stepWheel: function(event) {
			
			if (Event.wheel(event) > 0)
				this.stepUp();
			else
				this.stepDown();
		},
		
		stepUp: function() {
			var t = this.target.scrollTop - this.options.stepSize;
			t = t < 0 ? 0 : t;
			this.target.scrollTop = t;
			this.adjustSlider();
		},
		
		stepDown: function() {
			var t = this.target.scrollTop + this.options.stepSize;
			t = t > this.target.scrollHeight - this.target.offsetHeight ? this.target.scrollHeight - this.target.offsetHeight : t;
			this.target.scrollTop = t;
			this.adjustSlider();
		},
		
		adjustSlider: function() {
			this.slider.style.top = ( this.slider.minTop + ( this.target.scrollTop / ( this.target.scrollHeight - this.target.offsetHeight )) * ( this.slider.maxTop - this.slider.minTop )) + "px";
		},
		
		attachBehaviours: function() {
			Event.observe( this.slider, "mousedown", this.startDrag.bindAsEventListener( this ));
			Event.observe( this.btnUp, "mousedown", this.stepUp.bindAsEventListener( this ));
			Event.observe( this.btnDown, "mousedown", this.stepDown.bindAsEventListener( this ));
			Event.observe( document, "mousewheel", this.stepWheel.bindAsEventListener( this ));
			Event.observe( document, "DOMMouseScroll", this.stepWheel.bindAsEventListener( this ));
		},
		
		reset: function() {
			this.target.scrollTop = 0;
		}
		
	}
	
}

