(function($) { /* written by Biko Allen (biko@redgiantsoftware.com) */
	$.fn.rgCrossFader = function(settings) {
	
		var publicAccessorLabel = 'rgCrossFader.publicAccessor';
		var configLabel = 'rgCrossFader.config';

		if (typeof(this.data(publicAccessorLabel)) !== 'undefined' && this.data(publicAccessorLabel) !== null) {
			var pa = this.data(publicAccessorLabel);
			var cg = this.data(configLabel);
			var args = Array.prototype.slice.apply(arguments);
			if (args.length > 0) {
				if (typeof(args[0]) === 'object') {
					if (settings) $.extend(cg, settings);
					var args = Array.prototype.slice.apply(arguments);
					if (args.length > 1) {
						args = args.slice(1,args.length);
					} else {
						pa.start();
						return this;
					}
				}
				if (arguments.length === 1) {
					pa[arguments[0]]();
				} else if (arguments.length > 1) {
					var args = Array.prototype.slice.apply(arguments);
					args = args.slice(1,args.length);
					pa[arguments[0]].apply(this,args);
				}
			}
			return this;
		} 	
		
		var config = {
			'slideType':'fade',
			'index':0,
			'showTime':5000,
			'transitionTime':750,
			'doHoverPause':true, 
			'maxZIndex':100, 
			'slideChange':null, 
			'direction':'forward'
		},
		$timeOut = null,
		itemArray = [],
		blockAnimation = false,
		lastIndexRequest = -1,
		$self = this,
		$window = $(window),
		$body = $('body');
		
		if (settings) $.extend(config, settings);
		
		function cancelSlideShow() {
			if ($timeOut !== null) { window.clearInterval($timeOut); $timeOut = null; }
		}

		function doSlideShowNow() {
			if (blockAnimation) {
				if (arguments.length > 0) {
					lastIndexRequest = arguments[0];
				}
				return;
			}
			var currentIndex = config.index;
			var nextIndex = (arguments.length > 0) ? arguments[0] : (config.index >= itemArray.length - 1) ? 0 : config.index + 1;
			if (config.direction === 'backward') {
				if (currentIndex === 0) {
					nextIndex = itemArray.length - 1;
				} else {
					nextIndex = currentIndex - 1;
				}
			}
			if (currentIndex == nextIndex) { return; }
			var $f = itemArray[currentIndex].show(),
			$n = itemArray[nextIndex];			
			blockAnimation = true;
			doneF = function () {
				$f.hide();
				blockAnimation = false;
				if (lastIndexRequest != -1) {
					doSlideShowNow(lastIndexRequest);
					lastIndexRequest = -1;
				}
			};
			$f.css('z-index',(config.maxZIndex-1)+'');
			$n.css('z-index',config.maxZIndex+'');
			switch (config.slideType) {
				case 'fade' : 
					$n.fadeIn(config.transitionTime,doneF);
					break;
				case 'fadeInOut' : 
					$f.fadeOut(config.transitionTime,null);
					$n.fadeIn(config.transitionTime,doneF);
					break;
			}
			if (config.slideChange !== null) {
				config.slideChange(nextIndex);
			}
			config.index = nextIndex;
		}

		function doSlideShow() {
			cancelSlideShow();
			$timeOut = window.setInterval(function() {
				doSlideShowNow();
			},config.showTime);
		}

		$self.each(function() {
			(itemArray.length === config.index) ? $(this).show() : $(this).hide();
			if (itemArray.length === 0) {
				if (config.doHoverPause) {
					$(this).parent().hover(
						function() {
							cancelSlideShow();
						},
						function() {
							cancelSlideShow();
							doSlideShow();
						}
					);
				}
			}
			itemArray[itemArray.length] = $(this);
		});
		
		
		var publicAccessor = {
			'jump' : function (index) {
				cancelSlideShow();
				doSlideShowNow(index);
				doSlideShow();
				return publicAccessor;
			},
			'start' : function () {
				$self.children().hide();
				itemArray[config.index].show();
				config.direction = 'forward';
				doSlideShow();
			},
			'stop' : function () {
				cancelSlideShow();
			},
			'next' : function () {
				config.direction = 'forward';
				cancelSlideShow();
				doSlideShowNow();
				doSlideShow();
			},
			'previous' : function () {
				config.direction = 'backward';
				cancelSlideShow();
				doSlideShowNow();
				config.direction = 'forward';
				doSlideShow();
			}
		};
		
		this.data(publicAccessorLabel,publicAccessor);
		this.data(configLabel,config);
		
		doSlideShow();
		
		return this;
	};
})(jQuery);
