/*
 * 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-06-18 (Wed, 26 May 2010)
 * Version: 0.2.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){
	if( isNaN(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, // Integer 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:	{
				// Reserved Strings [$1 = current button number, $2 = current slide number, $3 = total number of slides]; These will be replaced in the following variables
				numeric: 0, // Integer; Amount of numeric controls
				numericWrapper: "$1", // String;
				next: false, // Boolean or String; String will show in button
				play: false, // Boolean or String; String will show in button
				stop: false, // Boolean or String; String will show in button
				prev: false // Boolean or String; String will show in button
			},
			theme: false // Add a classname for wrapper, helps for theming
		},s);
	

		// Set Width and Height
		return this.css({
			width: o.width,
			height: o.height,
			position: "relative",
			overflow: "hidden"
		}).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 peepShow"+ps.luid + (o.theme?" ps"+o.theme.substr(0,1).toUpperCase()+o.theme.substr(1):"");
			
			// 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] = {
					aS: aS,
					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+1)+")", o.animation.delay) : 1
				}
				// Prepare animation type for input into index
				o.animation.type = o.animation.type.toString().toLowerCase().replace(/\s/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,false);
				}
			}
			
			// Increment for next peepShow
			ps.luid++;
		});
	} else {
		var i = $(this).parents(".peepShow").attr("class").replace(/.*(?:peepShow([0-9])).*/g, "$1");
		if( s != $.fn.peepShow.index[i].aS ){
			if( !($(".peepShow"+i+" .psSlide").eq(s-1).filter(":animated").length > 0) ){
				$.fn.peepShow.step( i, s );
			}
		}
	}
}

$.extend($.fn.peepShow, {
	luid: 0,
	index: [], // used to preserve opptions for individual instantces of peepshow
	set: function(i,a){
		var ps=$.fn.peepShow;
		
		ps.index[i].aS = a;
		// If overlay=false then timeout bellow will be positive number, else is set to zero /// Line: A
		ps.index[i].timer = ps.index[i].delay ?
			setTimeout( "$.fn.peepShow.step("+i+","+(a==ps.index[i].uB?1:a+1)+")",
				ps.index[i].timer ? ps.index[i].delay+ps.index[i].speed : ps.index[i].delay
			)
		: 1;
	},
	step: function(i,t){
		// ToDo: If t < a, reverse animation
		var ps=$.fn.peepShow, a=ps.index[i].aS, rA;
		
		// If overlay=false then timeout bellow will be positive number, else is set to zero
		if( ps.index[i].timer ){
			
			var s=$(".peepShow"+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);
					})
					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);
					})
					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);
					});
					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);
					});
					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);
					});
					break;
			} // end switch
			
			ps.updateBtn(i,t,false)
			if( ps.index[i].timer ) ps.set(i,t);
		}
	},
	stop: function(i,a){
		clearTimeout($.fn.peepShow.index[i].timer);
		$.fn.peepShow.updateBtn(i,a,true)
	},
	updateBtn: function(i,a,s){
		var ps=$.fn.peepShow.index[i], o="", x, u, w=Math.round(ps.numeric/2);
		//s&&(a=(a-1==0?ps.uB:a-1));
		if(s)a=(a==0?ps.uB:a);
		// Prev
		if(ps.prev) o += '<li class="btnPrev"><a href="javascript:$.fn.peepShow.step('+i+','+(a-1==0?ps.uB:a-1)+')">'+(ps.prev!=true?ps.prev:"&laquo;")+'</a></li>';
		// Play
		if(ps.play) o += '<li class="btnPlay'+(!s?" active":"")+'"><a href="javascript:$.fn.peepShow.step('+i+','+(a==ps.uB?1:a+1)+')">'+(ps.play!=true?ps.play:"&#9658;")+'</a></li>';
		// Stop
		if(ps.stop) o += '<li class="btnStop'+(s?" active":"")+'"><a href="javascript:$.fn.peepShow.stop('+i+','+(a==ps.uB?1: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+','+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==ps.uB?1:a+1)+')">'+(ps.next!=true?ps.next:"&raquo;")+'</a></li>';
		
		$(".peepShow"+i+" > .psControls > ul").unbind("hover").html( o.replace(/\$2/g, a).replace(/\$3/g, ps.uB)/*$2 Current Slide,$3 Total Slides*/ ).find("li").hover(function(){
			this.className+=(this.className?" ":"")+"hover";
		}, function(){
			this.className=this.className.replace("hover","").replace(/^\s+|\s+$/g,"");
		});
	}
});	

})(jQuery);
