/*
 * 
 * Lazzo.nl
 * 
 */

Scrollblock = Class.create({
	
    initialize: function(box){
		
		this.DIRECTION = {UP:0, DOWN:1};
	
	    this.options = Object.extend({
      		offsetBy:{left:0,top:0},
			offsetTopImageBy:{left:0,top:0},
			offsetBottomImageBy:{left:0,top:0},
			setBoxHeight: false,
			setBoxHeightAlterBy: 0,
			setBoxHeightAdditionalElements:[],
			trackStyle:null,
			leftAlign:false,
			callback:Prototype.emptyFunction
			
		}, arguments[1] || { });
		
		this.box = box;
		if (this.options.trackStyle) {
			this.track = new Element('div');
			this.track.setStyle(this.options.trackStyle);
		}
		else {
			this.track = new Element('div', {className: 'scrolltrack'});
		}
		
		this.handle = new Element('div',{className:'scrollhandle'});
		
		this._initializeElements();
		this.update.bind(this).defer();
		
		
	},
	
	_initializeElements: function () {

		this._insertArrowButtons();
		this._insertTrack();
		
		this._insertHandle.bind(this).defer();
		this._wireSrollWheel();
				
	},
	
	_mousedown: function(direction){
		var delta = (direction == this.DIRECTION.DOWN)? 0.05:-0.05;
		this.intervalDate = new Date();
		this.mousedownInterval = setInterval(
				function() {
					var date = new Date();
					if ((date - this.intervalDate) > 30) {
						this.intervalDate = new Date();
						this.slider.setValueBy(delta);
					}
				}.bind(this),
				10
		);
	},
	
	_mouseup: function(){
		clearInterval(this.mousedownInterval);
	},
		
	_insertArrowButtons: function(){

		this.scrollbottom = new Element('div').addClassName('scrollbottom');
		this.box.insert({after:this.scrollbottom});

		this.scrollbottom.observe('mousedown', this._mousedown.bind(this, this.DIRECTION.DOWN));
		this.scrollbottom.observe('mouseup', this._mouseup.bind(this));
		
		this.scrolltop = new Element('div').addClassName('scrolltop');
		this.box.insert({after:this.scrolltop});
		this.scrolltop.observe('mousedown', this._mousedown.bind(this, this.DIRECTION.UP));
		this.scrolltop.observe('mouseup', this._mouseup.bind(this));
	},
	
	_insertHandle: function () {
	
		if (this.box.getHeight() == 0) {
			return;
		}
		
		this.track.insert(this.handle);
		this._setHandleHeight.bind(this).defer();
		
	},
	
	_setHandleHeight: function() {
		
		var handleHeight = (this.box.offsetHeight / this.box.scrollHeight) * this.box.offsetHeight;
		handleHeight = Math.round(handleHeight) - 40;
		handleHeight = (handleHeight <= 30)? 30:handleHeight;
		this.handle.setStyle({height:handleHeight+'px'});
	},
	
	_insertTrack: function () {
		this.box.insert({after:this.track});
	},
	
	_wireSliderControl: function () {
		if (this.slider) {
			this.slider.dispose();
		}

		this.slider = new Control.Slider(this.handle, this.track, {
			axis:'vertical',
			onSlide: function(value){
				// TEMP FIX! BUG IN SCRIPTACULUS??
				if (value==1)
					return;
				this._slide(value);
			}.bind(this),
			onChange: function(value){
				this._slide(value);
			}.bind(this)}
		 );
	},
	
	_wireSrollWheel: function () {
		Event.observe(this.box, 'mousewheel', this._scrollWheel.bindAsEventListener(this), true);
		Event.observe(this.box, 'DOMMouseScroll', this._scrollWheel.bindAsEventListener(this), true);
	},
	
	_scrollWheel: function (event) {
		var scroll_amount = Event.wheel(event);
		var deltaHeight = this.box.scrollHeight - this.box.offsetHeight;
		this.slider.setValueBy(-scroll_amount/(deltaHeight/15));
	},
	
	_slide: function (value) {
		var value = Math.round((this.box.scrollHeight - this.box.offsetHeight) * value)
		this.box.scrollTop = value;
		this.options.callback();
	},
	
	
	/*
	 * Get the current slider value. This might break in future Scripaculous updates.
	 */	
	getSliderValue: function() {
		
		return this.slider.value;
		
	},
	
	/*
	 * Set the current slider value. This might break in future Scripaculous updates.
	 */	
	setValue: function(value) {

		this.slider.setValue(value);
		
	},
	
	
	/*
	 * Interface to programmacaly move the scrollbar.
	 */
	setValueBy: function(value) {
		var scrollBy = (value+8) / this.box.scrollHeight; 
		//var value = Math.round((this.box.scrollHeight - this.box.offsetHeight) * value);
		this.slider.setValueBy(scrollBy);
		
	},
	
	showTrack: function () {
		this.scrolltop.show();
		this.track.show();
		this.scrollbottom.show();
	},
	
	hideTrack: function () {
		this.scrolltop.hide();
		this.track.hide();
		this.scrollbottom.hide();
	},
	hasScrollBar:function() {
		return this.track.visible();
	},
	
	/* returns a real between 0 and 1 */
	getScrollHeight: function(){
		return this.box.scrollTop / (this.box.scrollHeight - this.box.offsetHeight);
	},

	getScrollTop: function(){
		return this.box.scrollTop;
	},	

	setScrollTop: function(value){
		//this.box.scrollTop = value;
		this.slider.setValue(value);
	},	

	_update: function(){
		if (this.box.offsetHeight >= this.box.scrollHeight) {
			this.box.scrollTop = 0;
			$(document.body).removeClassName('scrollbar');
		}
		else {
			$(document.body).addClassName('scrollbar');
		}
	},
	
	update: function(){
		this._update();
		this._wireSliderControl.bind(this).delay(.5);
	},
	
	kill: function () {
		// are the eventha	ndlers killed as well?
		if (this.track.parentNode) {
			this.track.parentNode.removeChild(this.track);
			this.scrolltop.remove(); this.scrollbottom.remove();
		}
				
	},
	
	/*
	 * recalculate with box scroll to 0
	 */
	reset: function () {
		this.box.scrollTop = 0;
		this._setHandleHeight.bind(this).defer();
		this.update.bind(this).defer();
	},
	
	/*
	 * recalculate without box scroll to 0
	 */
	recalculate: function () {
		this._setHandleHeight.bind(this).defer();
		this.update.bind(this).defer();
	},
	
	setCallBack: function (callback) {

		this.options.callback = callback;

	}
});
