// wrap plugin in a closure
(function($) {
	// imagefade plugin definition
	$.fn.imagefade =
		function(options) {
			// extend default options with those provided
			var
				opts = $.extend({}, $.fn.imagefade.defaults, options),
				imgRegExp = /#img\-([0-9]+)/,
				matches;

			return this.each(
				function() {
					var
						$this = $(this),

						// build element specific options
						o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts,

						$clone =
							$this
								.clone()
									.addClass('open')
									.css(
										{
											left: '-9999px',
											position: 'absolute'
										}
									)
									.insertAfter($this),
						cloneWidth = $clone.width(),
						$parent = $this.parent(),
						$images = $('img:not(.thumb)', this),
						$thumbs = $('img.thumb', this),
						$index = $('.index', this),
						$imageClose = $('a.image-fade-close', this),
						$controls = $('.controls', this),
						$descriptions = $clone.next('.descriptions'),
						$descriptionsList = $('ul', $descriptions);

					// handle image-fade elements with hidden parents specially
					if (!cloneWidth) {
						if ($parent.hasClass('hidden')) {
							$parent.removeClass('hidden');
							cloneWidth = $clone.width();
							$parent.addClass('hidden');
						}
					}

					$clone.remove();

					$this
						.hover(
							function(e)
							{
								$controls.stop(true, true).fadeIn('fast');
							},
							function(e)
							{
								$controls.stop(true, true).fadeOut('fast');
							}
						);

					$images
						.each(
							function(i, image) {
								var
									$image = $(image),
									img = new Image(),
									loadHandler =
										function(e) {
											var imageHeight = $image.height();

											if (!imageHeight) {
												if ($parent.hasClass('hidden')) {
													$parent.removeClass('hidden');
													imageHeight = $image.height();
													$parent.addClass('hidden');
												}
											}

											if (imageHeight) {
												// destroy event handler
												$(img).unbind('load', loadHandler);
											}

											$image
												.css(
													{
														left: 0,
														position: 'absolute',
														top: 0
													}
												)
												.data('image-fade-init-height', imageHeight)
												.data('image-fade-init-width', $image.width())
												.data(
													'image-fade-raster-height',
													13 + (Math.floor((imageHeight - 13) / 28) + 1) * 28
												);

											$this.data('image-fade-init-height', $this.height());
											$this.data('image-fade-init-width', $this.width());
										};

								img.src = $image.attr('src');
								img.onload = loadHandler;

								loadHandler();
							}
						);

					$thumbs
						.bind(
							'click',
							function(e) {
								matches = imgRegExp.exec($('.active a', $index).attr('href'));

								var $image = matches ? $images.eq(matches[1]) : $images.eq(0);

								$this
									.addClass('open')
									.css('width', $this.data('image-fade-init-width'))
									.animate(
										{
											height: $image.data('image-fade-raster-height'),
											width: $image.data('image-fade-init-width')
										},
										'normal'
									);

								$image
									.fadeIn('normal')
									.css('width', '100%');
								$thumbs
									.css('width', '100%')
									.fadeOut('normal');
								$index
									.fadeIn('normal')
									.animate(
										{
											bottom:
												$image.data('image-fade-raster-height')
												- $image.data('image-fade-init-height')
										},
										'normal'
									);
								$imageClose.fadeIn('normal');
							}
						);

					$imageClose
						.bind(
							'click',
							function(e) {
								if (!$this.is(':animated')) {
									$this
										.animate(
											{
												height: $this.data('image-fade-init-height'),
												width: $this.data('image-fade-init-width')
											},
											'normal',
											function() {
												$this.removeClass('open');
											}
										);
									$images
										.filter(':visible')
											.fadeOut('normal')
										.end();
									$thumbs.fadeIn('normal');
									$(this).fadeOut('normal');
									$index.fadeOut('normal');
								}

								return false;
							}
						);

					$controls
						.hide()
						.delegate(
							'a',
							'click',
							function(e)
							{
								var
									$control = $(this).parent(),
									$visibleImage = $images.filter(':visible'),
									$newImage = $visibleImage[$control.hasClass('previous') ? 'prev' : 'next']('img'),
									$newDescription;

								if(!$newImage.length) return false;

								if(!$images.length || $images.index($newImage)+1 == ($control.hasClass('previous') ? 1 : $images.length))
								{
									$control.hide();
								}

								if($images.length && $images.index($newImage) > 0)
								{
									$('.previous', $controls).show();
								}
								if($images.length && $images.index($newImage)+1 < $images.length)
								{
									$('.next', $controls).show();
								}
								$newDescription = $('li', $descriptions).eq($images.index($newImage));

								$controls
									.queue(
										function(next)
										{
											$visibleImage
												.fadeOut('normal')
												.queue(function(next) { $newImage.fadeIn('normal', next); });
											$descriptionsList.animate({ 'left': -$newDescription.position().left }, 'normal', next);
										}
									);
								return false;
							}
						);

					$index
						.bind(
							'click',
							function(e) {
								var
									$target = $(e.target),
									$parent = $target.parent();

								if ($target.is('a')) {
									if (!$parent.hasClass('active')) {
										$('.active', $index).removeClass('active');
										$parent.addClass('active');

										matches = imgRegExp.exec($target.attr('href'));
										$images
											.filter(':visible')
												.fadeOut('normal')
												.queue(
													function() {
														var $image = $images.eq(matches[1]);
														$image
															.fadeIn(
																'normal',
																function() {
																	$images.dequeue();
																}
															);
														if ($thumbs.length) {
															$this
																.animate(
																	{
																		height: $image.data('image-fade-raster-height')
																	},
																	'normal'
																);
															$index
																.animate(
																	{
																		bottom:
																			$image.data('image-fade-raster-height')
																			- $image.data('image-fade-init-height')
																	},
																	'normal'
																);
														}
													}
												)
											.end();
									}

									return false;
								}
							}
						);
				}
			);
		};

	// imagefade plugin default options
	$.fn.imagefade.defaults =
		{
		};
})(jQuery);
