(function($){
	var settings = {
		'afterSlide' : function (newSlide) {},
		'beforeSlide' : function (newSlide) {},
		'halfwaySlide' : function (newSlide) {},
		'initialDelay' : 500,
		'rotationDelay' : 6000,
		'crossFadeDuration' : 2000,
		'slideUpDuration' : 1250,
		'heightAdjustDuration' : 750
	};

	var methods = {
		init : function (slides, options) {
			if ( options ) { 
				$.extend(settings, options);
			}
			
			var slideshow = this;
				caption = null,
				height = 0,
				count = 0,
				currentIndex = 1,
				includeCaptions = false,
				hasInitialCaption = false;
				
			slideshow
				.data('timer', null)
				.data('slideShowActive', true);
			
			if (!!slides[0].caption) includeCaptions = true;

			$(slideshow)
				.addClass('active-slideshow')
				.find('img').addClass('slide-image-init');

			// Add a caption if one doesn't already exist
			if (includeCaptions) {
				if ($(slideshow).find('.caption').length == 0) {
					$(slideshow).append('<div class="caption"><a href="#"><p class="inset"><span></span></p></a></div>');
				}
				else {
					hasInitialCaption = true;
				}
				caption = $(slideshow).find('.caption');
				height = caption.height();
				caption.find('p').height(caption.find('span').height());
			}

			count = slides.length;

			$(slideshow).find('img')
				.css('opacity', 1)
				.css('z-index', 1);

			// Prefetch the slideshow's images
			for (var i = 0; i < count; i++) {
				$('<img/>')
					.css('opacity', 0)
					.css('z-index', 1)
					.attr('src', slides[i].image)
					.addClass('slide-image-' + (i + 1))
					.data('slide-show-index', (i + 1))
					.prependTo(slideshow);
			};

			// Initialize --------------------------------------------------------
			if (includeCaptions) {
				caption
					.css('bottom', -height)
					.css('opacity', 0);

				caption
					// We are skipping the first slide, so make sure to wait at least
					// one settings.rotationDelay before displaying the caption.
					.delay(settings.initialDelay + (hasInitialCaption ? 0 : settings.rotationDelay))
					.animate({
						bottom: 0,
						opacity: 1
					}, settings.slideUpDuration);
			}

			// Time it -----------------------------------------------------------
			var rotateTo = function (i) {
				var current = $(slideshow).find('.slide-image-' + (i == 1 ? count : (i - 1)));
				var next = $(slideshow).find('.slide-image-' + i);

				if (includeCaptions) {
					var captionContainer = $(slideshow).find('.caption p');
					var caption = slides[i-1].caption;

					if (caption != null && caption == '') captionContainer.hide();
					else captionContainer.show();

					var currentCaptionSpan = $(slideshow).find('.caption p span');
					var newCaptionSpan = $('<span>' + caption + '</span>').hide();
					captionContainer.prepend(newCaptionSpan);

					currentCaptionSpan.fadeOut(settings.crossFadeDuration, function () {
						currentCaptionSpan.remove();
						$(slideshow).find('.caption a').attr('href', slides[i-1].url);
					});

					newCaptionSpan.fadeIn(settings.crossFadeDuration);

					var growing = captionContainer.height() < newCaptionSpan.height();

					captionContainer
						.delay(growing ? 0 : settings.crossFadeDuration * 0.75)
						.animate({
							height: newCaptionSpan.height()
						}, settings.heightAdjustDuration);
				}
				
				settings.beforeSlide.call(this, next);
				
				var halfway = function () {
					if (slideshow.data('slideShowActive'))	{
						settings.halfwaySlide.call(this, next);
					}
				};
				var half = setTimeout(halfway, (settings.crossFadeDuration * 0.5));
				
				next
					.css('z-index', 2)
					.animate({
						opacity: 1
					}, settings.crossFadeDuration, function () {
					if (slideshow.data('slideShowActive'))	{
							current.css('opacity', 0)
							next.css('z-index', 1);
							if ($(slideshow).find('.slide-image-init').length > 0) $(slideshow).find('.slide-image-init').remove();
							settings.afterSlide.call(this, next);
						}
					});
			};

			var rotate = function () {
				if (!!slideshow.data('timer')) {
					currentIndex = (currentIndex >= count) ? 1 : currentIndex + 1;
					rotateTo(currentIndex);
					slideshow.data('timer', setTimeout(rotate, settings.rotationDelay));
				}
			}
			
			slideshow.data('timer', setTimeout(rotate, settings.rotationDelay));
		},
		stop : function () {
			var slideshow = this;
			clearTimeout(slideshow.data('timer'));
			slideshow.data('timer', null);
		},
		destroy : function () {
			var slideshow = this;
			
			if (!!slideshow.data('slideShowActive')) {
				slideshow
					.slideShow('stop');
			
				slideshow.data('slideShowActive', null);
				
				slideshow
					.removeClass('active-slideshow')
					.find('img').each(function () {
						if ($(this).data('slide-show-index') == 1) {
							$(this)
								.css('opacity', 1)
								.removeClass('slide-image-' + $(this).data('slide-show-index'))
								.data('slide-show-index', null)
								.show();
						}
						else {
							$(this).remove();
						}
					});
			}	
		}
	};

	$.fn.slideShow = function (method) {
		// Method calling logic
		if ( methods[method] ) {
			return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
		}    
	};
})(jQuery);

