/**
 * 
 * aSlideshow, jQuery slideshow plugin - ajTools, a jQuery Toolkit
 * http://dev.andreafailli.it/ajtools
 *
 * Copyright 2011, Andrea Failli
 *
 * Date: 27/07/2011
 * Version: 1.1
 * 
 */


(function($) {
	jQuery.fn.aSlideshow = function(method) {
		
		// plugin settings
		var defaults = {
			sizeMode : "fit", // fit | fill | {landscape:'xx',portrait:'xx'}
			stretch : false,
			duration : 1000,
			delay : 4000,
			autoPlay : false,
			index : 0,
			useKeys : true,
			debug : false,
			source : null,	// where to find thumbs
			
			onchange : null // function(i){}
		};
		
		
		// plugin methods
		var methods = {
				
			init : function(options){
				
				var settings = defaults;				
				if (options) { 
					settings = $.extend({},defaults,options);
				}
				
				return this.each(function() {        
					var $this = $(this);
					$this.data("aSlideshow",{
						// local data storage
						settings : settings,
						imageCounter : 0,
						isFading : false,
						index : -1,
						isPlaying : false,
						timers: {
							show : null,
							change : null,
							autoPlay : null
						},
						handlers : []
					});
					
					$("a",settings.source ? settings.source : this).each(function(){
						var caption = $(this).attr("title") ? $(this).attr("title") : (	$("img",this).attr("title") ? $("img",this).attr("title") : null );					
						$this.aSlideshow("append",{
							image  : $(this).attr("href"),
							thumb  : null,//$("img",this).attr("src") ? $("img",this).attr("src") : null, // TODO : implement thumb preview
							caption: caption
						});
					});
					$this.children().not("img.aSlideshow-image").remove();
					
					$this.addClass("aSlideshow-container");
					$this.addClass("loading");
					
					if ($this.css("position") == "static") // position must not be static, at minimum "relative".
						$this.css("position","relative");
					
					$this.append("<span class='aSlideshow-caption'></span>");
					
					// check if IE lt 9
					if ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0" || $.browser.version == "8.0" ))
						$("span.aSlideshow-caption",this).addClass("IElt9");
					
					// window resize event handler
					$this.aSlideshow("bind",window,"resize",function(){
						var data = $this.data("aSlideshow");
						if (data.isFading) {
							var prevIndex = (data.index-1 <0) ? data.imageCounter-1 : data.index-1;
							$this.aSlideshow("resize",data.index);
							$this.aSlideshow("resize",prevIndex);
						} else {
							$this.aSlideshow("resize",data.index);
						}
						$this.aSlideshow("repositionCaption");
					});
					
											
					// key navigation event handler
					if (settings.useKeys)
						$this.aSlideshow("bind",document,"keyup",function(event){
							if ( event.which == 13 || event.which == 39) {
								// right arrow or Enter
								$this.aSlideshow("next",true);
							}
							if ( event.which == 37) {
								// right left
								$this.aSlideshow("prev",true);
							}
	
						});
					
					
					// show first
					$this.aSlideshow("goto",settings.index);
					
					// autoplay?
					if (settings.autoPlay)
						$this.aSlideshow("start");
					
				});
			},
			
			
			bind : function(object,event,handler) {
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				event = event+".aSlideshow";
				
				data.handlers.push({
					object : object,
					event : event,
					handler : handler
				});
				
				$(object).bind(event,handler);
				
				$this.data("aSlideshow",data);
			},
			
			
			destroy : function() {
				
				return this.each(function() {  
				
					var $this = $(this);
					var data = $this.data("aSlideshow");
					
					if (data)
						for (var key in data.timers)
							if (data.timers[key]!=null) {
								window.clearTimeout(data.timers[key]);
								data.timers[key] = null;
							}
					
					//unbind
					for (var i=0; i<data.handlers.length; i++)
						$(data.handlers[i].object).unbind(data.handlers[i].event,data.handlers[i].handler);
					
					$this.removeData("aSlideshow");
				
				});
				
			},
			
			
			log : function(x) {
				var data = $(this).data("aSlideshow")
				if (data && data.settings.debug)
					if (window.console)
						if (window.console.log) {
							if (typeof x == "string")
								window.console.log("aSlideshow: "+x);
							else
								window.console.log(x);
						}
						
			},
		
			
			append : function(image) {
				var thumb = image.thumb ? image.thumb : "about:blank";
				var img = $('<img class="aSlideshow-image" src="' + thumb + '" image="' + image.image + '" caption="' + (image.caption ? image.caption : '') + '" loaded="false" preloading="false" />');
				$(this).append(img);
				img.fadeTo(0,0);
				var data = $(this).data("aSlideshow");
				data.imageCounter++;
				$(this).data("aSlideshow",data);
			},
			
			
			preload : function(index){
				var $this = $(this);
				var img = $("img.aSlideshow-image",this).eq(index);
				
				if (img.attr("loaded")=="false") {
					$this.aSlideshow("log","Image "+index+" needs to be loaded");
					img.bind("load.aSlideshow",function(){
						$this.aSlideshow("log","Image "+index+" loaded");
						img.unbind("load.aSlideshow");
						img.attr("loaded","true");
						img.attr("preloading","false");
						img.attr("w",img.width());
						img.attr("h",img.height());
					});
					img.attr("preloading","true");
					img.attr("src",img.attr("image"));
				}
			},
			
			
			resize : function(index) {
				
				var sizeMode = $(this).data("aSlideshow").settings.sizeMode;
				
				var img = $("img.aSlideshow-image",this).eq(index);
				var x,y,w,h;
				var cw = $(this).width();
				var ch = $(this).height();
				var iw = parseInt(img.attr("w"));
				var ih = parseInt(img.attr("h"));
				var ratio = iw/ih;
				
				if (typeof(sizeMode) == "object") 
					if (ih>iw) sizeMode = sizeMode.portrait;
					else
						sizeMode = sizeMode.landscape;
				
				
				$(this).aSlideshow("log","Resizing image "+index+" ["+sizeMode+"]");
				
				switch (sizeMode) {
				case "fit" :
					w = cw; // new larghezza pari alla larghezza del contenitore
					h = w / ratio; // new altezza calcolata in funzione della larghezza
					if (h > ch) { // se la new altezza è troppa rispetto all'altezza del contenitore
						h = ch; // new larghezza pari all'altezza del contenitore
						w = h * ratio; // new larghezza calcolata in funzione dell'altezza
					}
					if ($(this).data("aSlideshow").settings.stretch==false)
						if (w>iw || h>ih) {w = iw; h = ih;} // do not enlarge image
					break;
				case "fill" :
					w = cw; // new larghezza pari alla larghezza del contenitore
					h = w / ratio; // new altezza calcolata in funzione della larghezza
					if (h < ch) { // se la new altezza non copre tutta l'altezza del contenitore
						h = ch; // new larghezza pari all'altezza del contenitore
						w = h * ratio; // new larghezza calcolata in funzione dell'altezza
					}
					break;
				default :
					$.error("jQuery.aSlideshow: unknown sizeMode "+sizeMode);
					return;
				}
				
				x = cw/2 - w/2;
				y = ch/2 - h/2;
				
				img.css({
					left  : x + "px",
					top   : y + "px",
					width : w + "px",
					height: h + "px"
				});
				
				
			},
			
			
			show : function(index) {
				var img = $("img.aSlideshow-image",this).eq(index);
				var caption = $("span.aSlideshow-caption",this);
				
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				$(this).aSlideshow("log","Show image "+index+" requested");
				
				
				data.isFading = true;
				
				// fadeOut
				$("img.aSlideshow-image",this).eq(data.index).stop().fadeTo(data.settings.duration,0);
				caption.stop().animate({opacity:0},data.settings.duration/3);
								
				// onchange handler
				if (data.index != index && $.isFunction(data.settings.onchange))
					data.settings.onchange(index);
				
				data.index = index;
				
				$this.addClass("loading");
				
				// image not already loaded
				if (img.attr("loaded")=="false") {
					// clear pending show() call
					if (data.timers.show!=null) {
						window.clearTimeout(data.timers.show);
						data.timers.show = null;
					}
					// initiate image preloading if not already initiated
					if (img.attr("preloading")=="false") {
						$this.aSlideshow("preload",index);
					}
					// postpone show() call
					data.timers.show = window.setTimeout(function(){
						$this.aSlideshow("show",index);
					},200);
					$this.data("aSlideshow",data);
					return;
				}
				
				// now image is loaded :)
				
				$this.removeClass("loading");
				
				$this.aSlideshow("log","Image "+index+" already loaded");
				
				$this.aSlideshow("resize",index);
				
				$this.aSlideshow("log","Show image "+index+" initiated");
				
				// fadeIn
				img.stop().fadeTo(data.settings.duration,1,function(){
					data.isFading = false;
					
					if (img.attr("caption")!="") {
						$this.aSlideshow("repositionCaption");
						caption.html(img.attr("caption"));						
						caption.animate({opacity:1},data.settings.duration/3);
					}
					
					
					
					$this.data("aSlideshow",data);
				});
				
				// preload next
				var nextIndex = (data.index+1)%data.imageCounter;
				var nextImg = $("img.aSlideshow-image",this).eq(nextIndex);
				if (nextImg.attr("loaded")=="false" && nextImg.attr("preloading")=="false")
					$this.aSlideshow("preload",nextIndex);
				
				// preload prev
				var prevIndex = (data.index-1 <0) ? data.imageCounter-1 : data.index-1;
				var prevImg = $("img.aSlideshow-image",this).eq(prevIndex);
				if (prevImg.attr("loaded")=="false" && prevImg.attr("preloading")=="false")
					$this.aSlideshow("preload",prevIndex);
				
				if (data.isPlaying)
					$this.aSlideshow("start");
				
				$this.data("aSlideshow",data);
				
				
			},
			
			
			repositionCaption : function() {
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				if (!data) return;
				
				var img = $("img.aSlideshow-image",this).eq(data.index);
				var x = parseInt(img.css("left"));
				var y = parseInt(img.css("top"));
				
				var captionSpan = $("span.aSlideshow-caption",this);
				if (x>0)
					captionSpan.css({
						left : x + "px",
						right: x + "px"
					});
				else 
					captionSpan.css({
						left : "0px",
						right: "0px"
					});
				if (y>0)
					captionSpan.css({
						bottom : y + "px"
					});
				else 
					captionSpan.css({
						bottom : "0px"
					});
				
			},
			
			
			next : function(immediate) {
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				var nextIndex = (data.index+1)%data.imageCounter;
				
				$this.aSlideshow("goto",nextIndex,immediate);
			},
			
			
			
			prev : function(immediate) {
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				var prevIndex = (data.index-1 <0) ? data.imageCounter-1 : data.index-1;
				
				$this.aSlideshow("goto",prevIndex,immediate);
				
			},
			
			
			"goto" : function(index,immediate) {
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				$this.aSlideshow("log","Image "+index+" requested ["+(immediate? "immediate" : "NOT immediate")+"]");
								
				if (immediate) {
					$this.aSlideshow("show",index);
				} else {
					var img = $("img.aSlideshow-image",this).eq(index);
					if (img.attr("loaded")=="true")
						$this.aSlideshow("show",index);
					else {
						// initiate image preloading if not already initiated
						if (img.attr("preloading")=="false") {
							$this.aSlideshow("preload",index);
						}
						if (data.timers.change != null) {
							window.clearTimeout(data.timers.change);
							data.timers.change = null;
						}
						data.timers.change = window.setTimeout(function(){
							$this.aSlideshow("goto",index,immediate);
						},200);
						$this.data("aSlideshow",data);
					}
				}
			},
			
			
			start : function(){
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				$this.aSlideshow("stop");
				
				data.isPlaying = true;
				
				data.timers.autoPlay = window.setTimeout(function(){
					$this.aSlideshow("next");
				},data.settings.delay);
				
				
				
				$this.data("aSlideshow",data);
			},
			
			stop : function(){
				var $this = $(this);
				var data = $this.data("aSlideshow");
				
				if (data.timers.autoPlay != null) {
					window.clearTimeout(data.timers.autoPlay);
					data.timers.autoPlay = null;
				}
				
				data.isPlaying = false;
				
				$this.data("aSlideshow",data);
			}
			
			
		
		};

		// method calling logic: $("xx").plugin("method",args)
		if ( methods[method] ) {
			return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.aSlideshow' );
		}  
		
		
	};	
})(jQuery);
