/*
 * jQuery Plugin: peepShow
 * http://www.roydukkey.com/
 *
 * Copyright (c) 2010 Rory Dueck
 *
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Date: 2010-04-26 (Tue, 26 Apr 2010)
 * Version: 0.1.2
 *
 * NOTE: Please report any improvements to roydukkey-at-gmail-dot-com.
 *       There are still many improvements that can me made to this
 *       script. Thanks to all in the open community.
 */
(function($){
// Do CAST all VARS

$.fn.peepShow = function(s) {
	// peepShow Defaults
	o = $.extend(true,{
		width: 0,
		height: 0,
		order: "numeric", // String; String = numeric|specific|random
		orderBy: "", // String; String = "1,3,7,..."; Only if o.order = specific
		animation: {
			type: "fade", // String; "value value" two values declar forward and backward type
			delay: 5000, // Int or Boolean; false = Show and display till next $.updateBtn()
			speed: 700,
			overlay: false // Boolean; false = next animation will not start until current animation finishes
		},
		controls:	{
			numeric: 0,
			numericWrapper: "$1", // String; Wildcards[$1 = current button number, $2 = current slide number] 
			next: false, // Boolean or String; String will show in button
			play: false, // ''
			stop: false, // ''
			prev: false // ''
		}
	},s);

	// Set Width and Height
	$(this).css({
		width: o.width,
		height: o.height,
		position: "relative",
		overflow: "hidden"
	});

	return this.each(function() {
		var ps = $.fn.peepShow,
			g=$(this),
			s=g.find(".psSlide"),
			uB=s.length,
			aS=0,
			a,
			order=[];		// Create space for show vars in index; luid = this instance of slideshow
		
		// Add Class
		this.className += (this.className ? " " : "") + "peepShow pShw"+ps.luid;
		
		// Create Index of Slides
		for( var i=0; i<uB; i++ ) order.push(i);
		
		// Set Order of Slides in Index
		switch(o.order) {
			// Radomize
			case "random":
				order.sort( function(){return 0.5 - Math.random()} );
			break;
			// Specific Order
			case "specific":
				if(o.orderBy) {
					order = [];
					for( i in o.orderBy = o.orderBy.replace(" ","").split(",") ) order[i] = o.orderBy[i]-1;
					uB = order.length;
				}
				break;
		}
		
		// Add CSS to Slides
		s.css({
			position: "absolute",
			top: 0,
			left: 0
		})
		// Show First Slide
		.eq( order[aS++] ).show();
		
		if( uB>1 ) {
			
			// Set all other Index values
			ps.index[ps.luid] = {
				order: order,
				type: {},
				delay: o.animation.delay,
				speed: o.animation.speed,
				overlay: o.animation.overlay,
				numeric: o.controls.numeric>uB ? uB : o.controls.numeric,
				wrap: o.controls.numericWrapper,
				next: o.controls.next,
				play: o.controls.play,
				stop: o.controls.stop,
				prev: o.controls.prev,
				uB: uB,
				timer: o.animation.delay ? setTimeout( "$.fn.peepShow.step("+ps.luid+","+aS+","+(aS+1)+")", o.animation.delay) : 1
			}
			// Prepare animation type for input into index
			o.animation.type = o.animation.type.toString().toLowerCase().replace(/^\s+|\s+$/g,"").replace(/[ ]{1,}/g," ").split(" ");
			for (i in a=["forward","back"])
				ps.index[ps.luid].type[a[i]] = !o.animation.type[i] ? o.animation.type[0] : o.animation.type[i];
			
			// Create Button Actions
			if(
				ps.index[ps.luid].numeric > 0 ||
				ps.index[ps.luid].next ||
				ps.index[ps.luid].play ||
				ps.index[ps.luid].stop ||
				ps.index[ps.luid].prev
			) {
				g.append('<div class="psControls"><ul /></div>');
				ps.updateBtn(ps.luid,aS);
			}
		}
		
		// Increment for next peepShow
		ps.luid++;
	});
	
}

$.extend($.fn.peepShow, {
	luid: 0,
	index: [], // used to preserve opptions for individual instantces of peepshow
	set: function(i,a,d){
		var ps=$.fn.peepShow, a, d;
		ps.index[i].timer = ps.index[i].delay ?
			setTimeout( "$.fn.peepShow.step("+i+","+a+","+(a==ps.index[i].uB?1:a+1)+")", d )
		: 1;
	},
	step: function(i,a,t){
		// ToDo: If t < a, reverse animation
		var ps=$.fn.peepShow, rA;
		
		// If overlay=false then timeout bellow will be positive number, else is set to zero
		if( ps.index[i].timer ) {
			
			var s=$(".pShw"+i+" .psSlide");
			clearTimeout( ps.index[i].timer );
			// If overlay=false set timer position to 0 for above evaluation
			if( !ps.index[i].overlay ) ps.index[i].timer=0;
			
			if( t < a && ps.index[i].type.back != "fade" )
				rA = ps.index[i].type.back;
			
			if( ps.index[i].type.forward == "random" || rA == "random" )
				rA = new Array("slideup","slidedown","slideright","slideleft","fade")[Math.floor(Math.random()*5)];
			
			// Do to all slides
			
			switch( rA || ps.index[i].type.forward ){
				case "slideup":
					s.eq( ps.index[i].order[a-1] ).animate({
						top: "-"+s.eq( ps.index[i].order[t-1] ).innerHeight()+"px"
					}, ps.index[i].speed, function(){
						$(this).css({
							display: "none",
							top: ""
						});
					});
					s.eq( ps.index[i].order[t-1] ).css({
						top: "",
						bottom: 0
					}).slideDown( ps.index[i].speed, function(){
						$(this).css({
							bottom: "",
							top: 0
						});
						if( !ps.index[i].timer ) ps.set(i,t,ps.index[i].delay);
					})
					break;
					
				case "slidedown":
					s.eq( ps.index[i].order[a-1] ).css({
						top: "",
						bottom: 0
					}).slideUp( ps.index[i].speed, function(){
						$(this).css({
							bottom: "",
							top: 0
						});
						if( !ps.index[i].timer ) ps.set(i,t,ps.index[i].delay);
					})
					s.eq( ps.index[i].order[t-1] ).css({
						top: "-"+s.eq( ps.index[i].order[t-1] ).innerHeight()+"px",
						display: "block"
					}).animate({
						top: 0
					}, ps.index[i].speed);
					break;
					
				case "slideright":
					s.eq( ps.index[i].order[a-1] ).animate({
						left: s.eq( ps.index[i].order[a-1] ).innerWidth()+"px"
					}, ps.index[i].speed, function(){
						$(this).css({
							display: "none",
							left: 0
						});
						if( !ps.index[i].timer ) ps.set(i,t,ps.index[i].delay);
					});
					s.eq( ps.index[i].order[t-1] ).css({
						left: "-"+s.eq( ps.index[i].order[t-1] ).innerWidth()+"px",
						display: "block"
					}).animate({
						left: 0
					}, ps.index[i].speed);
					break;
					
				case "slideleft":
					s.eq( ps.index[i].order[a-1] ).animate({
						left: "-"+s.eq( ps.index[i].order[a-1] ).innerWidth()+"px"
					}, ps.index[i].speed, function(){
						$(this).css({
							display: "none",
							left: 0
						});
						if( !ps.index[i].timer ) ps.set(i,t,ps.index[i].delay);
					});
					s.eq( ps.index[i].order[t-1] ).css({
						left: s.eq( ps.index[i].order[t-1] ).innerWidth()+"px",
						display: "block"
					}).animate({
						left: 0
					}, ps.index[i].speed);
					break;
					
				default:
					s.eq( ps.index[i].order[a-1] ).fadeOut( ps.index[i].speed );
					s.eq( ps.index[i].order[t-1] ).fadeIn( ps.index[i].speed, function(){
						// If overlay=true we can't do this, cause we'd be overwriting /// Line: A
						if( !ps.index[i].timer ) ps.set(i,t,ps.index[i].delay);
					});
					break;
			} // end switch
			
			// If overlay=false then timeout bellow will be positive number, else is set to zero
			if( ps.index[i].timer ) ps.set(i,t,ps.index[i].delay+ps.index[i].speed);  /// Line: A
			
			ps.updateBtn(i,t)
		}
	},
	stop: function(i,a){
		clearTimeout($.fn.peepShow.index[i].timer);
		$.fn.peepShow.updateBtn(i,a,true)
	},
	updateBtn: function(i,a,st){
		var ps=$.fn.peepShow.index[i], o="", x, u, w=Math.round(ps.numeric/2);
		
		// Prev
		if(ps.prev) o += '<li class="btnPrev"><a href="javascript:$.fn.peepShow.step('+i+','+a+','+(a-1==0?ps.uB:a-1)+')">'+(ps.prev!=true?ps.prev:"&laquo;")+'</a></li>';
		// Play
		if(ps.play) o += '<li class="btnPlay'+(!st?" active":"")+'"><a href="javascript:$.fn.peepShow.step('+i+','+a+','+(a==ps.uB?1:a+1)+')">'+(ps.play!=true?ps.play:"&#9658;")+'</a></li>';
		// Stop
		if(ps.stop) o += '<li class="btnStop'+(st?" active":"")+'"><a href="javascript:$.fn.peepShow.stop('+i+','+a+')">'+(ps.stop!=true?ps.stop:"&#9632;")+'</a></li>';
		// Numeric
		if( ps.numeric > 0 ) {
			if( a-w < 0 ) {
				x = 0;
				u = ps.numeric;
			} else {
				if( a+w > ps.uB ) {
					x = ps.uB-ps.numeric;
					u = ps.uB;
				} else {
					x = a-w;
					u = a+w+(w!=ps.numeric/2?-1:-0);
				}
			}
			for( ++x; x<=u; x++ ) {
				o += '<li class="btnNum' + x + (
					x==a ?
					' current"><a>' :
					'"><a href="javascript:$.fn.peepShow.step('+i+','+a+','+x+')">'
				) + ps.wrap.replace(/\$1/g,x)+'</a></li>'
			}
		}
		// Next
		if(ps.next) o += '<li class="btnNext"><a href="javascript:$.fn.peepShow.step('+i+','+a+','+(a==ps.uB?1:a+1)+')">'+(ps.next!=true?ps.next:"&raquo;")+'</a></li>';
		
		// Replace Special
		o = o.replace(/\$2/g, a); // $2 Current Slide
		
		// DO remover events before removing elements????
		$(".pShw"+i+" > .psControls > ul").unbind("hover").html(o).find("li").hover(function(){
			this.className+=(this.className?" ":"")+"hover";
		}, function(){
			this.className=this.className.replace("hover","").replace(/^\s+|\s+$/g,"");
		});
	}
});	

})(jQuery);
