var Fader = new Class({
	
	Implements: [Options],
	options: {
		fadeWaitTime: 3000, 				/* time to display item between fades */
		transition: Fx.Transitions.linear,	/* transition type to use */
		fadeTyepe: 'linear',				/* can be one of 'linear' or 'crossfade'. See demo page for more information */
		duration: 500,						/* duration of the transition */
		pauseOnHover: true,					/* Automatically add pause and resume mouse events on hover */
		indexItems: null,					/* array of items to use as a clickable index of all the rotating items. Optional */
		indexEventName: 'click'				/* event to watch for interaction on index items. would normally be click to jump to specific item */

	},
	
	initialize: function(container,options){
		
		if (!$(container)) return false;
		
		//set up the options (mainly just combines the defaults with whatever is passed in the options array)
		this.setOptions(options);
		
		//get the container node
		this.container = $(container);
		
		//get the direct children of the container. these are the bits that fade
		this.items = this.container.getChildren();
		
		//get the number of items to fade through. not really important
		this.itemsCount = this.items.length;
		
		/* Set the current item index to 0. this property is 
		used to determine which item is visiable (and to 
		calculate which item should be displayed next) */
		this.currentItem = 0;
		
		// used to determine if the auto-fading is running.
		this.isRunning = false;
		
		//hide all items except the first one
		this.items.each(function(currentItem,currentIndex) {

			currentItem.fadeEffect = new Fx.Tween(currentItem, { 
				property: ('opacity'),
				link: 'chain',
				transition: this.options.transition,
				duration: this.options.duration
			});
			
			if (currentIndex == 0) {
				currentItem.fadeEffect.set('opacity', 1);
			} else {
				currentItem.fadeEffect.set('opacity', 0);
			}
		},this);
		
		//add index clickability
		if (this.options.indexItems) {
			this.indexItems = $$(this.options.indexItems);
			this.indexItems.each(function(indexItem,indexItemIndex) {
				parentThis = this;
				indexItem.addEvent(this.options.indexEventName,function(e) {
					e.stop();
					this.fadeTo(indexItemIndex);
					this.stopAutoFade();
					return false;
				}.bind(parentThis));
				
				indexItem.addEvent('mouseleave',function(e) {
					e.stop();
					this.startAutoFade();
					return false;
				}.bind(parentThis));

			},this);
			
			this.indexItems.removeClass('active');
			this.indexItems[0].addClass('active');

		}
		
		
		//add events for pausing and resuming the sliding when on an item
		if (this.options.pauseOnHover) {
			this.items.addEvents({
				'mouseenter':function(){
					this.stopAutoFade();
				}.bind(this),
				
				'mouseleave':function(){
					this.startAutoFade();
				}.bind(this)
			});
		}
		
		//start the show!
		this.startAutoFade();
	
	},
		
	/* fade to an element elements. You can use natural language
	for the item you want to see, such as next, previous, first, last.
	Typically you'll want to view the 'next' item. This is how the auto
	fader works, and is the default if no index is specified. Of course, 
	you can also specify a numeric index of the item you want to view as
	well. */
	fadeTo: function( index ){
		
		// if it's not auto fading (
		if (index == "auto") { 
			index = 'next';
		} else {
			this.stopAutoFade();
			this.startAutoFade();
		}
		
		// if we're already in the middle of animating something, ignore change requests. 
		if (this.animating) return false;
		
		if (index == 'next') {
			index = this.currentItem+1;
		}
		
		if (index == 'previous') {
			index = this.currentItem-1;
		}
		
		if (index == 'first') {
			index = 0;
		}

		if (index == 'last') {
			index = this.itemsCount-1;
		}
		
		if (index > (this.itemsCount - 1)) {
			index = 0;
		}
		
		if (index < 0) {
			index = this.itemsCount - 1;
		}
		
		// don't do anything if the next item to show is the same as the current item
		if (this.currentItem == index) return false;
		
		var oldItem = this.items[this.currentItem];
		var newItem = this.items[index];
		
		
		if (this.indexItems) {
			this.indexItems.removeClass('active');
			this.indexItems[index].addClass('active');
		}
		
		newItem.setStyle('z-index',2); //place soon-to-be revealed image over the top
		oldItem.setStyle('z-index',1); //make sure old image is underneath it.
		
		// perform the fade!
		if (this.options.fadeTyepe == 'linear') {
			newItem.fadeEffect.start(0,1);
			oldItem.fadeEffect.start(1,0);		
		} else { //linear
			newItem.fadeEffect.start(0,1).chain(function() {
				oldItem.fadeEffect.set(0);
			}); 
		}
						
		//set the currently displayed item to the new index.
		this.currentItem = index;
	},
	
	// start autofading
	startAutoFade: function(){
		/* to prevent us from setting up multiple periodicals. 
		Things can go a bit wobbly otherwise.  */
		if (this.isRunning) return;
		this.isRunning = true;
		this.autoFade = this.fadeTo.periodical(this.options.fadeWaitTime, this, 'auto');
	},
	
	// stop autofading
	stopAutoFade: function() {
		$clear(this.autoFade);
		this.isRunning = false;
		return true;
	}

})

/*
Creates a native method extension method on the element object. 
Allows you to set it up like $('somecontainerid').fader([Options]).
Will automagically start fading between all children.
*/
Element.implement({
	fader: function(options){
		this.fader = new Fader(this,options);
		return this.fader;
	}
}); 

