var SO = Object.extend({
	Scroller: Class.create({
		initialize: function(container, scrollbar, options) {
			this.container = $(container);
			this.scrollbar = $(scrollbar);
			this.options = Object.extend({
				leftArrowClass: 'scroll_left',
				rightArrowClass: 'scroll_right',
				handleClass: 'handle',
				scrollStep: 30, // pixels
				scrollInterval: 0.1 // seconds
			}, options || {});
			
			this.leftArrow = this.scrollbar.down('.'+this.options.leftArrowClass);
			this.rightArrow = this.scrollbar.down('.'+this.options.rightArrowClass);
			this.handle = this.scrollbar.down('.'+this.options.handleClass);
			
			this.container.up().makePositioned();
			this.container.setStyle({ position: 'absolute', left: '0px' });
			this.containerWidth = this.container.getWidth();
			this.containerMaskWidth = this.container.up().getWidth();
			
			this.currentLeftPosition = parseInt(this.container.style.left, 10);
			this.scrollbarWidth = this.scrollbar.getWidth() - this.leftArrow.getWidth()*2;			
			
			// Size and Position Handle
			this.containerScrollDistance = this.containerWidth - this.containerMaskWidth;
			this.handleOffset = this.leftArrow.getWidth();
			this.handle.setStyle({ width: (this.containerMaskWidth / this.containerWidth * this.scrollbarWidth)+'px', left: this.handleOffset+'px' });
			this.handleScrollDistance = this.scrollbarWidth - this.handle.getWidth();
			var handleScrollDistance = this.handleScrollDistance;
			var handleOffset = this.handleOffset;
			
			this.draggableHandle = new Draggable(this.handle, { 
				constraint: 'horizontal', 
				onDrag: function() {
					this.updateScroll();
				}.bind(this),
			
				snap: function(x, y, draggable) {
		      function constrain(n, lower, upper) {
		    		if (n > upper) return upper;
		        else if (n < lower) return lower;
		        else return n;
		      }
		      return [
		      	constrain(x, handleOffset, handleOffset+handleScrollDistance),
		        y];
				}
		 });
			
			// Attach Events
			this.leftArrow.observe('mousedown', this.startScroll.bind(this).curry('left'));
			this.rightArrow.observe('mousedown', this.startScroll.bind(this).curry('right'));
			
			this.leftArrow.observe('mouseup', this.stopScroll.bind(this));
			this.rightArrow.observe('mouseup', this.stopScroll.bind(this));

			this.leftArrow.observe('click', function(event) { Event.stop(event); });
			this.rightArrow.observe('click', function(event) { Event.stop(event); });
			this.handle.observe('click', function(event) { Event.stop(event); });
		},
		
		startScroll: function(direction, event) {
			Event.stop(event);
			var step = direction == 'left' ? this.options.scrollStep : -this.options.scrollStep;
			this.scrollBy(step);
			this.scrollInterval = setInterval(this.scrollBy.bind(this).curry(step), this.options.scrollInterval*1000);
		},
		
		scrollBy: function(step) {
			this.scrollTo(this.currentLeftPosition + step);
		},
		
		stopScroll: function(event) {
			Event.stop(event);
			clearInterval(this.scrollInterval);
		},
		
		scrollTo: function(position) {
			position = position > 0 ? 0 : (position < -this.containerScrollDistance ? -this.containerScrollDistance : position);
			this.currentLeftPosition = position;
			this.container.setStyle({ left: position+'px' });
			
			this.updateHandle();
		},
		
		updateScroll: function() {
			var left = -((parseInt(this.handle.getStyle('left'), 10)-this.handleOffset) / this.handleScrollDistance * this.containerScrollDistance);
			this.currentLeftPosition = left;
			this.container.setStyle({ left: left+'px'});
		},
		
		updateHandle: function() {
			var left = Math.abs(this.currentLeftPosition) / this.containerScrollDistance * this.handleScrollDistance;
			this.handle.setStyle({ left: left+this.handleOffset+'px'});
		}
	})
}, SO || {});
