(function($) {
	$.fn.lacuca = function(options) {
		if(arguments.length==0) { options = {}; }
		options.galleryid = this.attr('id');
		options.defaultbuttons = {enable: false};
		options.panelbehavior = {wraparound:false, persist:false};
		options.statusvars = [];
		options.contenttype = ['inline'];

		var opts = $.extend($.fn.lacuca.defaults, options);
		opts.$carousel = this;
		opts.$belt = this.find('.'+opts.beltclass);
		opts.$frame = $('#'+opts.frameid).css('position','relative');
		opts.$meta = $('#'+opts.metaid).css('position', 'relative');
		var index = 1;
		var ajaxPartial = true;
		var status;
		var prevStatus;
		var prevSteps;
		var moving = false;
		var loading = false;
		var loadingFrame = false;
		var loadingThumbs = false;
		var loadingBeforeSteps = false;
		var imagesLoading = false;
		var filesToLoad = 0;
		var newImage = false;
		var newImageFrame = false;
		var newInfo = false;

		function imgLoad(objects, callback, errorCallback) {
			if(arguments.length<3) {
				errorCallback = callback;
			}
			objects.each(function(){
				if(this.nodeType === 1 && this.tagName.toLowerCase() === 'img' && this.src !== '') {
					// Image is already complete, fire the hollaback (fixes browser issues were cached
					// images isn't triggering the load event)
					if(this.complete || this.readyState === 4) {
						callback();
					}
					// Check if data URI images is supported, fire 'error' event if not
					else if(this.readyState === 'uninitialized' && this.src.indexOf('data:') === 0) {
						errorCallback();
					}else{
						$(this).load(callback);
					}
				}
			});
		}

		function attachLinks() {
			opts.$belt.find('a').unbind().click(function(){
				if(!loadingThumbs) {
					if(loadingFrame) {
						newImage.remove();
						newInfo.remove();
					}else{
						loadingFrame = $('<div class="loading"><div class="overload"></div><div class="icon"></div></div>').prependTo(opts.$frame).fadeTo(0,0).fadeTo('slow', 1);
					}
					opts.$belt.find('.selected').removeClass('selected');
					var a = $(this).addClass('selected');
					var panel = a.parent('.'+opts.panelclass);
					var thumb = a.find('img');
					var title = a.attr('title');
					if(!title || !title.length) {
						title = thumb.attr('title');
						if(!title || !title.length) {
							title = thumb.attr('alt');
						}
					}
					var oldImg = opts.$frame.find('img');
					var oldInfo = opts.$meta.children();
					loadingFrame.find('.icon').css('height', oldImg.height());
					newImage = $('<img src="'+a.attr('href')+'" alt="'+title+'" title="'+title+'" />');
					newImageFrame = $('<div></div>').prepend(newImage).fadeTo(0, 0).prependTo(opts.$frame).css('position','absolute').css('width','100%').css('height','100%');
					newInfo = $('<div></div>').append(panel.find('.meta').children().clone(true)).fadeTo(0,0).prependTo(opts.$meta).css('position','absolute');
					imgLoad(newImage, function() {
						loadingFrame.stop();
						loadingFrame.fadeTo("slow", 0, function(){$(this).remove();});
						loadingFrame = false;
						if(newImage.width() > opts.$frame.width()) {
							newImage.css('width', opts.$frame.width()+'px');
						}
						if(newImage.height() > opts.$frame.height()) {
							newImage.css('width', 'auto');
							newImage.css('height', opts.$frame.height()+'px');
						}
						oldImg.fadeTo('slow', 0, function(){
							var img = $(this);
							var parent = img.parent();
							if(parent.children().length==1) {
								parent.remove();
							}else{
								img.remove();
							}
						});
						oldInfo.fadeTo('slow', 0, function(){$(this).remove();});
						newImageFrame.fadeTo('slow', 1);
						newInfo.fadeTo('slow', 1);
					});
				}
				return false;
			}).css('cursor', 'pointer');
		}
		
		function refreshStatus() {
			var config=stepcarousel.configholder[opts.galleryid]
			var startpoint=config.currentpanel //index of first visible panel 
			var visiblewidth=0
			var visiblespanels = 1;
			for(var endpoint=startpoint; endpoint<config.paneloffsets.length; endpoint++){ //index (endpoint) of last visible panel
				visiblewidth+=config.panelwidths[endpoint]
				if (visiblewidth>config.gallerywidth){
					break
				}
				visiblespanels++;
			}
			prevStatus = status;
			status = {
				startpoint: ++startpoint,
				endpoint: (endpoint+1==startpoint)? startpoint : endpoint, //If only one image visible on the screen and partially hidden, set endpoint to startpoint
				length: config.paneloffsets.length,
				visiblespanels: visiblespanels,
				visiblewidth: visiblewidth,
				gallerywidth: config.gallerywidth,
				index: index,
				ajaxpartial: ajaxPartial
			}
			if(!prevStatus) {
				prevStatus = status;
			}
		}

		this.getStatus = function() {
			return status;
		}
		
		this.pos = function() {
			return status.startpoint;
		}
		
		this.prev = function(steps, fillContent) {
			var ret = false;
			if(!loadingThumbs) {
				moving = true;
				if(arguments.length==0) { steps = 1; }
				opts.$belt.stop(true);
				stepcarousel.stepBy(opts.galleryid, -steps);
				refreshStatus();
				if(arguments.length>=2 && index>1 && prevStatus.startpoint-steps != status.startpoint) {
					prevSteps = -steps;
					fillContent();
				}else{
					ret = true;
				}
				moving = false;
			}
			return ret;
		}

		this.next = function(steps, fillContent) {
			var ret = false;
			if(!loadingThumbs) {
				moving = true;
				if(arguments.length==0) { steps = 1; }
				opts.$belt.stop(true);
				stepcarousel.stepBy(opts.galleryid, steps);
				refreshStatus();
				if(arguments.length>=2 && status.visiblewidth < status.gallerywidth) {
					prevSteps = steps;
					fillContent();
				}else{
					ret = true;
				}
				moving = false;
			}
			return ret;
		}
		
		this.goTo = function(panel) {
			var config=stepcarousel.configholder[opts.galleryid];
			stepcarousel.stopautostep(config);
			var panel=Math.min(panel-1, config.paneloffsets.length-1);
			var endpoint=config.paneloffsets[panel]+(panel==0? 0 : config.beltoffset);
			config.$belt.css('left', -endpoint+'px');
			config.currentpanel=panel;
			stepcarousel.statusreport(opts.galleryid);
			refreshStatus();
		}
		
		this.setLoading = function() {
			loading = $('<div class="loading"><div class="overload"></div><div class="icon"></div></div>').appendTo(this).fadeTo(0,0).fadeTo('slow', 1);
			loadingThumbs = true;
			opts.setLoading();
		}
		
		this.unsetLoading = function() {
			loading.fadeTo("slow", 0, function(){$(this).remove();});
			loading = loadingThumbs = false;
			if(loadingBeforeSteps) {
				loadingBeforeSteps = false;
				if(prevSteps<0) {
					opts.$carousel.prev(-prevSteps);
				}else{
					opts.$carousel.next(prevSteps);
				}
			}
			opts.unsetLoading();
		}
		
		this.loadContent = function(url, relativePanelsToSave, onload) {
			if(!loadingThumbs) {
				if(arguments.length<3) {
					onload = function(){};
				}
				var panels = opts.$belt.children();
				var sign = relativePanelsToSave<0? -1 : 1;
				var panelsToSave = relativePanelsToSave*sign;
				var minPanelsToSave;
				if(moving) {
					minPanelsToSave = sign>0?
					/* inserting after */	prevStatus.startpoint:
					/* inserting before */	status.length-prevStatus.startpoint+1;
					opts.$belt.stop(true);
					stepcarousel.stepTo(opts.galleryid, prevStatus.startpoint); //Finish the animation
					loadingBeforeSteps = true;
				}else{
					minPanelsToSave = sign>0?
					/* inserting before */	status.startpoint:
					/* inserting after */	status.length-status.startpoint+1;
				}
				this.setLoading();
				if(panelsToSave > panels.length) {
					panelsToSave = panels.length;
					relativePanelsToSave = panelsToSave*sign;
				}
				if(panelsToSave < minPanelsToSave) {
					panelsToSave = minPanelsToSave;
					relativePanelsToSave = panelsToSave*sign;
				}
				$.ajax({
					url: url, //path to external content
					async: true,
					error:function(XMLHttpRequest){
						loading.html(XMLHttpRequest.responseText);
					},
					success:function(content, textStatus, XMLHttpRequest) {
						ajaxPartial = XMLHttpRequest.status == 206;
						content = $(content);
						var toRemove = status.length-panelsToSave;
						var toInsert = content.length;
						var prev;
						if(sign>0) {
							//InsertBefore
							prev = (loadingBeforeSteps? prevStatus.startpoint : status.startpoint) + toInsert;
							index -= toInsert;
							for(var i=0; i<toRemove; i++) {
								panels.eq(i+panelsToSave).remove();
							}
							content.prependTo(opts.$belt);
						}else{
							//InsertAfter
							prev = (loadingBeforeSteps? prevStatus.startpoint : status.startpoint) - toRemove;
							index += toRemove;
							for(var i=0; i<toRemove; i++) {
								panels.eq(i).remove();
							}
							content.appendTo(opts.$belt);
						}
						imagesLoading = content.find('img').addClass('loading');
						filesToLoad = imagesLoading.length;
						imgLoad(imagesLoading, function(){
							if(--filesToLoad == 0) {
								imagesLoading.removeClass('loading');
								stepcarousel.init($, opts);
								prevStatus = null;
								opts.$carousel.goTo(prev);
								attachLinks();
								opts.$carousel.unsetLoading();
							}
						});
					}
				})
			}
		}
		
		imagesLoading = this.find('img').addClass('loading');
		filesToLoad = 0;
		imgLoad(imagesLoading, function(){
			if(--filesToLoad == 0) {
				imagesLoading.removeClass('loading');
				stepcarousel.setup(opts);
				refreshStatus();
				attachLinks();
				opts.$carousel.unsetLoading();
			}
		});
		filesToLoad += imagesLoading.length;
		if(filesToLoad > 0) {
			this.setLoading();
		}else{
			imagesLoading.removeClass('loading');
			stepcarousel.setup(opts);
			refreshStatus();
			attachLinks();
		}
		
		return this;	
	}
	
	$.fn.lacuca.defaults = {
		beltclass: 'belt', //class of inner "belt" DIV containing all the panel DIVs
		panelclass: 'panel', //class of panel DIVs each holding content
		frameid: 'frame',
		metaid: 'meta',
		autostep: {enable:false},
		setLoading: function(){},
		unsetLoading: function(){}
	}

})(jQuery);
