/**
* scroll r1 // 2008.09.04 // jQuery 1.2.6
* 
* // basic usage
* $("p").scroll( direction , speed );
* 
* // advanced usage receives configuration object only
* $("p").scroll({
*	direction: 'up',         // string  = scrolling direction
*	speed: 1,                // number  = velocity multiplier
*	fast: 2,                 // number  = velocity multiplier for fast mode
*	interval: 100,           // number  = milliseconds of polling interval
*	ticks: 1,                // number  = steps until the contents get scrolled by one position
*	repeat: 0,               // number  = greater than zero: milliseconds until scrolling is restarted
*	style: 'jscroll',        // string  = css class name of scrolling container
*	auto: false,             // boolean = indicates whether contents scroll automatically
*	rollover: false,         // boolean = indicates whether contents get rolled over
*	collapse: false,         // boolean = indicates whether container collapses if content has less height
*	onStart: function(obj){} // function = callback function being called if scrollings gets started
* });
* 
* @param  d  direction string || an object with configuration options
* @param  s  speed number  || nothing (use configuration options object)
* @return    The object (aka "this") that called scroller, and the event object
* @author    Marco Ochschim <m.ochschim@inershop.de>
*/
(function($) {
	
	$.fn.scroll = function(d, s) {
		
		// overriding configuration options
		var options = {};
		if (typeof d == 'object') {
			options = d;
		} else {
			if (d) { options.direction = d; }
			if (s) { options.speed = s; }
		}
		
		return this.each(function(index) {
			
			// copy object reference
			var obj = this;
			
			// determine scroll container id
			var id = 'is-jquery-scroll-' + index;

			// create jquery wrapper
			var $this = $(this); 
			
			// create namespace 'scroll'
			obj.scroll = { ref: obj };
			
			// support metadata plugin (v1.0 and 2.0)
			obj.scroll.opts = $.extend(
				false, 
				{}, 
				$.fn.scroll.defaults, 
				options || {}, 
				$.metadata ? $this.metadata() : $.meta ? $this.data() : {}
			);
			
			var prev = '&#8592;'; // left
			var next = '&#8594;'; // right
			if (obj.scroll.opts.direction == 'up' || obj.scroll.opts.direction == 'down') {
				prev = '&#8593;'; // up
				next = '&#8595;'; // down
			}
			
			// initialize member variables
			if (!obj.id) { obj.id = 'obj-' + id }
			obj.scroll.prev = false;
			obj.scroll.next = false;
			obj.scroll.fast = false;
			obj.scroll.offset = 0;
			obj.scroll.tick = 0.0;
			
			// styles for scrolling contents
			$this.css({
				position: 'absolute',
				top: '0',
				left: '0',
				height: 'auto',
				overlow: 'visible'
			});
			
			// scrolling contents gets wrapped by the scroll box
			$this.wrap('<div></div>');
			
			// style the scroll box
			$(obj.parentNode).wrap(
				'<div id="' + id + '" class="' + obj.scroll.opts.style + '-' + 
				obj.scroll.opts.direction + '"></div>'
			).before(
				'<a href="javascript:void()" class="scroll-ctrl scroll-prev"><span><em>' + 
				prev + '</em></span></a>'
			).after(
				'<a href="javascript:void()" class="scroll-ctrl scroll-next"><span><em>' + 
				next + '</em></span></a>'
			).css({
				position: 'relative',
				overflow: 'hidden'
			}).addClass(
				obj.scroll.opts.style
			);
			
			// overflow, collapse
			if (obj.offsetHeight > obj.parentNode.offsetHeight) {
				$(obj.parentNode.parentNode).addClass('scroll-overflow');
			} else {
				if (obj.scroll.opts.collapse) {
					$(obj.parentNode).height(obj.offsetHeight);
				}
			}
			
			// backward scrolling
			$('#' + id + ' a.scroll-prev').hover(
				function() { obj.scroll.prev = true; },
				function() { obj.scroll.prev = false; }).mousedown(
				function() { obj.scroll.fast = true; }).mouseup(
				function() { obj.scroll.fast = false; }
			);
			
			// forward scrolling
			$('#' + id + ' a.scroll-next').hover(
				function() { obj.scroll.next = true; },
				function() { obj.scroll.next = false; }).mousedown(
				function() { obj.scroll.fast = true; }).mouseup(
				function() { obj.scroll.fast = false; }
			);
			
			// a private function for starting the scrolling
			obj.scroll.start = function(interval, offset) {
				if (!this.interval) {
					if (this.timeout) {
						window.clearTimeout(this.timeout);
						this.timeout = null;
					}
					if (!interval || interval < 0) {
						interval = this.opts.interval;
					}
					if (offset != null) {
						this.offset = offset;
						this.ref.style.top = this.pos0 + this.offset;
					}
					this.interval = window.setInterval("document.getElementById('"+this.ref.id+"').scroll.proceed()", interval);
					this.opts.onStart(this);
				}
			};
			
			// a private function for prompting the scrolling repetition
			obj.scroll.repeat = function(offset) {
				if (offset == null) { offset = 'null'; }
				this.stop();
 
				var self = this;
				this.timeout = window.setTimeout(function() {
							var e = document.getElementById(self.ref.id);
							if (e)
								e.scroll.start(null, offset);
						}, 
						this.opts.repeat);
			};
			
			// a private function for suspending the scrolling
			obj.scroll.suspend = function(timeout) {
				if (this.interval) {
					window.clearInterval(this.interval);
					this.interval = null;
				}
				if (this.timeout) {
					window.clearTimeout(this.timeout);
					this.timeout = null;
				}
				if (timeout != null) {
					// todo: resume scrolling automatically after timeout
				}
			};
			
			// a private function for resuming the scrolling
			obj.scroll.resume = function(timeout) {
				if (timeout == null) {
					// todo: resume scrolling immediately
				} else {
					// todo: resume scrolling after timeout
				}
			};
			
			// a private function for stopping the scrolling
			obj.scroll.stop = function() {
				if (this.interval) {
					window.clearInterval(this.interval);
					this.interval = null;
					this.offset = 0;
					this.tick = 0.0;
				}
				if (this.timeout) {
					window.clearTimeout(this.timeout);
					this.timeout = null;
				}
			};
			
			// A private function for scrolling the contents
			obj.scroll.proceed = function() {
				window.__jquery_scroll_doScroll(this.ref);
			};
			
			// start polling scrolling interval
			obj.scroll.start();
		});
	};
	
	$.fn.scroll.defaults = {
		direction: 'down',
		speed: 1,
		fast: 2,
		interval: 100,
		ticks: 1,
		repeat: 0,
		style: 'jscroll',
		auto: false,
		rollover: false,
		collapse: false,
		onStart: function() {}
	};
	
	window.__jquery_scroll_doScroll = function (obj) {
		obj.scroll.tick += 1 / obj.scroll.opts.ticks;
		if (obj.scroll.tick >= 1) {
			obj.scroll.tick = 0.0;
		} else {
			return;
		}
		if (obj.scroll.offset == 0) {
			obj.scroll.pos0 = obj.offsetTop;
			if (obj.offsetHeight > obj.parentNode.offsetHeight) {
				$(obj.parentNode.parentNode).addClass('scroll-overflow');
			} else {
				if (obj.scroll.opts.collapse) {
					$(obj.parentNode).height(obj.offsetHeight);
				}
			}
		}
		var height = obj.parentNode.offsetHeight;
		var down = obj.scroll.next || (!obj.scroll.prev && obj.scroll.opts.auto && obj.scroll.opts.direction == 'down');
		var up   = obj.scroll.prev || (!obj.scroll.next && obj.scroll.opts.auto && obj.scroll.opts.direction == 'up');
		var newTop;
		var objHeight = obj.offsetHeight;
		var top = obj.offsetTop;
		var fast = (obj.scroll.fast) ? obj.scroll.opts.fast : 1;
		var rollover = obj.scroll.opts.rollover && (objHeight > height);
		if (down) {	
			obj.scroll.offset--;
			if (rollover) {
				// rollover bottom position
				if ((objHeight + top) > 0) {
					newTop = top - (obj.scroll.opts.speed * fast);
				} else {
					obj.scroll.offset = height;
					newTop = obj.scroll.pos0 + obj.scroll.offset;
				}
			} else {
				// keep bottom position
				if ((objHeight + top) > height) {
					newTop = top - (obj.scroll.opts.speed * fast);
				} else {
					newTop = top;
					// restart after specific timeout
					if (!obj.scroll.next && obj.scroll.opts.repeat > 0) {
						obj.scroll.repeat(0);
					}
				}
			}
			obj.style.top = newTop + "px";
		};
		if (up) {
			obj.scroll.offset++;
			if (rollover) {
				// rollover top position
				if ((top - height) < 0) {
					newTop = top + (obj.scroll.opts.speed * fast);
				} else {
					obj.scroll.offset = -1 * objHeight;
					newTop = obj.scroll.pos0 + obj.scroll.offset;
				}
			} else {
				// keep top position
				if (top < 0) {
					newTop = top + (obj.scroll.opts.speed * fast);
				} else {
					newTop = top;
					// todo restart after specific timeout
					if (!obj.scroll.prev && obj.scroll.opts.repeat > 0) {
						obj.scroll.repeat(-1 * height);
					}
				}
			}
			obj.style.top = newTop + "px";
		};
	}
})(jQuery);
