/**
 * LoopScroller class. Scrolls all children inside context, in an endless loop.
 * This can be used to easily scroll children inside of context with style 'overflow: hidden'.
 *
 * @author rob.bast@gmail.com
 * @var string|element  context  Context to attach to
 * @var array           options  Array containing options (optional)
 *
 * Options are the following:
 * @option string    children    Elements selector for children to scroll
 * @option integer   startIndex  Element to jump to on first effect
 * @option integer   delay       Delay between each effect
 * @option boolean   jumpToTop   Whether to jump back to top at the end, or scroll back one by one
 * @option object    fxOptions   An options object, to be passed to Fx.Scroll
 * @option function  onNext      Fired when setting the index in preperation for the cycleNext function
 * @option function  onPrev      Fired when setting the index in preperation for the cyclePrev function
 * @option function  onStop      Fired when the loop is stopped
 *
 * Events return current index, next index.
 */
var LoopScroller = new Class({

	Implements: [Options, Events],
	
	/* Default optionset. */
	options: {
		children: 'div',
		startIndex: 1,
		delay: 2000,
		jumpToTop: true,
		fxOptions: {
			duration: 500
		},
		onNext: $empty, /* function(curId, nextId){console.log('onNext = cur: '+curId+' next: '+nextId);}, */
		onPrev: $empty, /* function(curId, nextId){console.log('onPrev = cur: '+curId+' next: '+nextId);}, */
		onStop: $empty  /* function(){console.log('onStop');} */
	},
	
	/* Class internals. */
	myFx: null,
	children: [],
	timeoutId: null,
	index: null,
	
	/* Init function. */
	initialize: function(context, options) {
		this.setOptions(options);
		this.context = $(context);
		if (!this.context) return;
		this.context.scrollTop = 0;
		var children = this.context.getChildren(this.options.children);
		if (children.length > 1) {
			this.children = children;
			this.myFx = new Fx.Scroll($(this.context), this.options.fxOptions);
			this.changeIndex(this.options.startIndex);
			this.timeoutId = this.cycleNext.delay(this.options.delay, this);
		}
	},
	
	/* Handles the changing of index and fires appropriate events. */
	changeIndex: function(index) {
		if (index < this.nextIndex) {
			this.fireEvent('onPrev', [this.index, index]);
		} else {
			this.fireEvent('onNext', [this.index, index]);
		}
		this.index = index;
	},
	
	/* Scrolls to next element untill last is reached,
	   then redirects to cyclePrev function. */
	cycleNext: function() {
		var index = this.index;
		if ($chk(index)) {
			if (index < this.children.length-1) {
				this.changeIndex(index+1);
				this.myFx.toElement(this.children[index]).chain(
					function(){
						this.timeoutId = this.cycleNext.delay(this.options.delay, this);
					}.bind(this)
				);
			} else {
				this.changeIndex((this.options.jumpToTop) ? 0 : index-1);
				this.myFx.toElement(this.children[index]).chain(
					function(){
						this.timeoutId = this.cyclePrev.delay(this.options.delay, this);
					}.bind(this)
				);
			}
		}
	},
	
	/* Scrolls to previous element untill first is reached,
	   then redirects to cycleNext function. */
	cyclePrev: function() {
		var index = this.index;
		if ($chk(index)) {
			if (index) {
				this.changeIndex(index-1);
				this.myFx.toElement(this.children[index]).chain(
					function(){
						this.timeoutId = this.cyclePrev.delay(this.options.delay, this);
					}.bind(this)
				);
			} else {
				this.changeIndex(index+1);
				this.myFx.toElement(this.children[index]).chain(
					function(){
						this.timeoutId = this.cycleNext.delay(this.options.delay, this);
					}.bind(this)
				);
			}
		}
	},
	
	/* Stop the whole loop. */
	stop: function() {
		if (this.timeoutId) $clear(this.timeoutId);
		if (this.nextIndex) this.nextIndex = null;
		this.fireEvent('onStop');
	}

});