/**
 * jQuery 'evented' slideshow plugin
 * Created by Mark Perkins, mark@allmarkedup.com
 * 
 * Provides a **low-level**, event-driven slideshow implementation. Different transition
 * types are supplied by extensions.
 * 
 * For more info check out http://allmarkedup.com 
 */

;(function($) {
	
	var defaults = {
		startSlide	: 1,			// which slide to start the slideshow on. NOT zero-indexed. 
		speed 		: 1000,			// the transition speed from slide to slide
		wait		: 3000, 		// the pause between changing slides when autoPlay is on
		transition 	: 'basic',		// the transition type to use. anything other than 'basic' will require a plugin extension to be included.
		atEnd		: 'stop', 		// the behaviour that the slideshow displays when at the end of the slideshow. Options: loop, stop
		autoPlay	: false,		// whether to start auto-playing ths slideshow on load.
		autoPlayDirection : 'forwards',	// the direction of the auto-play
		wrapperCSS	: {},			// CSS styles applied to the wrapper element. Can be used by extensions.
		innerCSS	: {},			// CSS styles appliend to the 'inner wrapper'. Can be used by extensions.
		slideCSS	: {}			// CSS styles appliend to the individual slideshow items. Can be used by extensions.
	},
	_this = this,
	intervals = [],
	timeouts = [];
	
	$.fn.evtslideshow = function( options )
	{
		return this.each(function(){

			var opts = $.extend(true, {}, defaults, options); // merge defaults with user supplied options
			var $wrap = opts.$wrapper = $(this);
			
			$wrap.bind( 'jump.evtslideshow', function( e, slideNum ){ goTo( opts, slideNum-1 ); });
			$wrap.bind( 'next.evtslideshow', function(){ next( opts ); });
			$wrap.bind( 'prev.evtslideshow', function(){ prev( opts ); });
			$wrap.bind( 'refresh.evtslideshow', function(){ refresh( opts ); });
			$wrap.bind( 'play.evtslideshow', function( e ){ autoPlayStart( opts ); });
			$wrap.bind( 'pause.evtslideshow', function( e, duration ){ autoPlayPause( opts, duration ); });

			setUp( opts );
		});
	};
	
	function setUp( opts )
	{
		opts.$slides 		=	opts.$wrapper.children();
		opts.totalSlides	=	opts.$slides.size();
		opts.currentSlide	=	opts.startSlide - 1;
		opts.first 			=	isFirstSlide( opts, opts.currentSlide );
		opts.last 			=	isLastSlide( opts, opts.currentSlide );
		opts.transition		= 	$.fn.evtslideshow.transition[opts.transition];
		opts.$inner			=	$('<div></div>');
		opts.ref			= 	new Date().getTime();
		opts.dir			=	'next';
		
		opts.$wrapper.append(opts.$inner);
		opts.$inner.append(opts.$slides);
		
		if ( opts.transition.styles != undefined ) opts = $.extend(true, {}, opts, opts.transition.styles );
		
		opts.$wrapper.data('evtslideshow_playing', false);
	
		opts.$wrapper.css(opts.wrapperCSS);
		opts.$inner.css(opts.innerCSS);
		opts.$slides.css(opts.slideCSS);
		
		opts.transition.setUp( opts, function(){
			opts.$wrapper.trigger( 'initialized.evtslideshow', [opts.currentSlide+1, opts.totalSlides] );
			onFinish( opts, opts.currentSlide );
			if ( opts.autoPlay === true ) autoPlayStart( opts );
		});
	}

	function refresh( opts )
	{
		opts.startSlide = opts.currentSlide+1;
		setUp( opts );
	}
	
	function next( opts )
	{
		opts.dir = 'next';
		switch( opts.atEnd )
		{
			case 'loop': case 'rewind': goTo( opts, (opts.last ? 0 : opts.currentSlide + 1) ); break;
			default: goTo( opts, (opts.last ? opts.totalSlides - 1 : opts.currentSlide + 1) ); break; // stop when getting to last page 
		}
	}
	
	function prev( opts )
	{
		opts.dir = 'prev';
		switch( opts.atEnd )
		{
			case 'loop': case 'rewind': goTo( opts, (opts.first ? opts.totalSlides - 1 : opts.currentSlide - 1) ); break;
			default: goTo( opts, (opts.first ? 0 : opts.currentSlide - 1) ); break; // stop when getting to first page 
		}
	}
	
	function goTo( opts, slideNum )
	{	
		if ( ! opts.$slides.eq(opts.currentSlide).is(':animated') && ! opts.$inner.is(':animated') )
		{
			opts.$wrapper.trigger( 'started.evtslideshow', opts.currentSlide+1 );
			
			if ( opts.currentSlide != slideNum )
			{
				opts.transition.action.call( _this, opts, slideNum, function(){
					
					onFinish( opts, slideNum );
				});
			}
		}
	}
	
	onFinish = function( opts, slideNum )
	{
		opts.currentSlide = slideNum;
		opts.first = isFirstSlide( opts, opts.currentSlide ) ? true : false;
		opts.last = isLastSlide( opts, opts.currentSlide ) ? true : false;
		
		if ( opts.$wrapper.data('evtslideshow_playing') === true ) autoPlayStart( opts );
		
		opts.$wrapper.trigger( 'finished.evtslideshow', [opts.currentSlide+1, opts.first, opts.last] );	
	}
	
	function autoPlayStart( opts )
	{
		clearAutoPlay( opts );
		var action = opts.autoPlayDirection == 'backwards' ? prev : next;
		intervals[opts.ref] = setInterval( function(){ action( opts ); }, opts.wait );
		opts.$wrapper.data('evtslideshow_playing', true);
	}

	function autoPlayPause( opts, duration )
	{
		clearAutoPlay(opts);
		if ( duration !== undefined )
		{
			timeouts[opts.ref] = setTimeout.call( _this, function(){ autoPlayStart( opts ); }, duration );
		}
		opts.$wrapper.data('evtslideshow_playing', false);
	}
	
	function clearAutoPlay( opts )
	{
		if ( intervals[opts.ref] !== undefined ) { clearInterval( intervals[opts.ref] ); }
		if ( timeouts[opts.ref] !== undefined ) { clearTimeout( timeouts[opts.ref] ); }
	}
	
	$.fn.evtslideshow.transition = {};
	
	$.fn.evtslideshow.transition.basic = {
		
		setUp : function( opts, callback )
		{
			opts.$slides.filter(':not(:eq('+opts.currentSlide+'))').hide();
			callback();
		},
		
		action : function( opts, slideNum, callback )
		{
			opts.$slides.eq(opts.currentSlide).hide();
			opts.$slides.eq(slideNum).show();
			callback();
		}
	};
	
	// utility functions
	
	function isFirstSlide( opts, internalPageNum ) { return ( internalPageNum === 0 ); }
	function isLastSlide( opts, internalPageNum ) { return ( internalPageNum === opts.totalSlides-1 ); }
	
})(jQuery);
$.fn.evtslideshow.transition.fade = {
	
	styles : {
		wrapperCSS : {
			position : 'relative'
		},
		slideCSS : {
			position : 'absolute',
			top : 0,
			left: 0
		}
	},
	
	setUp : function( opts, callback )
	{
		opts.$slides.filter(':not(:eq('+opts.currentSlide+'))').hide();
		callback();
	},
	
	action : function( opts, slideNum, callback )
	{
		opts.$slides.eq(opts.currentSlide).fadeOut( opts.speed );
		opts.$slides.eq(slideNum).fadeIn( opts.speed, function(){
			callback();
		});
	}
};