/* jQuery plugin: crossFadeCarousel */

(function($){
	
$.fn.crossFadeCarousel = function(options){
	var defaults = {
		slides: [], 			// the individual slide element
		autoplay: true, 		// carousel will automatically start playing through the slides
		autotime: 7000, 		// the time each slide will stay on screen for before transitioning
		loop: true,				// play over once the last slide has been reached
		maxRevolutions: 2,		// how many times to loop
		currentRevolution: 0,	// which revolution the loop is currently on
		intime: 600,			// fade in slide time
		outtime: 400,			// fade out slide time
		transition: 'linear',	// transition easing type (jQuery core: linnear or swing, other options would require further jQuery plugins)
		navlinks: false,		// includes a navigation panel for the carousel
		navigation: {			// optional navigation parameters to build a navigation DOM element out of
			id: 'carouselnav', 			// navigation parent div id
			parenttag: 'ul',				
			childtags: 'li',
			activeclass: 'on',			// the navlink on-state
			leftclass: 'endl',			// first navlink container
			rightclass: 'endr',			// last navlink container
			injectlocation: 'after',	// after, before, append or prepend
			pausethenreplay: true		// if set to false, clicking on navigation will override the autoplay option and stop the animation
			/* HTML structure for navigation:
			 * <div id="carouselnav">
			 *		<ul>
			 *			<li class="endl"><a class="on" href="#" title="1">1</a></li>
			 *			<li><a href="#" title="2">2</a></li>
			 *			...
			 *			<li class="endr"><a href="#" title="N">N</a></li>
			 *		</ul>
			 *	</div>
			 */
		},
		fixtransparentpngs: {	// optional settings to fix transparent png slides in IE browsers
			set: false,
			bgcolor: null,
			bgcss: null
		},
		fadebody: { 			// to fade the body background-colour requires jquery.color.js plugin
			set:false,
			cssInfo: []			// simple array to pass in colors for body fade, one for each slide
		}		
	};
	
	var opts = $.extend(true, defaults, options);
	
	return this.each(function(){
		
		var $self = $(this);
		$self.position = 0;
		
		// quick checks that we have what we need to continue
		if(opts.slides[0] == undefined) {
			console.log('crossFadeCarousel plugin: no slide elements defined');
			return;
		}
		
		// fade body background-colour is set to true? check we have an array with colours in
		if(opts.fadebody.set != false){
			if (opts.fadebody.cssInfo.length == 0) {
				console.log('crossFadeCarousel plugin: fadebody is set to true, so you need to supply a list of colors to fade the body (one for each slide)');
				return;
			}
		}
		
		// if there is more than 1 slide, the animation can go ahead
		if(opts.slides.length > 1){
			
			$self.slidenum = opts.slides.length -1;
			
			// if navlinks has been defined, build the navigation element(s)
			if(opts.navlinks) var navstring = '<' + opts.navigation.parenttag + '>', controller = $('<div id="' + opts.navigation.id + '"></div>'), navlinks = [];
 

			// go through the list of slides and make all but the first one hidden
			opts.slides.each(function(i, v){
				if(i != 0) $(v).hide();
				if (opts.navlinks) {
					if(i==0) {
						navstring += '<' + opts.navigation.childtags + ' class="' + opts.navigation.leftclass + '"><a href="#">' + (i +1) + '</a></' + opts.navigation.childtags + '>';
					} else if(i == $self.slidenum) {
						navstring += '<' + opts.navigation.childtags + ' class="' + opts.navigation.rightclass + '"><a href="#">' + (i +1) + '</a></' + opts.navigation.childtags + '>';
					} else {
						navstring += '<' + opts.navigation.childtags + '><a href="#">' + (i +1) + '</a></' + opts.navigation.childtags + '>';
					}
				}
			});
			
			if(opts.navlinks) {
				navstring += '</' + opts.navigation.parenttag + '>';
				controller.html(navstring);
				switch(opts.navigation.injectlocation){
					case 'before':
						$self.before(controller);
						break;
					case 'append':
						$self.append(controller);
						break;
					case 'prepend':
						$self.prepend(controller);
						break;
					default:
						$self.after(controller);
				}
				navlinks = $('#'+opts.navigation.id+' a');
				$(navlinks[0]).addClass(opts.navigation.activeclass);
			
				$(navlinks).click(function(){
					if(opts.autoplay){
						$self.pause();
						if (opts.navigation.pausethenreplay) {
							$self.playthrough();
						}
					}
					$self.to($(this).text());
					return false;
				});
			}
			
			$self.transition = function(stack, from, to){
				var fromethis = $(stack[from]), tothis = $(stack[to]), flag = 0;
				if(from != to){
					fromethis.animate({'opacity': 'toggle'}, {duration:opts.outtime, easing:opts.transition});
					tothis.animate({'opacity': 'toggle'}, {
						duration:opts.intime, 
						easing:opts.transition, 
						step: function(now, fx){
							if (fx.prop == 'opacity') {
								if(flag !=1 && now > 0){
									if(opts.fadebody.set != false && opts.fadebody.cssInfo.length > 0){
										$('body').animate({'backgroundColor': opts.fadebody.cssInfo[to]}, {duration:opts.outtime*0.9, easing:opts.transition});
									}
									flag=1;
								}
							}
						}
					});
				}	
			}; 
		
			$self.next = function(){
				var next = $self.position +1 > $self.slidenum ? 0 : $self.position +1;
				if(opts.loop != true && next == $self.slidenum) $self.pause();
				if(next == 0){ opts.currentRevolution++; }
				if(opts.currentRevolution >= opts.maxRevolutions) $self.pause();
				$self.transition(opts.slides, $self.position, $self.position = next);
				$self.changenavstate($self.position);			
			};
		
			$self.prev = function(){
				var prev = $self.position -1 < 0 ? $self.slidenum : $self.position -1;
				$self.transition(opts.slides, $self.position, $self.position = prev);	
				$self.changenavstate($self.position);		
			};
		
			$self.to = function(n){
				$self.transition(opts.slides, $self.position, $self.position = (n-1));
				$self.changenavstate(n-1);
			};

			$self.playthrough = function(){
				$self.interval = window.setInterval(function(){
					$self.next();
				}, opts.autotime);			
			};
		
			$self.pause = function(){
				$self.interval = window.clearInterval($self.interval);
				$self.changenavstate($self.position);
			};
			
			$self.fixpngs = function(){
				/* IE7 and 8 don't fade tranparent pngs content well: it loses the alpha channel and defaults to black until the opacity is 100% or 0% 
				This is a known IE bug. 
				The simplest fix is to apply a solid background colour to the image/parent div; i'm adding to the image
				If this isn't possible, then apply the AlphaLoader fix, this will reduce the black, but won't necessarily remove it enitirely */
				
				if(opts.fixtransparentpngs.set != false){

					// test for IE7 & 8
					if (window.XMLHttpRequest && document.all) {
					
						// get list of pngs
						$self.pngs = $(opts.slides).find('img[src$=.png]').toArray();
						if (opts.fixtransparentpngs.bgcss != null) {
							$self.pngs = $self.pngs.concat($(opts.fixtransparentpngs.bgcss).toArray());
						}
						
						if (opts.fixtransparentpngs.bgcolor != null) {
							// use the solid bgcolour fix	
							$.each($self.pngs, function(i, p){
								$(p).css('backgroundColor', opts.fixtransparentpngs.bgcolor);
							})
						} else {
							// use the AlphaLoader fix suggested by http://www.snutt.net/testzon/ie_alpha/
							$.each($self.pngs, function(i, p){
								if($(p).attr('src') != undefined){
									$(p).css('filter', 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\''+$(p).attr('src')+'\')');
								}
							});
						}
					}
				}
				
			};
			
			$self.changenavstate = function(n){
				if (opts.navlinks){
					$(navlinks).removeClass(opts.navigation.activeclass);
					$(navlinks[n]).addClass(opts.navigation.activeclass);
				}
			};

			// start the carousel playing if autoplay is true
			if(opts.autoplay != false) $self.playthrough();
			$self.fixpngs();
		}
	});
	
	
};
	
})(jQuery)







