(function($){

	$.jqSlideshow = {
		// Slideshow Default options
		defaults:{
			delay: 4000, /* Delay between animations */
			duration: 1800, /* Duration of fade in animation */
			curLayer: 1, /* start from layer number */
			zIndex: 2, /* z-index value. layers will use this value +/- 1 either side */
			shownumbers: false, /* Show navigable image layer icons or not */
			shownav: true, /* Show next/prev icons or not */
			effect: 'fade',
			items: 'dl',
			captioneffect: 'fade',
			autoplay: false,
			after: null
		},
		// Set options per instance
		setOptions: function(options){
			var opts = this.defaults;
			for(var x in options){
				if(typeof opts[x] === 'undefined') alert('Invalid option '+x);
				else opts[x] = (opts[x] != null && opts[x].constructor == Object)? this.setOptions(options[x], opts[x]) : options[x];
			}
			return opts;
		},
		// Init Instance Variables
		initVars: function(obj){
			obj.layers = $(obj.element).find(obj.options.items).each(function(){
				// Setup css positioning based on effect
				switch(obj.options.effect){
					case 'slide':
							$(this).css({zIndex: obj.options.zIndex, left:obj.slidewidth});
						break;
					default:
							$(this).css({zIndex: obj.options.zIndex, left:0, opacity:0.01});
						break;
				}
			});
			// set the initial Active layer
			obj.activeIndex = obj.options.curLayer = obj.options.curLayer == 'rand'? Math.floor(Math.random()*obj.layers.length) : 0;
			$(obj.layers[obj.activeIndex]).css({zIndex: obj.options.zIndex+1});
		},
		// Start the slideshow
		initSlideshow: function(obj){
			if(obj.layers.length > 1 && obj.options.autoplay){
				$.jqSlideshow.cycleLayers(obj);
			}else{
				$(obj.layers[obj.activeIndex]).css({'left':0,opacity:1});
			}
		},
		// Calculate next image, current image and previous image and layer zindex and opacity accordingly
		cycleLayers: function(obj){
			var o = obj.options;
			var l = obj.layers.length, c = o.curLayer, z = o.zIndex, d = o.delay;
			switch(obj.options.effect){
				case 'slide':
					$(obj.layers[c<=0?l-1:c-1]).css({'left':obj.slidewidth, zIndex:z-1});
					$(obj.layers[c=o.curLayer=c>=l?0:c]).css({'left':0,zIndex:z});
				break;
				default:
					$(obj.layers[c<=0?l-1:c-1]).css({'opacity':0, zIndex:z-1});
					$(obj.layers[c=o.curLayer=c>=l?0:c]).css({'opacity':1,zIndex:z});
				break;
			}
			if(obj.options.autoplay) obj.timer = setTimeout(function(){ $.jqSlideshow.fadeInLayer(obj, c+1==l?0:c+1); ++o.curLayer;}, parseInt(d));
		},
		// Bring Layer to front and Fade in Animation with callback to cycleLayers.
		fadeInLayer: function(obj, i, speed){
			var speed = speed || obj.options.duration;
			var o = obj.options;
			clearTimeout(obj.timer);
			obj.activeIndex = i;
			obj.clickactive = false;
			switch(obj.options.effect){
				case 'slide':
					$(obj.layers[i]).css({zIndex:o.zIndex+1}).animate({'left':0}, parseInt(speed), function(){$.jqSlideshow.cycleLayers(obj);});
					$(obj.layers[o.curLayer]).animate({'left':0-obj.slidewidth}, parseInt(speed), function(){ $(this).css({'left': obj.slidewidth}); obj.clickactive = true; $.jqSlideshow.triggerAfter(obj);} );
					break;
				default:
					$(obj.layers[i]).css({zIndex:o.zIndex+1}).animate({'opacity':1}, parseInt(speed), function(){$.jqSlideshow.cycleLayers(obj); obj.clickactive = true; $.jqSlideshow.triggerAfter(obj);});
					break
			}
			if(o.shownumbers && obj.layers.length>2){
				$(obj.icons).removeClass('active');
				$(obj.icons[obj.activeIndex]).addClass('active');
			}
		},
		switchImage: function(obj, i, speed){
			var speed = speed || obj.options.duration;
			clearTimeout(obj.timer);
			switch(obj.options.effect){
				case 'slide': 
					$(obj.layers[i]).css({'left':slidewidth,zIndex:obj.options.zIndex-1}); 
					break;
				default: 
					obj.layers.css({'opacity':0,zIndex:obj.options.zIndex-1});
					$(obj.layers[obj.activeIndex]).css({'opacity':1,zIndex:obj.options.zIndex-1}).animate({'opacity':0}, 500);
					break;
			}
			$.jqSlideshow.fadeInLayer(obj, i, speed);
			obj.options.curLayer = obj.activeIndex = i;
		},
		// Show Navigation
		showSlideshowNav: function(obj){
			// Show numbers navigation
			var nextZindex = obj.layers.length+obj.options.zIndex;
			if(obj.options.shownumbers && obj.layers.length>1){
				nums = $('<div id="slideshownumbers"/>').appendTo(obj.element);
				nums.css({zIndex: nextZindex+1, position:'absolute'});
				obj.layers.each(function(i,item){
					var num = $('<span/>').appendTo(nums).html(i+1);
					num.bind('click',function(){
						if(obj.activeIndex == i || !obj.clickactive) return;
						$.jqSlideshow.switchImage(obj, i, 900);
					});
				});
				obj.icons = $('span', nums);
				$(obj.icons[obj.activeIndex]).addClass('active');
			}
			if(obj.options.shownav && obj.layers.length>1){
				prev = $('<div class="prev">prev</div>').appendTo(obj.element);
				next = $('<div class="next">next</div>').appendTo(obj.element);
				prev.css({zIndex: nextZindex, position:'absolute'});
				next.css({zIndex: nextZindex, position:'absolute'});
				prev.bind('click',function(){
					var i = obj.options.curLayer<=0? obj.layers.length-1 : obj.options.curLayer-1;
					if(obj.clickactive) $.jqSlideshow.switchImage(obj, i);
				});
				next.bind('click',function(){
					var i = obj.options.curLayer>=obj.layers.length-1? 0 : obj.options.curLayer+1;
					if(obj.clickactive) $.jqSlideshow.switchImage(obj, i);
				});
			}
		},
		triggerAfter: function(obj){
			if( $.isFunction(obj.options.after) ){
				obj.options.after.call(obj);
			}
		}
		// eof jqSlideshow object
	}
	
	
	$.fn.jqSlideshow = function(options){
		return this.each(function(i){
			var slide = {
			  options: $.jqSlideshow.setOptions(options),
				timer: null,
				activeIndex: 0,
				icons: [],
				slidewidth: $(this).width(),
				clickactive: true,
				layers: null,
				element: this
			}
			$.jqSlideshow.initVars(slide);
			$.jqSlideshow.showSlideshowNav(slide);
			$.jqSlideshow.initSlideshow(slide);
		});
	}
	
})(jQuery);
