/**
 *	jQuery MG Gallery Plugin
 *
 *	Version 1.1.0
 *
 * Copyright (c) 2011 Wolfgang Moritz (http://www.wolfmoritz.com) - Metolius Group (http://metoliusgroup.com)
 * Licensed under the MIT License:
 *   http://www.opensource.org/licenses/mit-license.php
 */
;(function($) {

	var config = {};
	var $thumbs;

	// MG Gallery Main Function
	$.fn.mggallery = function (options) {

		// Merge defaults with parameters (options) and assign to config
		$.extend(config, $.fn.mggallery.defaults, options);

		// Add local properties to config object
		config.gallery = {
			priorIndex: 0,
			currentIndex: 0,
			currentHash: '1',
			thumbnailCount: 0,
			thumbnailPagePriorIndex: 1,
			thumbnailPageIndex: 1,
			thumbnailTotalPages: 0,
			slideShowIntervalId: 0
		};

		// Cache thumbnail list items and initialize the gallery if thumbs are found.
		$thumbs = this.children('ul').children('li');
		config.gallery.thumbnailCount = $thumbs.size();
		if (config.gallery.thumbnailCount > 0) {

			// We have thumbs, fire up the engine!
			$.fn.mggallery.methods.init(this);

			// After everything is up and running, preload main images in the background.
			$.fn.mggallery.methods.preloadImages();
		};

		return this;
	}; // End $.fn.mggallery

	// !bookmark Public Methods
	$.fn.mggallery.methods = {
		// Append main image, title, meta containers to mainImageDivContainerId after page load, and prepend slideShowControls div.
		initGalleryContainer: function() {
			var currentHtml = '<div class="current" style="opacity: 0;">';
			currentHtml += '<div class="' + config.currentImageDivClass.replace('.','') + '"><a href="#"><img src="" /></a></div>';
			currentHtml += '<div class="' + config.currentTitleDivClass.replace('.','') + '"></div>';
			currentHtml += '<div class="' + config.currentMetaDivClass.replace('.','') + '"></div></div>';
			$(config.mainImageDivContainerId).html(currentHtml);
			$(config.mainImageDivContainerId).before('<div class="slideShowControls" />');

			// If the slide show has been enabled, then append slide show controls
			if(config.slideShowInterval > 0) {
				$('.slideShowControls').html('<span class="pause">' + config.slideShowPause + '</span><span class="play">' + config.slideShowPlay + '</span>');
			};
		},

		// Load current image and text/html to container
		loadImage: function (newImage) {
			// Get the attributes of the new item
			var $newImg = $(newImage);
			var newSrc = $newImg.children('a').attr('href');
			var newTitle = $newImg.children('a').attr('title');
			var newMeta = $newImg.children(config.thumbnailMetaDivClass).html();

			// Set prior and current indexes
			config.gallery.priorIndex = config.gallery.currentIndex;
			config.gallery.currentIndex = $newImg.data('img_id');
			config.gallery.thumbnailPagePriorIndex = config.gallery.thumbnailPageIndex;
			config.gallery.thumbnailPageIndex = $newImg.data('thumbpage');

			// Set URL hash with image path and name for deep linking
			if(config.enableDeepLinks && newSrc !== undefined) {
				window.location.hash = newSrc.replace(window.location.hostname,'').replace(window.location.protocol,'').replace('//','');
				config.gallery.currentHash = $newImg.data('img_hash');
			};

			// New image source
			$('div.current').children(config.currentImageDivClass).children('a').children('img').attr('src',newSrc);

			// Don't display Current Image Title if empty.
			if( ! $.trim(newTitle)) {
				$('div.current').children(config.currentTitleDivClass).hide();
			} else {
				$('div.current').children(config.currentTitleDivClass).html(newTitle).show();
			};

			// Don't display Current Image Meta if empty.
			if( ! $.trim(newMeta)) {
				$('div.current').children(config.currentMetaDivClass).hide();
			} else {
				$('div.current').children(config.currentMetaDivClass).html(newMeta).show();
			};

			// Swap ".currentThumb" class on thumbnails
			$('li.' + config.thumbnailCurrentItemClass).removeClass(config.thumbnailCurrentItemClass.replace('.',''));
			$newImg.addClass(config.thumbnailCurrentItemClass.replace('.',''));

			// Fade old and new thumbs
			$.fn.mggallery.methods.fadeThumb('li[data-img_id="' + config.gallery.priorIndex + '"]', config.thumbDefaultOpacity);
			$.fn.mggallery.methods.fadeThumb($newImg, 1);

			// Check if the new image is in the current thumbnail set
			if(config.gallery.thumbnailPagePriorIndex !== config.gallery.thumbnailPageIndex) {
				$.fn.mggallery.methods.swapThumbPage();
			};
		},

		// Load the next image in sequence
		getNextImage: function() {
			if(config.gallery.currentIndex + 1 < config.gallery.thumbnailCount) {
				$.fn.mggallery.methods.exchangeImage('li[data-img_id="' + (config.gallery.currentIndex + 1) + '"]');
			} else {
				$.fn.mggallery.methods.exchangeImage('li[data-img_id="0"]');
			};
			$.fn.mggallery.methods.initThumbPageControls();
		},

		// Animate thumbnail opacity changes
		fadeThumb: function (thumbItem, newOpacity) {
			if($(thumbItem).data('img_id') === config.gallery.currentIndex) {
				newOpacity = 1;
			};
			$(thumbItem).children('a').children('img').stop().animate({opacity: newOpacity}, config.animationSpeed);
		},

		// Assign prefered image exchange type function to this variable in init()
		exchangeImage: '',

		// Swap images sequentially
		swapImage: function (newImage) {
			$('div#' + config.mainImageDivContainerId + '>div.current').animate({opacity: 0}, config.animationSpeed, function() {
				$.fn.mggallery.methods.loadImage(newImage);
			}).animate({opacity: 1}, config.animationSpeed);
		},

		// Crossfade images
		crossfadeImage: function (newImage) {
			$current = $('div#' + config.mainImageDivContainerId + '>div.current');
			$current.clone().appendTo(config.mainImageDivContainerId).toggleClass('current prior');
			$current.css('opacity',0);
			$.fn.mggallery.methods.loadImage(newImage);
			$current.stop().animate({opacity: 1}, config.animationSpeed);
			$('div#' + config.mainImageDivContainerId + '>div.prior').stop().animate({opacity: 0}, config.animationSpeed, function() {
				$('div#' + config.mainImageDivContainerId + '>div.prior').remove();
			});
		},

		// Clean image path selector
		hashImagePath: function(dirtyPath) {
			return dirtyPath.replace(window.location.hostname,'').replace(window.location.protocol,'').replace(/[^a-zA-Z0-9]/g, '');
		},

		// Silently preload large (main) images in background once the page is up.
		preloadImages: function () {
			$thumbs.each(function () {
				$('<img/>')[0].src = $(this).children('a').attr('href');
			});
		},

		// Initialize thumbnail pagination controls
		initThumbPageControls: function() {
			var first = '<span class="first" title="' + config.thumbNavFirstTitle + '">' + config.thumbNavFirst + '</span>';
			var prev = '<span class="prev" title="' + config.thumbNavPrevTitle + '">' + config.thumbNavPrev + '</span>';
			var next = '<span class="next" title="' + config.thumbNavNextTitle + '">' + config.thumbNavNext + '</span>';
			var last = '<span class="last" title="' + config.thumbNavLastTitle + '">' + config.thumbNavLast + '</span>';
			var controls = '';

			// If on first page, then only include next and last
			if(config.gallery.thumbnailPageIndex === 1) {
				controls = next + last;
			// If on the last page, then only include previous and first
			} else if (config.gallery.thumbnailPageIndex === config.gallery.thumbnailTotalPages) {
				controls = first + prev;
			// Otherwise, show all controls
			} else {
				controls = first + prev + next + last;
			};

			$('.thumbPageControls').html(controls);
		},

		// Swap out thumbnail page
		swapThumbPage: function() {
			// Fade out the current thumbnail page
			$('div.thumbPage_' + config.gallery.thumbnailPagePriorIndex).add('div.thumbPageControls').fadeOut(config.animationSpeed, function() {
				$.fn.mggallery.methods.initThumbPageControls();

				// Now fade in the new thumnail page, and update the page controls
				$('.thumbPage_' + config.gallery.thumbnailPageIndex).add('div.thumbPageControls').fadeIn(config.animationSpeed);
			});
		},

		// Start the slide show
		startSlideShow: function () {
			if(config.gallery.slideShowIntervalId === 0) {
				config.gallery.slideShowIntervalId = window.setInterval(function() {
					$.fn.mggallery.methods.getNextImage();
				},config.slideShowInterval);
			};
		},

		// Stop the running slide show
		stopSlideShow: function () {
			if(config.gallery.slideShowIntervalId !== 0) {
				window.clearInterval(config.gallery.slideShowIntervalId);
				config.gallery.slideShowIntervalId = 0;
			};
		},

		// Enable polling for change in URL hash (back/forward button)
		pollImageHashChange: function() {
			var id = window.setInterval(function () {
				if(config.gallery.currentHash !== $.fn.mggallery.methods.hashImagePath(window.location.hash)) {
					$.fn.mggallery.methods.exchangeImage('li[data-img_hash="' + $.fn.mggallery.methods.hashImagePath(window.location.hash) + '"]');
				};
			}, 250);
		},

		// Main initialization function
		init: function($galleryThumbnails) {
			//Assign each thumbnail list item a numerber and a hash data- selector.
			$thumbs.each(function(i) {
				$(this).addClass('thumbItem').attr('data-img_id',i).attr('data-img_hash',$.fn.mggallery.methods.hashImagePath($(this).children('a').attr('href')));
			});

			// Add the thumbnail page controls div if we need it or not (for consistent layout), and create the main image container
			$galleryThumbnails.prepend('<div class="thumbPageControls" />');
			$.fn.mggallery.methods.initGalleryContainer();

			// Loop through all thumbnails, slicing into sets based on thumbPageLimit.
			var i = 0;
			while(i < config.gallery.thumbnailCount) {
				config.gallery.thumbnailTotalPages += 1;
				if(config.gallery.thumbnailTotalPages === 1) {
					$thumbs.slice(i, i + config.thumbPageLimit).wrapAll('<div class="thumbPage_' + config.gallery.thumbnailTotalPages + '" />').attr('data-thumbPage',config.gallery.thumbnailTotalPages);
				} else {
					$thumbs.slice(i, i + config.thumbPageLimit).wrapAll('<div class="thumbPage_' + config.gallery.thumbnailTotalPages + '" style="display:none;"/>').attr('data-thumbPage',config.gallery.thumbnailTotalPages);
				};

				i += config.thumbPageLimit;
			};

			// Load image specified in the URL, else the first one
			if($.fn.mggallery.methods.hashImagePath(window.location.hash).length > 0 && $.fn.mggallery.methods.hashImagePath(window.location.hash) !== undefined) {
				$.fn.mggallery.methods.loadImage('li[data-img_hash="' + $.fn.mggallery.methods.hashImagePath(window.location.hash) + '"]');
			} else {
				$.fn.mggallery.methods.loadImage($thumbs[0]);
			};

			// Set image exchange type
			if(config.exchangeType === 'swap') {
				$.fn.mggallery.methods.exchangeImage = $.fn.mggallery.methods.swapImage;
			} else if (config.exchangeType === 'crossfade') {
				$.fn.mggallery.methods.exchangeImage = $.fn.mggallery.methods.crossfadeImage;
			};

			// Set thumbnail pagination if requested and there are more thumbnails than the display limit
			if(config.thumbPageLimit > 0 && config.gallery.thumbnailCount > config.thumbPageLimit) {
				$.fn.mggallery.methods.initThumbPageControls();
			};

			// !bookmark Binding all events…
			// Event: Load next image if current main image clicked
			$(config.currentImageDivClass).find('a').click(function(e) {
				e.preventDefault();
				$.fn.mggallery.methods.getNextImage();
			});

			// Event: Load clicked thumbnail
			$galleryThumbnails.delegate('li.thumbItem','click',function(e) {
				e.preventDefault();
				// No sense to change anything if this is the current image
				if($(this).data('img_id') !== config.gallery.currentIndex) {
					$.fn.mggallery.methods.exchangeImage(this);
				};
			});

			// Event: Set hoverover opacity on thumbs
			$thumbs.hover(
				function() {
					$.fn.mggallery.methods.fadeThumb(this, 1);
				},
				function() {
					$.fn.mggallery.methods.fadeThumb(this, config.thumbDefaultOpacity);
			});

			// Event: Thumbnail page controls
			$('.thumbPageControls').delegate('span','click',function(e) {
				e.preventDefault();
				config.gallery.thumbnailPagePriorIndex = config.gallery.thumbnailPageIndex;
				var go = $(this).attr('class');
				if(go === 'first') {
					config.gallery.thumbnailPageIndex = 1;
				} else if (go === 'prev') {
					config.gallery.thumbnailPageIndex--;
				} else if (go === 'next') {
					config.gallery.thumbnailPageIndex++;
				} else if (go === 'last') {
					config.gallery.thumbnailPageIndex = config.gallery.thumbnailTotalPages;
				};
				$.fn.mggallery.methods.swapThumbPage();

				// Load first image on new thumbnail page if not already selected
				if($('.thumbPage_' + config.gallery.thumbnailPageIndex + '>.thumbItem:first').data('img_id') !== config.gallery.currentIndex) {
					$.fn.mggallery.methods.exchangeImage('.thumbPage_' + config.gallery.thumbnailPageIndex + '>.thumbItem:first');
				};
			});

			// Hide all thumbnail image meta divs, we don't want to see them with the thumbs.
			$thumbs.find(config.thumbnailMetaDivClass).hide();

			// We're now ready to raise the curtain. Show #galleryThumbnails if hidden, set the initial opacity and fade in the thumbnail list.
			$thumbs.children('a').children('img').css('opacity', 0);
			$galleryThumbnails.show();
			$('div#' + config.mainImageDivContainerId + '>div.current').animate({opacity: 1}, config.animationSpeed);
			$thumbs.each(function(i) {
				$.fn.mggallery.methods.fadeThumb(this, config.thumbDefaultOpacity)
			});

			// If the config.slideShowInterval is set to an interval, enable the slide show
			if(config.slideShowInterval > 0) {
				if(config.slideShowAutoStart) {
					$.fn.mggallery.methods.startSlideShow();
					$('.slideShowControls .play').hide().siblings('.pause').show();
				} else {
					$('.slideShowControls .pause').hide().siblings('.play').show();
				};

				// Handle slide show controls
				$('.slideShowControls').delegate('span','click',function(e) {
					var request = $(this).attr('class');
					if(request === 'play' && config.gallery.slideShowIntervalId === 0) {
						$.fn.mggallery.methods.getNextImage();
						$.fn.mggallery.methods.startSlideShow();
						$(this).hide().siblings('.pause').show();
					} else if (request === 'pause' && config.gallery.slideShowIntervalId !== 0) {
						$.fn.mggallery.methods.stopSlideShow();
						$(this).hide().siblings('.play').show();
					};
				});
			};

			// If backbutton functionality has been requested, start polling
			if(config.enableBackButton && config.enableDeepLinks) {
				$.fn.mggallery.methods.pollImageHashChange();
			};
		}
	};

	// !bookmark Default Options
	$.fn.mggallery.defaults = {
		thumbnailMetaDivClass:		'.thumbnailMeta',	// You can specify your own class or ID for gallery elements
		thumbnailCurrentItemClass:	'.currentThumb',
		mainImageDivContainerId:	'#galleryMainContainer',
		currentImageDivClass:		'.currentImage',
		currentTitleDivClass:		'.currentTitle',
		currentMetaDivClass:		'.currentMeta',
		animationSpeed:				1000, 			// Options include, 'slow', 'fast' or any number of milliseconds.
		exchangeType:				'crossfade', 	// Option includes 'swap'.
		thumbDefaultOpacity:		0.5, 			// Any number between 0 (invisible) and 1 (visible).
		thumbPageLimit:				9,				// Number of thumbnails to display at a time. Set to 0 (zero) to display all.
		thumbNavTop:				true,			// Include the thumbnail pagination controls at the top of the thumbnail gallery
		thumbNavBottom:				false,			// Include the thumbnail pagination controls at the bottom of the thumbnail gallery
		thumbNavFirst:				' &#171; ',		// "First" thumbnail pagination set label. You can also pass in an image tag as '<img src="path/image.ext" />', or enter '&nbsp;' and use CSS for the image.
		thumbNavFirstTitle:			'First',		// Use for alternate title text for thumbpage navigation controls.
		thumbNavPrev:				' &lt; ',		// "Previous" thumbnail pagination set label. You can also pass in an image tag as '<img src="path/image.ext" />', or enter '&nbsp;' and use CSS for the image.
		thumbNavPrevTitle:			'Previous',		// Use for alternate title text for thumbpage navigation controls.
		thumbNavNext:				' &gt; ',		// "Next" thumbnail pagination set label. You can also pass in an image tag as '<img src="path/image.ext" />', or enter '&nbsp;' and use CSS for the image.
		thumbNavNextTitle:			'Next',			// Use for alternate title text for thumbpage navigation controls.
		thumbNavLast:				' &#187; ',		// "Last" thumbnail pagination set label. You can also pass in an image tag as '<img src="path/image.ext" />', or enter '&nbsp;' and use CSS for the image.
		thumbNavLastTitle:			'Last',			// Use for alternate title text for thumbpage navigation controls.
		slideShowInterval:			3000,			// Slide show interval in milliseconds. Set to 0 to disable the slide show and controls.
		slideShowPlay:				' Play ',		// "Play" slide show label.You can also pass in an image tag as '<img src="path/image.ext" />', or enter '&nbsp;' and use CSS for the image.
		slideShowPause:				' Pause ',		// "Pause" slide show label.You can also pass in an image tag as '<img src="path/image.ext" />', or enter '&nbsp;' and use CSS for the image.
		slideShowAutoStart:			false,			// Whether to start the slide show on page load, or let the user choose to activate.
		enableDeepLinks:			true,			// Appends hash to URL for the current image to allow direct links.
		enableBackButton:			false			// Allows users to browse prior images using the back button. Only works if enableDeepLinks is true, as this simply polls the window.location.hash for changes.
	};
})(jQuery);

