/*  Control.Scroller, version 1.0
 *  Copyright (c) 2006, Glenn Nilsson <glenn.nilsson@gmail.com>
 *
 *  Control.Scroller is distributed under the terms of an Creative Commons
 *  Attribution license. In short words, you can use this however you like
 *  as long as you give me and the code credit. Read more at:
 *  <http://creativecommons.org/licenses/by/2.5/>
 *
 *  Requirements: Prototype framework <http://prototype.conio.net/> and
 *  slider.js from <http://wiki.script.aculo.us/scriptaculous/show/Slider>
 *
 *  For details, see: <http://wailqill.com/projects/scroller/>
 *
/*--------------------------------------------------------------------------*/
Control.Scroller = Class.create();
Control.Scroller.scrollers = [];
Control.Scroller.prototype = {
	initialize: function(content, handle, track, options) {
		this.id = "scroller"
		this.content = $(content);
		this.handle = $(handle);
		this.track = $(track);
		this.disabled = false;
		this.container = this.content.parentNode;
		this.currentValue = 0;
		this.innerContent = this.content.down();
		this.multiplier = -1;
		/* Slider-options */
		this.options = Object.extend({
			axis: 'vertical',
			onChange: function(value)  {
				self.updateView(value);
			},
			onSlide: function(value)  {
				self.updateView(value);
			}
		}, options);
		var self = this;
		/* Scroller-options */
		this.options = Object.extend({
			scrollOnHover: false,
			delta: 20,
			interval: 100
		}, this.options);
		
		this.maxValue = this.isVertical() ?
				this.innerContent.offsetHeight - this.handle.offsetHeight :
				this.innerContent.offsetWidth - this.handle.offsetWidth;
		this.options.range = $R(0, this.maxValue);

		this.buttons = {
			up: $(this.options.up),
			down: $(this.options.down)
		};

		this.eventMouseAction = this.buttonAction.bindAsEventListener(this);
		$H(this.buttons).values().each(function(button) {
			if (self.options.scrollOnHover) {
				Event.observe(button, "mouseover", self.eventMouseAction);
				Event.observe(button, "mouseout", self.eventMouseAction);
			} else {
				Event.observe(button, "mousedown", self.eventMouseAction);
				Event.observe(button, "mouseup", self.eventMouseAction);
			}
		});
		this.slider = new Control.Slider(this.handle, this.track, this.options);
	},
	isVertical: function() {
		return this.options.axis == 'vertical';
	},
	buttonAction: function(e) {
		if (!this.disabled) {
			this.multiplier = Event.element(e) == this.buttons.up ? -1 : 1;
			switch (e.type) {
				case "mouseover":
				case "mousedown":
					this.scroll();
					var self = this;
					this.timer = setInterval(function() { self.scroll() }, self.options.interval);
					break;
				case "mouseout":
				case "mouseup":
					clearTimeout(this.timer)
					break;
			}
		}
	},
	scroll: function() {
		this.slider.setValue(this.currentValue + this.options.delta * this.multiplier, 0);
	},
	updateView: function(value) {
		this.currentValue = value;
		if (this.isVertical()) {
			this.container.scrollTop = Math.round(this.currentValue);
		} else {
			this.container.scrollLeft = Math.round(this.currentValue);
		}
		(this.options.onScroll || Prototype.emptyFunction)(value, this);
	},
	reset: function() { 
		this.updateView(0);
		this.slider.setValue(0);
		this.resize();
	},
	resize: function() {
		var containerDimensions = Element.getDimensions(this.container);
		var contentDimensions = Element.getDimensions(this.innerContent);
		this.maxValue = this.isVertical() ?
			containerDimensions.height - contentDimensions.height :
			containerDimensions.width - contentDimensions.width;
		if (this.maxValue >= 0) {
			this.disabled = true;
			this.handle.hide();
			this.buttons.up.style.cursor = 'default';
			this.buttons.down.style.cursor = 'default';
			this.slider.setDisabled();
		} else {
			this.disabled = false;
			this.maxValue = Math.abs(this.maxValue);
			this.handle.show();
			this.buttons.up.style.cursor = 'pointer';
			this.buttons.down.style.cursor = 'pointer';
			this.slider.range = $R(0,this.maxValue);
			this.slider.setEnabled();
		}
	},
	moveTo: function(el) {
		new Effect.MoveTo(this.container, {to_element: el, duration: 1.0, beforeUpdate: function() {
			this.currentValue = this.container.scrollLeft;
			this.scroll();
		}.bind(this)});
	}
}
