(function($) {


var JMMSlideShowImage = function(options, gallerySettings) {
	
	var s = this;
	
	this.settings = $.extend({
		method: "data",
		src: null,
		alt: "",
		width: 0,
		height: 0,
		src: null,
		caption: "",
		load: null
	}, options);
	
	this.gallerySettings = gallerySettings;
	
	this.wrapper = null;
	this.img = null;
	this._loaded = false;
	
	if (this.settings.method == "target") {
		this.wrapper = this.settings.wrapper;
		this.img = this.settings.img;
		this.settings.width = this.img.width();
		this.settings.height = this.img.height();
		this._loaded = false;
		
		this.wrapper.addClass("image-wrapper-loading");
		this.img.hide();
		$("<img/>").load(function() {
				s._loaded = true;
				if ($.isFunction(s.settings.load)) {
					s.settings.load();
				}
				s.img.show();
			}).attr("src", this.img.attr("src"));		
	} else {
		
		this.wrapper = $('<div class="image-wrapper image-wrapper-loading" />'); 
	
		this.img = $('<img />');
		this.img.hide().attr("alt", this.settings.alt)
			.attr({width: this.settings.width, height: this.settings.height})
			.load(function() {
				s._loaded = true;
				if ($.isFunction(s.settings.load)) {
					s.settings.load();
				}
				
				s.wrapper.removeClass("image-wrapper-loading");
				s.img.show();
			})
			.appendTo(this.wrapper)
			.attr("src", this.settings.src);
	}
	
	this.wrapper.css({"height": this.settings.height});
	
	this.getWrapper = function() {
		return this.wrapper;
	}
	
	this.getCaption = function() {
		return this.settings.caption;
	}
	
	this.hide = function(callback, instant) {
		if (instant === true) {
			this.wrapper.hide();
			if ($.isFunction(callback)) {
				callback();			
			}
		} else {
			if ($.isFunction(callback)) {
				this.wrapper.fadeOut(this.gallerySettings.transitionDuration, callback);
			} else {
				this.wrapper.fadeOut(this.gallerySettings.transitionDuration);
			}
		}
	}
	
	this.show = function(callback, instant) {
		if (instant === true) {
			this.wrapper.show();
			if ($.isFunction(callback)) {
				callback();
			}
		} else {
			if($.isFunction(callback)) {
				this.wrapper.fadeIn(this.gallerySettings.transitionDuration, callback);
			} else {
				this.wrapper.fadeIn(this.gallerySettings.transitionDuration);
			}
		}
	}
};

var JMMSlideShow = function(options) {
	
	var s = this;
	
	this.settings = $.extend({
		transitionDuration: 800,
		stageResizeDuration: 300	
	}, options);
	
	this.wrapper = $(this.settings.target).removeClass("slideshow-nojs");
	this.stage = $("> .stage", this.wrapper);
	this.images = [];
	this._current = -1;
	
	this.caption = $(".caption", this.wrapper);
	
	this.progressBar = $('<div class="progress-bar"><div class="inner"><div class="slider" /></div></div>').appendTo(this.stage);
	this.progressSlider = $(".slider", this.progressBar);
	
	this.size = function() {
		return this.images.length;
	}
	
	this.refreshLoader = function() {
	
		var imagesLoaded = 0;
		
		for (var i in this.images) {
			if (this.images[i]._loaded == true) {
				imagesLoaded++;
			}
		}
		
		if (imagesLoaded == this.size()) {
			this.progressSlider.width("100%");
			window.setTimeout(function() { s.progressBar.fadeOut() }, 250);
		} else {
			this.progressSlider.width(Math.round(imagesLoaded / this.size() * 100) + "%");
		}		
	};
	
	// get first image from the dom
	this.images.push(new JMMSlideShowImage({
		method: "target",
		wrapper: $("div.image-wrapper"),
		img: $("img", this.stage),
		caption: $(".caption").html(),
		load: function() { s.refreshLoader(); }
	}, this.settings));
	
	// traverse all images given by array
	for (var i in this.settings.images) {
		var img = new JMMSlideShowImage($.extend(this.settings.images[i], { load: function() { s.refreshLoader(); } }), this.settings);
		this.stage.append(img.getWrapper());
		img.hide(null, true);
		this.images.push(img);
	}

	this.prevLink = $('<a href="#" class="prevLink" />')
		.appendTo(this.stage)
		.click(function() { s.prev(); return false; });
	
	this.nextLink = $('<a href="#" class="nextLink" />')
		.appendTo(this.stage)
		.click(function() { s.next(); return false; });
	
	this.next = function() {
		if (this.images[this._current + 1]) {
			this._goto(this._current + 1);
		} else {
			this._goto(0);
		}
	};
	
	this.prev = function() {
		if (this._current > 0) {
			this._goto(this._current - 1);
		} else {
			this._goto(this.size() - 1);
		}		
	};
	
	this._goto = function(i) {
		if (this.images[i]) {
			if (this._current != -1) {
				
				var currentHeight = s.images[s._current].settings.height;
				var nextHeight = s.images[i].settings.height;
				
				if (nextHeight > currentHeight) {
					this.images[this._current].hide();
					this.images[i].show(function() {
						s.stage.animate({height: nextHeight}, s.settings.stageResizeDuration, "linear", function() {
							s.caption.html(s.images[i].getCaption());
						});
					});		
				} else if (nextHeight < currentHeight) {
					var cur = this._current;
					this.stage.animate({height: nextHeight}, s.settings.stageResizeDuration, "linear", function() {
						s.images[cur].hide();
						s.images[i].show(function() { s.caption.html(s.images[i].getCaption()); });
					});
				} else {
					this.images[s._current].hide();
					this.images[i].show(function() { s.caption.html(s.images[i].getCaption()); });
				}
			} else {
				this.stage.css("height", this.images[i].settings.height);
				this.images[i].show(null, true);
				this.caption.html(this.images[i].getCaption());
			}
			
			s._current = i;
		}		
	};
	
	this.addImage = function(options) {
		var w = new JMMSlideShowImage(options);
		this.images.push(w);
	}
	
	this.init = function() {		
		this._goto(0);	
	};
}


$.createJMMSlideShow = function(options) {
	new JMMSlideShow(options).init();
}

})(jQuery);
