/* =========================================================

jquery.jcycle.js

Date: 2009-05-04
Author: Rob Lehman
Mail: rob@roblehman.com
Web: http://www.roblehman.com/jcycle/

Based on...
 • InnerFade by Torsten Baldes, http://medienfreunde.com/lab/innerfade/
 • Slideshow by Matt Oakes, http://portfolio.gizone.co.uk/applications/slideshow/

Requires:
 • The jQuery library, version 1.3.2 or later, http://jquery.com/

Optional:
 • The Cookies plugin by JA Auldridge, http://code.google.com/p/cookies/
 	» Required if option startfromcookie is true
 • The Easing plugin by George Smith, http://gsgd.co.uk/sandbox/jquery/easing/
 	» Adds extra effects for motion animations

To use this plugin:

 1. Create a parent element whose direct descendants are the objects to cycle. The child elements can be anything:
 	images, divs, etc. They do not need any specific ID or class names. There can also be child elements you do NOT want
	to cycle; if so, use the children option (see below) to filter these out.
	
 2. Call jCycle from the parent element:
 	a.	Simple call:
	
			$('selector-for-parent').jcycle();
	
	b.	With options:
		
			$('selector-for-parent').jcycle({
				animationtype:    	'fade', 	// 'fade', 'slide', 'sideways', 'corner', 'wipe', or 'none'
				speed:            	'normal',	// Time of transition: 'normal','slow','fast', or a number in milliseconds
				type:             	'sequence', // 'sequence', 'random', or 'random_start'
				timeout:          	2000,		// Time to wait between transitions: 'normal','slow','fast', or a number in milliseconds
				containerheight:  	'100%',
				containerwidth:		'100%',
				runningclass:     	'jcycle',	// a CSS class name to apply to the container
				children:         	null,		// a jQuery selector string to cycle only certain children of the container; leave null to use all children
				animatefirst:		false,		// true or false, animates with the same effect as animationtype unless overruled with firstanimation
				firstanimation:		'default',	// 'default' plus same options as animationtype; uses a different animation for the first (only applicable if animatefirst is true)
				firstspeed:			'default',	// 'default' plus same options as speed; uses a different time for the first animation (only applicable if animatefirst is true)
				showcontrolbox:		'never',	// 'never', 'always', 'hover', 'semihover' (fades to 50% opacity on mouseout)
				showcaptions:		false,		// takes data from the 'data-caption' attribute of each slide div
				captionalignment:	'left',		// left or right
				captionprefix:		'',			// text prepended to the captions for all objects
				startfromcookie:	false,		// overrides the "random_start" type; starts the cycle on whatever was last active
				easingtype:			'easeOutQuad'	// needs the easing plugin; see documentation (URL above) for options
			});

// ========================================================= */


(function($) {

	var cycleTimer;
	var firstDone;

    $.fn.innerfade = function(options) {
        return this.each(function() {   
            $.innerfade(this, options);
        });
    };

    $.innerfade = function(container, options) {
        var settings = {
       		animationtype:		'fade',
            speed:				'normal',
            type:				'sequence',
            timeout:			2000,
            containerheight:	'100%',
			containerwidth:		'100%',
            runningclass:   	'innerfade',
            children:       	null,
			animatefirst:		false,
			firstanimation:		'default',
			firstspeed:			'default',
			showcontrolbox:		'never',
			showcaptions:		false,
			captionprefix:		'',
			captionalignment:	'left',
			startfromcookie:	false,
			easingtype:			'easeOutQuad'
        };
        if (options) $.extend(settings, options);
		
		var elements = new Object();
        if (settings.children === null) elements = $(container).children();
        else elements = $(container).children(settings.children);
		var captions = new Object();
		
		//Resolve timer keywords to their millisecond counterparts so they can be compared and manipulated
		resolveTimer = function(timer) {
			switch (timer.toString().toLowerCase()) {
				case 'normal': return 400; break;
				case 'fast': return 200; break;
				case 'slow': return 600; break;
				default: return timer;
			}
		};
		settings.speed = resolveTimer(settings.speed);
		settings.timeout = resolveTimer(settings.timeout);
		if (settings.firstspeed.toString().toLowerCase()=='default') settings.firstspeed = settings.speed;
		settings.firstspeed = resolveTimer(settings.firstspeed);
		// Adjust timeout to include the speed time. The function uses timeout so that the timer starts when the animation STARTS,
		// not when it ends. If speed > timeout, the effect will be chaos. Timeout is adjusted here to avoid that problem, and
		// to make it easier to describe its purpose to developers using the plugin.
		settings.timeout+=settings.speed;
		

        if (elements.length > 1) {
            $(container).css({'position': 'relative', 'height': settings.containerheight, 'overflow': 'hidden'}).addClass(settings.runningclass);
			
			if (settings.type == 'random') {
			//rearrange the elements array in random order; from this point on it's the same as the 'sequence' option
				var elementsRandom = new Object();
				elementsRandom = jQuery.makeArray(elements);
				elementsRandom.sort(function(){return Math.round(Math.random())-0.5;});
				$(container).empty();
				for (var e = 0; e < elementsRandom.length; e++) $(container).append($(elementsRandom[e]).clone());
				elements = $(container).children();
			}
			
			if (settings.showcaptions) {
			//create a new div AFTER the container; use CSS to position and style it as needed
				$(container).after('<div class="innerfade-captions"></div>');
				if ($('.innerfade-captions').css('position')!='absolute'&&$('.innerfade-captions').css('position')!='relative') $('.innerfade-captions').css('position','relative');
				for (var i = 0; i < elements.length; i++) {
					caption = $(elements[i]).attr('data-caption');
					if (caption!='') caption=settings.captionprefix+caption;
					var leftPos = (settings.captionalignment=='right') ? 'right:0' : 'left:0';
					$(container).siblings('.innerfade-captions').append('<div id="innerfade-caption-'+i+'" style="position:absolute;top:0;'+leftPos+';">'+caption+'</div>');
					$(container).siblings('.innerfade-captions').children('div').hide();
					captions[i]=$(container).siblings('.innerfade-captions').children('#innerfade-caption-'+i);
				};
			}
			
			//prepare the elements for cycling
            for (var i = 0; i < elements.length; i++) {
                $(elements[i]).css({'z-index': String(elements.length-i), 'position': 'absolute'}).hide();
            };
			
			var current, last;
			
			if (settings.startfromcookie) {
				//find the cookie indicating the last active photo, and set the current elements index to it
				if ($.cookies.get('innerfadeLast')!=null) last=$.cookies.get('innerfadeLast'); else last=0;
				current = (last + 1) % elements.length;
			}
			else {
				if (settings.type == 'sequence' || settings.type == 'random') {
					current = 1;
					last = 0;
				}
				else if ( settings.type == 'random_start' ) {
					last = Math.floor(Math.random()*elements.length);
					current = (last + 1) % elements.length;
				}
				else alert('Innerfade: type must either be \'sequence\', \'random\' or \'random_start\'');
			}
			
			if (settings.animatefirst && !settings.startfromcookie) {
				firstDone = false;
				if (settings.firstanimation=='' || settings.firstanimation=='default') settings.firstanimation=settings.animationtype;
				if (settings.firstanimation=='fade'){
					$(elements[last]).addClass('current').fadeIn(settings.firstspeed);
					$(captions[last]).fadeIn(settings.firstspeed);
				}
				else if (settings.firstanimation=='slide')
					//$(elements[last]).addClass('current').slideDown(settings.firstspeed);
					$(elements[last]).addClass('current')
						.css({'top':'-'+settings.containerheight,'display':'block','z-index':elements.length})
						.animate({'top':0},settings.firstspeed,settings.easingtype);
				else if (settings.firstanimation=='sideways') {
					$(elements[last]).addClass('current')
						.css({'left':settings.containerwidth,'display':'block','z-index':elements.length})
						.animate({'left':0},settings.firstspeed,settings.easingtype);
				}
				else if (settings.firstanimation=='corner') {
					$(elements[last]).addClass('current')
						.css({'width':0,'height':0,'display':'block','z-index':elements.length})
						.animate({'width':settings.containerwidth,'height':settings.containerheight},settings.firstspeed,settings.easingtype);
				}
				else if (settings.firstanimation=='wipe') {
					//the first slide doesn't wipe - it slides in. it's impossible to wipe it in since there's nothing
					//behind it. the wipe effect is actually animating the slide in front to collapse
					$(elements[last]).addClass('current')
						.css({'left':settings.containerwidth,'display':'block','z-index':elements.length})
						.animate({'left':0},settings.firstspeed,settings.easingtype);
				}
				else if (settings.firstanimation=='none')
					$(elements[last]).addClass('current').show();
				else
		            alert('Innerfade: invalid animationtype.');
			}
			else {
				firstDone = true;
				$(elements[last]).addClass('current').css('display','block');
				$(captions[last]).css('display','block');
			}
			var firsttimeout = settings.timeout - settings.speed + settings.firstspeed;
			cycleTimer = setTimeout(function() {$.innerfade.cycle(elements, settings);}, firsttimeout);
			
			if (settings.showcontrolbox!='never') {

				$(container).before('<div class="innerfade-control"><a href="" class="innerfade-prev">PREV</a><a href="" class="innerfade-play playing">PAUSE</a><a href="" class="innerfade-next">NEXT</a></div>');
				if (settings.showcontrolbox=='always') {
				}
				else if (settings.showcontrolbox=='hover') {
					$(container).parent().children('.innerfade-control').hide();
					$(container).parent().hover(function() {
							$(this).children('.innerfade-control').fadeIn();
						}, function() {
							$(this).children('.innerfade-control').fadeOut();
						});
				}
				else if (settings.showcontrolbox=='semihover') {
					$(container).parent().children('.innerfade-control').fadeTo(0,.3);
					$(container).parent().hover(function() {
							$(this).children('.innerfade-control').fadeTo('normal',1);
						}, function() {
							$(this).children('.innerfade-control').fadeTo('normal',.3);
						});
				}
				$(container).parent().find('.innerfade-play').bind('click',function() {
						if ($(this).html()=='PLAY') {
							$.innerfade.cycle(elements, settings);
							$(this).html('PAUSE').addClass('playing').removeClass('paused');
						}
						else {
							clearTimeout(cycleTimer);
							$(elements).stop().parent().children('.current').css({'display':'block','opacity':'','height':''});
							if ($(elements).parent().children('.dying').size()>0 ) {
								$(elements).parent().children('.current').removeClass('current').parent().children('.dying').css({'display':'block','opacity':'','height':''}).removeClass('dying').addClass('current');
							}
							$(this).html('PLAY').addClass('paused').removeClass('playing');
						}
						$(this).blur();
						return false;
					});
				$(container).parent().find('.innerfade-next').bind('click',function() {
						clearTimeout(cycleTimer);
						$(this).siblings('.innerfade-play').html('PAUSE').addClass('playing').removeClass('paused');
						$(elements).stop().parent().children('.current').css({'display':'block','opacity':'','height':''});
						if (firstDone) {
							if ($(elements).parent().children('.dying').size()>0 ) {
								$(elements).parent().children('.current').removeClass('current').parent().children('.dying').css({'display':'block','opacity':'','height':''}).removeClass('dying').addClass('current');
							}
							$.innerfade.cycle(elements, settings, 0);
						}
						else {
							cycleTimer = setTimeout(function() {$.innerfade.cycle(elements, settings);}, settings.timeout);
						}
						firstDone = true;
						$(this).blur();
						return false;
				   });
				$(container).parent().find('.innerfade-prev').bind('click',function() {
						clearTimeout(cycleTimer);
						$(this).siblings('.innerfade-play').html('PAUSE').addClass('playing').removeClass('paused');
						$(elements).stop().parent().children('.current').css({'display':'block','opacity':'','height':''});
						if (firstDone) {
							if ($(elements).parent().children('.dying').size()>0 ) {
								$(elements).parent().children('.current').removeClass('current').parent().children('.dying').css({'display':'none','opacity':'','height':''}).removeClass('dying').addClass('current');
								$.innerfade.cycle(elements, settings, 0);
							}
							$.innerfade.cycle(elements, settings, 0, 'prev');
						}
						else {
							cycleTimer = setTimeout(function() {$.innerfade.cycle(elements, settings);}, settings.timeout);
						}
						firstDone = true;
						$(this).blur();
						return false;
				   });
			}//if (settings.showcontrolbox!='never')
			
		}//if (elements.length > 1)
    };

	$.innerfade.cycle = function(elements, settings, speed, direction) {
		
		firstDone = true;
		
		//Get the currently displayed element - this should ALWAYS find a match - and also get the element to show
		var current = $(elements).index($('.current'));
		if (typeof(direction)!='undefined'&&direction=='prev') var next = (current==0)?elements.length-1:current-1;
		else var next = (current + 1) %  elements.length;

		//Set the next element's class to carry the 'current' flag
		$(elements).parent().children('.current').removeClass('current');
		$(elements[next]).addClass('current');

		//Cycle out the current element and bring in the next one
		var effectSpeed = (typeof(speed) == 'undefined') ? settings.speed : speed;
		
        if (settings.animationtype == 'fade') {
            $(elements[current]).addClass('dying').fadeOut(effectSpeed, function(){$(this).removeClass('dying');});
            $(elements[next]).fadeIn(effectSpeed, function() {removeFilter($(this)[0]);});
		} else if (settings.animationtype == 'slide') {
            //$(elements[current]).addClass('dying').slideUp(effectSpeed, function(){$(this).removeClass('dying');});
            //$(elements[next]).slideDown(effectSpeed);
			$(elements[next])
				.css({'display':'block', 'z-index':elements.length, 'top':'-'+settings.containerheight})
				.animate({'top':0}, effectSpeed, settings.easingtype, function() {
						$(elements[current]).css({'display':'none', 'z-index':1});
						$(this).css('z-index',2);
					});
		} else if (settings.animationtype == 'sideways') {
			$(elements[next])
				.css({'display':'block', 'z-index':elements.length, 'left':settings.containerwidth})
				.animate({'left':0}, effectSpeed, settings.easingtype, function() {
						$(elements[current]).css({'display':'none', 'z-index':1});
						$(this).css('z-index',2);
					});
		} else if (settings.animationtype == 'corner') {
			$(elements[next])
				.css({'display':'block', 'z-index':elements.length, 'width':0, 'height':0})
				.animate({'width':settings.containerwidth, 'height':settings.containerheight}, effectSpeed, settings.easingtype, function() {
						$(elements[current]).css({'display':'none', 'z-index':1});
						$(this).css('z-index',2);
					});
		} else if (settings.animationtype == 'wipe') {
			$(elements[current]).css('z-index',2); //set the current image on top
			$(elements[next]).css({'display':'block','z-index':1,'width':settings.containerwidth});//set the next image to be visible except it's underneath the current one
			$(elements[current]).animate({'width':0}, effectSpeed, settings.easingtype, function() { //collapse the current image width to 0 and then hide it entirely
					$(elements[current]).css({'display':'none','z-index':''});
				});
		} else if (settings.animationtype == 'none') {
            $(elements[current]).hide();
            $(elements[next]).show();
        } else
			alert('Innerfade: animationtype must be \'slide,\' \'fade,\' or \'none.\'');
		
		//Set the cookie
		if (settings.startfromcookie) $.cookies.set('innerfadeLast',next);
		
		//Swap out the caption
		if (settings.showcaptions) {
			
			$('#innerfade-caption-'+current).fadeOut(effectSpeed);
			$('#innerfade-caption-'+next).fadeIn(effectSpeed);
		}
		
		//Set the timer to do this again
		cycleTimer = setTimeout((function() {$.innerfade.cycle(elements, settings);}), settings.timeout);
		
	};

})(jQuery);

// **** remove Opacity-Filter in ie ****
function removeFilter(element){if(element.style.removeAttribute)element.style.removeAttribute('filter');}
