(function($)
{
	$.fn.shadowGallery = function(options)
	{
		options = $.extend({ }, $.fn.shadowGallery.defaults, options);
		return this.each(function()
		{
			$this = $(this);
			
			// Set up thumbnails.
			var images = thumbnails($this.filter('img'), options.links);
			
			if (options.shadowbox)
			{
				// Add Shadowbox relations.
				var links = $this.find('a.thumbnail-scaled').attr('rel', 'shadowbox[' + options.galleryId + ']');
				Shadowbox.setup($.makeArray(links));
			}
			
			if (options.fade)
			{
				// Add hover-fade to images.
				images.css('opacity', options.defaultOpacity);
				images.hover(function()
				{
					$(this).fadeTo(options.fadeSpeed, options.hoverOpacity);
				}, function()
				{
					$(this).fadeTo(options.fadeSpeed, options.defaultOpacity);
				});
			}
		});
	};
	
	$.fn.shadowGallery.defaults =
	{
		links: true,
		shadowbox: true,
		fade: true,
		defaultOpacity: 0.75,
		hoverOpacity: 1,
		fadeSpeed: 'fast',
		galleryId: 'shadow-gallery'
	};
	
	function thumbnails(targets, insertLinks)
	{
		var callback = function(image)
		{
			image = $(image);
			var container = image.parent();
			if (insertLinks)
			{
				if (container.is('a:not(.thumbnail-scaled)'))
				{
					// Don't bother generating thumbnails if a (non-generated) link's already provided.
					return;
				}
				
				if (!container.is('a.thumbnail-scaled'))
				{
					// Generate a link to surround the image.
					image.wrap('<a href="' + image.attr('src') + '" class="thumbnail-scaled"></a>');
					container = image.parent();
				}
			}
			else
			{
				if (!container.is('.thumbnail-scaled'))
				{
					// Generate an inert wrapper.
					image.wrap('<div class="thumbnail-scaled"></div>');
					container = image.parent();
				}
			}
			
			container.css('overflow', 'hidden');
			
			// Generate scaled thumbnails. Thanks Galleria!
			var containerWidth = container.width();
			var containerHeight = container.height();
			var imageWidth = image.width();
			var imageHeight = image.height();
			var width = Math.ceil(imageWidth / imageHeight * imageHeight);
			var height = Math.ceil(imageHeight / imageWidth * containerWidth);
			if (imageWidth / imageHeight < containerWidth / containerHeight)
			{
				image.css({ height: 'auto', width: containerWidth, marginTop: - (height - containerHeight) / 2, marginLeft: 0 });
			}
			else
			{
				image.css({ width: 'auto', height: containerHeight, marginLeft: - (width - containerWidth) / 2, marginTop: 0 });
			}
		};
		
		return $(targets).filter('img').each(function()
		{
			var $this = $(this);
			
			// First pass; immediately as function is called. We do this a) so that at least
			// something has been done until the images have loaded and b) because Firefox
			// doesn't fire the 'load' event when navigating back.
			callback(this);
			
			// Second pass: when image has loaded. This ensures that the width/height calculations
			// have been done correctly.
			$this.load(function()
			{
				callback(this);
			});
		});
	};
})(jQuery);