/** 
 * ContentONE Rotator
 *
 * Automatically rotates between a series of images.
 *
 * @version		1.3
 * @date		January 25, 2011
 * @author		Brad Harrison
 * @copyright	(c) World Web Management Services (http://www.worldwebms.com/)
 */
(function($) {

	/**
	 * Create C1 jQuery extension.
	 */
	if( !$.fn.c1 ) {
		$.fn.c1 = function( name, options ) {
			if( this.c1[name] )
				return this.c1[name].call( this, options );
			return this;
		}
	}
	
	/**
	 * Create C1 Rotator jQuery extension.
	 */
	$.fn.c1.rotator = function( options ) {
		return this.each( function() {
			options.images = $(options.images ? options.images : '.c1-rotator-image', this);
			options.thumbs = $(options.thumbs ? options.thumbs : '.c1-rotator-thumb', this);
			if( options.count > 0 ) {
				options.next = $(options.next ? options.next : '.c1-rotator-next', this);
				options.prev = $(options.prev ? options.prev : '.c1-rotator-prev', this);
			}
			$.fn.c1.rotator.manager.init( options );
		} );
	};
	
	/**
	 * Create C1 Rotator management class.
	 */
	$.fn.c1.rotator.manager = {
		
		id: 0,
		config: [],
	
		/**
		 * Initialises an image rotator.
		 * @param	object config The configuration
		 */
		init: function( config ) {
		
			// Update the configuration
			config.images = config.images;
			config.thumbs = config.thumbs;
			config.pos = 0;
			config.speed *= 1000;
			config.animating = false;
			config.preload = {};
			if( config.fade == null )
				config.fade = 'slow';
			if( config.delay == null )
				config.delay = 0;
			
			// Setup the configuration
			var id = this.id++;
			this.config[id] = config;
			
			// Stop the images from rotating when the mouse moves over them
			this.config[id].images.each( function( i ) {
				$(this).hover(
					function() {
						$.fn.c1.rotator.manager.stop( id );
					},
					function() {
						$.fn.c1.rotator.manager.start( id );
					}
				);
			} );
			
			// Intercept hover events
			if( config.hover == true ) {
				this.config[id].thumbs.each( function( i ) {
					$(this).hover(
						function() {
							$.fn.c1.rotator.manager.show( id, i, false );
						},
						function() {
							$.fn.c1.rotator.manager.start( id );
						}
					);
				} );
				
			// Intercept onclick events for thumbnails
			} else {
				this.config[id].thumbs.each( function( i ) {
					$(this).click( function() {
						$.fn.c1.rotator.manager.show( id, i );
						return false;
					} );
					$('a', this).click( function() {
						$.fn.c1.rotator.manager.show( id, i );
						return false;
					} );
				} );
				
			}
			
			// If only a certain number of thumbs should be shown
			if( config.count > 0 ) {
				config._top = 0;
				
				// Attach event handlers
				if( config.next ) {
					config.next.click( function() {
						$.fn.c1.rotator.manager.next( id );
					} ).css( 'cursor', 'pointer' )[ config.count > config.thumbs.length ? 'show' : 'hide' ]();
				}
				if( config.prev ) {
					config.prev.click( function() {
						$.fn.c1.rotator.manager.prev( id );
					} ).css( 'cursor', 'pointer' )[ config.count > config.thumbs.length ? 'show' : 'hide' ]();
				}
				
				// Hide other thumbs
				$.fn.c1.rotator.manager.thumbs( id );
				
			}
			
			// If the first image must be preloaded
			if( config.images.length > 0 && $(config.images[0]).css( 'display' ) == 'none' ) {
				config.pos = 999999;
				this.preload( id, 0, function() {
					jQuery.fn.c1.rotator.manager.show( id, 0, true );
				} );
				
			// Immediately start the rotation
			} else if( config.delay == 0 )
				this.start( id );
			
			// Delay the rotation
			else
				window.setTimeout( 'jQuery.fn.c1.rotator.manager.next( ' + id + ' );', config.delay * 1000 );
			
			return id;
		},
		
		/**
		 * Preload all images for the next image.
		 */
		preload: function( id, pos, callback ) {
			var config = this.config[id];
			
			// If no position was given
			if( pos == null )
				pos = config.pos + 1;
			if( pos >= config.images.length )
				pos = 0;
			
			// If the item has already been preloaded, skip over it
			var preload = config.preload;
			if( preload[pos] != null )
				return;
			
			// Determine what background images need to be loaded
			preload[pos] = [];
			$(config.images[pos]).find( '*[style]' ).each( function() {
				if( $(this).css( 'display' ) != 'none' ) {
					var src = $(this).css( 'background-image' );
					if( src.indexOf( 'url(' ) >= 0 ) {
						var image = new Image();
						if( callback )
							image.onload = callback;
						image.src = src.replace( /["')]/g, '' ).replace( /url\(/g, '' );
						preload[pos].push( image );
					}
				}
			} );
			
		},
		
		/**
		 * Displays the previous image in a specific group.
		 * @param	integer id The id of the group
		 */
		prev: function( id ) {
			
			// Determine the previous position
			var pos = this.config[id].pos - 1;
			if( pos < 0 )
				pos = this.config[id].images.length - 1;
			
			// Display the image
			this.show( id, pos, true );
			
		},
		
		/**
		 * Displays the next image in a specific group.
		 * @param	integer id The id of the group
		 */
		next: function( id ) {
		
			// Determine the next position
			var pos = this.config[id].pos + 1;
			if( pos >= this.config[id].images.length )
				pos = 0;
			
			// Display the image
			this.show( id, pos, true );
				
		},
		
		/**
		 * Shows a specific image in the group.
		 * @param	integer id The id of the group
		 * @param	integer pos The position to display
		 * @param	boolean rotate True to continue rotating; false to stop rotating
		 */
		 show: function( id, pos, rotate ) {
		 	var t = this, config = t.config[id];
		 
		 	// Clear any existing timeouts
		 	t.stop( id );
		 	
		 	// If the next position should be used
		 	if( pos < 0 ) {
		 		rotate = config._next.rotate;
		 		pos = config._next.pos;
		 		config._next = null;
		 	}
		 	
		 	// If there is currently an animation, then delay the showing
		 	if( config.animating ) {
		 		config._next = {pos: pos, rotate: rotate};
		 		return;
		 	}
		 		
		 	// As long as the position has changed
		 	if( config.pos != pos ) {
		 
			 	// Determine the current and next image
				var next = $(config.images[pos]);
				var existing = (config.images[config.pos] ? $(config.images[config.pos]) : $('null'));
				
				// Reset the active class on the existing thumb
				var thumb = config.thumbs[config.pos];
				if( thumb ) {
					if( config.thumbFade == null ) {
						t.flip( $(thumb).removeClass( 'c1-rotator-thumb-active' ).find( 'img' ) );
						t.flip( $(config.thumbs[pos]).addClass( 'c1-rotator-thumb-active' ).find( 'img' ) );
					} else {
						var thumbNew = $(config.thumbs[pos]).css( 'z-index', 11 );
						$(thumb).css( 'z-index', 10 );
						t.flip( thumbNew.addClass( 'c1-rotator-thumb-active' ).hide().find( 'img' ) );
						thumbNew.fadeIn( config.thumbFade, function() {
							t.flip( $(thumb).removeClass( 'c1-rotator-thumb-active' ).hide().find( 'img' ) );
						} );
						if( config.thumbFadeOut )
							$(thumb).fadeOut( config.thumbFade );
					}
				}
				
				// Fade in the new image
				config.pos = pos;
				if( config.fade != 0 ) {
					config.animating = true;
					existing.css( 'z-index', 1 );
					next.css( 'z-index', 2 ).fadeIn( config.fade, function() {
						existing.hide();
						$.fn.c1.rotator.manager.config[id].animating = false;
						if( $.fn.c1.rotator.manager.config[id]._next != null )
							window.setTimeout( 'jQuery.fn.c1.rotator.manager.show( ' + id + ', -1 );', 10 );
					} );
					if( config.fadeOut )
						existing.fadeOut( config.fade );
				} else {
					existing.hide();
					next.show();
					if( config._next != null )
						window.setTimeout( 'jQuery.fn.c1.rotator.manager.show( ' + id + ', -1 );', 10 );
				}
				
			}
		 	
		 	// If only a certain number of thumbnails are to be shown
		 	if( config.count > 0 ) {
		 		if( config.pos < config._top ) {
		 			config._top = config.pos;
		 		} else if(config.pos >= (config._top + config.count)) {
		 			config._top = config.pos - config.count + 1;
		 		}
		 		t.thumbs( id );
		 	}
		 	
			// Continue automatic rotation if requested
			if( rotate == null || rotate == true )
				t.start( id );
			
		 },
		 
		 /**
		  * Starts the rotation for the given id.
		  * @param	integer id The id of the group
		  */
		 start: function( id ) {
			this.config[id].timeout = window.setTimeout( 'jQuery.fn.c1.rotator.manager.next( ' + id + ' );', this.config[id].speed );
			jQuery.fn.c1.rotator.manager.preload( id );
		 },
		 
		 /**
		  * Stops the rotator for the given id.
		  * @param	integer id The id of the group
		  */
		 stop: function( id ) {
		 	if( this.config[id].timeout ) {
			 	window.clearTimeout( this.config[id].timeout );
			 	this.config[id].timeout = null;
			 }
		 },
		 
		 /**
		  * Shows or hides the thumbnail images
		  */
		 thumbs: function( id ) {
			var config = this.config[id];
			var start = config._top;
			var end = start + config.count;
			var classes = [];
			for( var i = 0; i < config.count; i++ )
				classes.push( 'c1-rotator-thumb-pos' + ( i + 1 ) );
			config.thumbs.each( function( i ) {
				$(this)[ i >= start && i < end ? 'show' : 'hide' ]().removeClass( classes.join( ' ' ) );
				$('a', this).removeClass( classes.join( ' ' ) );
				var className = classes[i - start];
				if( className ) {
					$(this).addClass( className );
					$('a', this).addClass( className );
				}
			} );
			if( config.next )
				config.next[ config.pos < ( config.thumbs.length - 1 ) ? 'show' : 'hide' ]();
			if( config.prev )
				config.prev[ config.pos == 0 ? 'hide' : 'show' ]();
		 },
		 
		 /**
		  * Flips the src and background image of the specified element.
		  * @param	object jQuery element The element to update
		  */
		 flip: function( element ) {
			if( element.length == 0 )
				return;
		 	var bg = element.css( 'background-image' ).replace( /[)"']/g, '' ).replace( /url\(/g, '' );
		 	var src = element.attr( 'src' );
		 	if( src && bg && bg != 'none' ) {
			 	element.attr( 'src', bg );
			 	element.css( 'background-image', 'url(' + src + ')' );
			 }
		 }
	
	};
	
})(jQuery);
