/*!
* @file
* @brief    sigplus Image Gallery Plus extended prettySlider engine with jQuery
* @author   Levente Hunyadi
* @version  1.2
* @remarks  Copyright (C) 2009-2010 Levente Hunyadi
* @remarks  Licensed under GNU/GPLv3, see http://www.gnu.org/licenses/gpl-3.0.html
* @see      http://hunyadi.info.hu/projects/sigplus
*/

/*
* sigplus Image Gallery Plus plug-in for Joomla
* Copyright 2009-2010 Levente Hunyadi
*
* sigplus is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sigplus is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

(function ($) {
	/**
	* Maximum computed width of matched elements including margin, border and padding.
	*/
	$.fn.maxWidth = function() {
		var w = 0;
		this.each( function(index, el) {
			w = Math.max(w, $(el).outerWidth(true));
		});
		return w;
	}

	/**
	* Maximum computed height of matched elements including margin, border and padding.
	*/
	$.fn.maxHeight = function() {
		var h = 0;
		this.each( function(index, el) {
			h = Math.max(h, $(el).outerHeight(true));
		});
		return h;
	}

	/**
	* Initialize image slider.
	*/	
	$.fn.imageSlider = function (settings) {
		// default configuration properties
		var defaults = {
			rowCount: 1,                // number of rows per slider page
			columnCount: 4,             // number of columns per slider page
			showButtons: true,          // whether to show navigation buttons
			showLinks: true,            // whether to show navigation links
			showPageCounter: true,      // whether to show page counter
			showOverlayButtons: true,   // whether to show navigation buttons that overlay image thumbnails
			alignment: 'left',          // 'left' (default), 'center' or 'right'
			orientation: 'horizontal',  // 'horizontal' (default) or 'vertical'
			navigation: 'top',          // 'top' (default), 'bottom' or 'both'
			firstText: 'First',         // the text of the navigate to first link
			prevText: 'Previous',       // the text of the navigate to previous link
			nextText: 'Next',           // the text of the navigate to next link
			lastText: 'Last',           // the text of the navigate to last link
			pageText: '%1$d of %2$d',   // the content to replace "image 1 of 2" with %1$d and %2$d for placeholders
			duration: 800               // duration for scroll animation [ms]
		};
		settings = $.extend(defaults, settings);
		if (settings.itemCount) {  // number of items per slider page set explicitly
			switch (settings.orientation) {
				case 'vertical':
					settings.rowCount = settings.itemCount;
					settings.columnCount = 1;
					break;
				default:  // case 'horizontal':
					settings.rowCount = 1;
					settings.columnCount = settings.itemCount;
			}
		}
		
		var gallery = this;
		var itemDimensions;             // maximum width and height of items in viewport
		var sliderDimensions;
		var viewportDimensions;
		var sliderIndexPosition = 0;    // index of item in slider taking the current first position

		/**
		* Align an element in parent container according to alignment settings.
		*/
		function _align(el) {
			switch (settings.alignment) {
				case 'center':
					el.addClass('imageSliderCenter'); break;
				case 'right':
					el.addClass('imageSliderRight'); break;
				default:  // left
					el.addClass('imageSliderLeft');
			}
		}
		
		/**
		* Get dimensions for image slider items.
		*/
		function _getItemDimensions() {
			if ($('li img', gallery).length == $('li', gallery).length) {  // use image dimensions if list has only images
				var itemWidth = $('li img', gallery).maxWidth();     // maximum image width
				var itemHeight = $('li img', gallery).maxHeight();   // maximum image height
			} else {
				var itemWidth = $("li", gallery).maxWidth();
				var itemHeight = $("li", gallery).maxHeight();
			}
			return { width: itemWidth, height: itemHeight }
		}

		/**
		* Setup slider viewport.
		*/
		function _setup() {
			gallery.addClass('imageSlider');
			switch (settings.alignment) {
				case 'left':
					gallery.addClass('imageSliderLeft'); break;
				case 'right':
					gallery.addClass('imageSliderRight'); break;
			}

			var count = $('li', gallery).length;
			itemDimensions = _getItemDimensions();
			viewportDimensions = {
				width: settings.columnCount * itemDimensions.width,
				height: settings.rowCount * itemDimensions.height
			};
			switch (settings.orientation) {
				case 'vertical':
					sliderDimensions = {
						width: settings.columnCount * itemDimensions.width,
						height: Math.ceil(count / settings.columnCount) * itemDimensions.height
					};
					break;
				default:  // case 'horizontal':
					sliderDimensions = {
						width: Math.ceil(count / settings.rowCount) * itemDimensions.width,
						height: settings.rowCount * itemDimensions.height
					};
			}
			
			// resize unordered list that encapsulates items to scrollable slider ribbon dimensions
			$('ul', gallery).css({
				width: sliderDimensions.width,
				height: sliderDimensions.height
			});
			
			$('li', gallery).each(function() {
				// resize list items to maximum item width and height
				$(this).css({
					width: itemDimensions.width,
					height: itemDimensions.height
				});
				var image = $('img', this);
				if (image.length == 1) {
					// center descendants within available space in list item area
					$(this).children().wrapAll('<div class="imageSliderAlignment"><div></div></div>');
					var slideraligner = $('div.imageSliderAlignment', this);
					slideraligner.width(image.outerWidth(true));  // separate calls for Opera compatibility
					slideraligner.height(image.outerHeight(true));
				}
			});
			
			// wrap items to show in viewport, which has fixed size and hides overflowing elements
			$('ul', gallery).wrap('<div class="imageSliderViewport"></div>');
			var viewport = $('div.imageSliderViewport', gallery);
			viewport.css({
				width: viewportDimensions.width,
				height: viewportDimensions.height
			});
			_align(viewport);
			_setupNavigation();
		}
		
		function _setupNavigation() {
			if (settings.showButtons || settings.showLinks || settings.showPageCounter) {
				var pageCount = Math.ceil( $("li", gallery).length / (settings.rowCount * settings.columnCount) );
				var navFirst = '<a class="pg_first" href="#" title="'+ settings.firstText +'">' + (settings.showButtons ? '<span></span>' : '') + (settings.showLinks ? settings.firstText : '') +'</a>';  // span is a floatable placeholder element that has navigation image as background
				var navPrev = '<a class="pg_prev" href="#" title="' + settings.prevText + '">' + (settings.showButtons ? '<span></span>' : '') + (settings.showLinks ? settings.prevText : '') + '</a>';
				var navNext = '<a class="pg_next" href="#" title="' + settings.nextText + '">' + (settings.showLinks ? settings.nextText : '') + (settings.showButtons ? '<span></span>' : '') + '</a>';
				var navLast = '<a class="pg_last" href="#" title="' + settings.lastText + '">' + (settings.showLinks ? settings.lastText : '') + (settings.showButtons ? '<span></span>' : '') + '</a>';
				var navCounter = settings.showPageCounter ? settings.pageText.replace('%1$d', '<span class="current">1</span>').replace('%2$d', '<span class="total">'+ pageCount +'</span>') : '';
				var nav = '<div class="imageSliderPaging">' + navFirst + ' ' + navPrev + ' ' + navCounter + ' ' + navNext + ' ' + navLast + '</div>';

				switch (settings.navigation) {
					case 'both':
						$(gallery).prepend(nav);
						$(gallery).append(nav);
						break;
					case 'top':
						$(gallery).prepend(nav);
						break;
					default:  // case 'bottom':
						$(gallery).append(nav);
				}

				var paging = $('.imageSliderPaging', gallery);
				paging.width(viewportDimensions.width);
				_align(paging);
			}

			if (settings.showOverlayButtons) {
				var navOverlayPrev = $('<div class="pg_prev"></div>');
				var navOverlayPrevButton = $('<div class="pg_prev" title="'+ settings.prevText +'"></div>');
				navOverlayPrevButton.css('visibility','hidden');
				navOverlayPrev.append(navOverlayPrevButton);
				var navOverlayNext = $('<div class="pg_next"></div>');
				var navOverlayNextButton = $('<div class="pg_next" title="'+ settings.nextText +'"></div>');
				navOverlayNextButton.css('visibility','hidden');
				navOverlayNext.append(navOverlayNextButton);
				switch (settings.orientation) {
					case 'vertical':
						if (itemDimensions.height < 120) {
							navOverlayPrev.addClass('pg_top_small');
							navOverlayNext.addClass('pg_bottom_small');
						} else {
							navOverlayPrev.addClass('pg_top_large');
							navOverlayNext.addClass('pg_bottom_large');
						}
						break;
					default:  // case 'horizontal':
						if (itemDimensions.width < 120) {
							navOverlayPrev.addClass('pg_left_small');
							navOverlayNext.addClass('pg_right_small');
						} else {
							navOverlayPrev.addClass('pg_left_large');
							navOverlayNext.addClass('pg_right_large');
						}
				}
				$('div.imageSliderViewport', gallery).prepend(navOverlayNext);
				$('div.imageSliderViewport', gallery).prepend(navOverlayPrev);
				navOverlayPrev.mouseenter(function () {
					navOverlayPrevButton.css('visibility','visible');
				});
				navOverlayPrev.mouseleave(function () {
					navOverlayPrevButton.css('visibility','hidden');
				});
				navOverlayNext.mouseenter(function () {
					navOverlayNextButton.css('visibility','visible');
				});
				navOverlayNext.mouseleave(function () {
					navOverlayNextButton.css('visibility','hidden');
				});
			}

			if (settings.showButtons || settings.showLinks || settings.showOverlayButtons) {
				$(".pg_first", gallery).click(function () {
					_scroll("first");
					return false;
				});
				$(".pg_prev", gallery).click(function () {
					_scroll("prev");
					return false;
				});
				$(".pg_next", gallery).click(function () {
					_scroll("next");
					return false;
				});
				$(".pg_last", gallery).click(function () {
					_scroll("last");
					return false;
				});
			}
		}

		/**
		* Execute image slider animation.
		*/
		function _scroll(dir) {
			var p = settings.rowCount * settings.columnCount;
			var n = $("li", gallery).length;  // total number of items in slider
			var t = (n%p ? n-n%p : n-p);      // greatest possible index for the first position
			switch (dir) {
				case 'first':
					sliderIndexPosition = 0; break;
				case 'prev':
					sliderIndexPosition = (sliderIndexPosition >= p) ? sliderIndexPosition - p : 0; break;
				case 'next':
					sliderIndexPosition = (sliderIndexPosition < t) ? sliderIndexPosition + p : t; break;
				case 'last':
					sliderIndexPosition = t;  break;
				 default:
					return;
			};
			
			switch (settings.orientation) {
				case 'vertical':
					var pad = sliderIndexPosition / settings.columnCount * itemDimensions.height;
					$('ul', gallery).animate(
						{ top: -pad },
						settings.duration
					);
					break;
				default:  // case 'horizontal':
					var pad = sliderIndexPosition / settings.rowCount * itemDimensions.width;
					$('ul', gallery).animate(
						{ left: -pad },
						settings.duration
					);
			}
			_updatePaging();
		}
		
		/**
		* Update which navigation links are enabled.
		*/
		function _updatePaging() {
			var p = settings.rowCount * settings.columnCount;
			var n = $("li", gallery).length;   // total number of items in slider
			var t = (n%p ? n-n%p : n-p);       // greatest possible index for the first position
			if (settings.showPageCounter) {
				$("span.current", gallery).text(Math.ceil(sliderIndexPosition / (settings.rowCount*settings.columnCount)) + 1);
			}
			if (settings.showButtons || settings.showLinks || settings.showOverlayButtons) {
				if (sliderIndexPosition > 0) {
					$(".pg_first", gallery).removeClass("imageSliderPagingDisabled");
					$(".pg_prev", gallery).removeClass("imageSliderPagingDisabled");
				} else {
					$(".pg_first", gallery).addClass("imageSliderPagingDisabled");
					$(".pg_prev", gallery).addClass("imageSliderPagingDisabled");
				}
				if (sliderIndexPosition < t) {
					$(".pg_next", gallery).removeClass("imageSliderPagingDisabled");
					$(".pg_last", gallery).removeClass("imageSliderPagingDisabled");
				} else {
					$(".pg_next", gallery).addClass("imageSliderPagingDisabled");
					$(".pg_last", gallery).addClass("imageSliderPagingDisabled");
				}
			}
		}

		_setup();
		_updatePaging();
	}
})(jQuery);
