/*
	Code based on jquery.pager.js by Rik Lomas.
	http://rikrikrik.com/jquery/pager/
	
	created/copyright 2007 by ahura mazda/minel pather
*/
$.fn.pager = function(selector, options)
{	
	
	// Setting class
	var settings =
	{		
		navigationClass: 'pagingNavigationMenu',
		navigationAttachPositions: ['append'],
		currentPageClass: 'pagingCurrentPage',
		pagingQuickLinksClass: 'pagingQuickLinks',
		pageIndexClass: 'pagingPageIndex',
		pagingLinksContainerClass: 'pagingLinksContainer',
		previousPageText: '&#139;',
		previousPageClass: 'previousPageClass',
		nextPageText: '&#155;',
		nextPageClass: 'nextPageClass',
		previousPageGroupText: '&laquo;',
		nextPageGroupText: '&raquo;',
		linkWrap: null,
		height: null,
		rowsPerPage: 10,
		pagesPerMenu: 5,
		customMessage: null,
		customMessageClass: "pagingCustomMessage"
	}
	
	if (options)
	{
		$.extend(settings, options);
	}
	
	
	//#region public events
		
	this.onChange =
		function()
		{
			//Intentionally left empty
		};
	
	//#endregion public events
		
	return this.each(
		function()
		{
			var _instanceJQ = $(this);
			// Zero-Index based
			var selectorTotal;
			// One-Index based
			var pageTotal;
			// Zero-Index based		
			var currentPageIndex = 0;
			
			//One-Index based
			var currentStartPageIndex = 0;
			
			//One-Index based
			var currentEndPageIndex = 0;
			
			var navigationContainerClassJQuery = '.' + settings.navigationClass
			
			// Cached JQueries objects
			
			// A JQuery array of each Row element
			var rowItemsJQuery = null;
			
			// A JQuery arrauy of each Custom Message container
			var navigationCustomMessageJQuery = null;
			
			function initialiseCache()
			{
				rowItemsJQuery = $(selector, _instanceJQ).not(navigationContainerClassJQuery);
			}
			
			///<summary>
			///	Cache the customMessage container once they have been created and attached.
			/// Updated when the page group (range) is changed.
			///</summary>
			function cacheCustomMessageJQuery()
			{
				navigationCustomMessageJQuery = $('.' + settings.customMessageClass, _instanceJQ);
			}
		
			function initialise()
			{
				// Get the number of rows (items) to paginate
				selectorTotal = $(selector, _instanceJQ).size();
				
				// There can be only 1 page if the number of rows per page
				// is greater than the available row items,
				if (settings.rowsPerPage <= selectorTotal)
				{
					// Get the integer division value.
					// EG: (54 / 10) = 5
					pageTotal = Math.ceil(selectorTotal / settings.rowsPerPage);
					
				}
				else
				{
					pageTotal = 1;
				}
				
				initialiseCache();
				
				/*
				if (settings.height == null)
				{			
					settings.height = getHighest();
				}
				*/
				
				if (selectorTotal > 1)
				{
					makeNavigation();
					showRows();
					highlightPageIndex();
				}			
				
				sizePanel();
				
				if(settings.linkWrap != null)
				{
					linkWrap();
				}
			}
			
			///<summary>
			///	The custom message setting allows the developer to place a dynamic message with the navigation menu.
			///	The message uses tokens which are replaced with current values.
			///	The tokens are:
			///		%pt	:	page total
			///		%p	:	current page
			///		#rt	:	row total
			///		#rs	:	row start
			///		#re	:	row end
			///</summary>
			function renderCustomMessage(containerIsCreated)
			{
				var renderedCustomMessage = '';
				
				if (settings.customMessage != null)
				{
					renderedCustomMessage = settings.customMessage.replace("%pt", pageTotal);
					renderedCustomMessage = renderedCustomMessage.replace("%p", (currentPageIndex + 1));
					renderedCustomMessage = renderedCustomMessage.replace("%rt", selectorTotal);
					
					var rowStart = ((currentPageIndex * settings.rowsPerPage) + 1);
					var rowEnd = ((rowStart - 1) + settings.rowsPerPage);
					if (rowEnd > selectorTotal)
					{
						rowEnd = selectorTotal;
					}
					
					renderedCustomMessage = renderedCustomMessage.replace("%rs", rowStart);
					renderedCustomMessage = renderedCustomMessage.replace("%re", rowEnd);
					
					if (containerIsCreated)
					{
						renderedCustomMessage = "<div class='" + settings.customMessageClass + "'>" + renderedCustomMessage + "</div>";
					}
				}
				
				return renderedCustomMessage;
			}
			
			///<summary>
			///	Update the internals of the customMessage and updates the CustomMessage container.
			///	This is used when the CustomMessage already exists on the page
			///</summary>
			function updateCustomMessage()
			{
				var renderedCustomMessage = renderCustomMessage(false);
				navigationCustomMessageJQuery.each(
					function()
					{
						$(this).html(renderedCustomMessage);
					});
			}
			
			function removeExistingPagingNavigationMenus()
			{
				var pagingMenusJQuery = $('.' + settings.navigationClass, _instanceJQ);
				pagingMenusJQuery.each(
					function()
					{
						$(this).remove();
					});
			}
			
			function attachPagingNavigationMenu(navigationHTML)
			{
				var navigationAttachPositions = settings.navigationAttachPositions;
				if (settings.navigationAttachPositions.length > 0)
				{
					for (var attachLocationIndex in navigationAttachPositions)
					{
						// The position to place the dynamically generated navigation menu
						switch (navigationAttachPositions[attachLocationIndex])
						{		
							case 'before':
								_instanceJQ.before(navigationHTML);
								break;
								
							case 'after':		
								_instanceJQ.after(navigationHTML);
								break;
								
							case 'prepend':
								_instanceJQ.prepend(navigationHTML);
								break;
								
							default:
								_instanceJQ.append(navigationHTML);
								break;
						}
					}
				}
			}
		
			function makeNavigation()
			{	
				var navigationHTML = '';
				
				removeExistingPagingNavigationMenus();
				
				// Navigation Menu does not exist, hence the first line of HTML creates a new Navigation Menu
				navigationHTML = '<div class="' + settings.navigationClass + '">';
				
				// Get the Integer component of the division
				// Note: Mixture of Zero and One-Based indexes which works perfectly for this equation
				var startPageGroupIndex = Math.floor(currentPageIndex / settings.pagesPerMenu);
				startPageGroupIndex *= settings.pagesPerMenu;
				
				currentStartPageIndex = (startPageGroupIndex + 1);
				currentEndPageIndex = (startPageGroupIndex + settings.pagesPerMenu);
				if (currentEndPageIndex > pageTotal)
				{
					currentEndPageIndex = pageTotal;
				}
				
				// Renders the custom Message if it has been set
				navigationHTML += renderCustomMessage(true);
				
				navigationHTML += "<div class='" + settings.pagingLinksContainerClass + "'>";
				
				//TODO: Add this link and functionality later
				//navigationHTML += '<a href="#" rel="previousPageGroup" class="' + settings.pagingQuickLinksClass + '">' + settings.previousPageGroupText + '</a>';
				navigationHTML += '<ul class="' + settings.previousPageClass + '"><li><a href="#" rel="previousPage">' + settings.previousPageText + '</a></li></ul>';
				var currentPageLinkText = '';
				
				navigationHTML+= '<ul class="' + settings.pageIndexClass + '" >';
				for (var pageIndex = currentStartPageIndex; pageIndex <= currentEndPageIndex; pageIndex++)
				{
					if (pageIndex === 1)
					{
						navigationHTML += '<li class="pagination-first"><a href="#" rel="' + pageIndex + '">' + pageIndex + "</a></li>";
					}
					else
					{
						navigationHTML += '<li><a href="#" rel="' + pageIndex + '">' + pageIndex + "</a></li>";
					}
				}
				navigationHTML+= '</ul>';
				navigationHTML += '<ul class="' + settings.nextPageClass + '"><li><a href="#" rel="nextPage">' + settings.nextPageText + '</a></li></ul>';
				//TODO: Add this link and functionality later
				//navigationHTML += '<a href="#" rel="nextPageGroup" class="' + settings.pagingQuickLinksClass + '">' + settings.nextPageGroupText + '</a>';
				
				// Closing tags for the Div container that surrounds all the links
				//TODO: <div class="clear"></div> is hardcoded. find alternative method
				navigationHTML += '</div><div class="clear"></div>';
				
				// If the Navigation Menu did not exist, add the closing tags to the creation of the new Navigation Menu
				//TODO: <div class="clear"></div> is hardcoded. find alternative method
				navigationHTML += '</div><div class="clear"></div>';
				
				attachPagingNavigationMenu(navigationHTML);
				
				styleCurrentPageLink();
				
				cacheCustomMessageJQuery();
			}
			
			function showRows()
			{
				// Hide all the displayed rows
				rowItemsJQuery.filter(":visible").hide();
				
				var startRowIndex = (currentPageIndex * settings.rowsPerPage);
				var endRowIndex = (startRowIndex + settings.rowsPerPage);
				if (endRowIndex > selectorTotal)
				{
					endRowIndex = selectorTotal;
				}
				
				for (var rowIndex = startRowIndex; rowIndex < endRowIndex; rowIndex++)
				{
					// Find and unhide the rows for the current page
					$(rowItemsJQuery.get(rowIndex)).show();
				}
			}		
			
			function highlightPageIndex()
			{
				// Find the links with the Current Page Class assigned and remove the class assignment
				var navigationQuery = 'a.' + settings.currentPageClass;
				var navigationLinksJQuery = $(navigationQuery, navigationContainerClassJQuery);
				navigationLinksJQuery.removeClass(settings.currentPageClass);
				
				// Find the new Current Page links and assign the Current Page Class to them
				var currentLinkQuery = "." + settings.pagingLinksContainerClass + "[rel=" + (currentPageIndex + 1) + "]";
				var currentLinksJQuery = $(currentLinkQuery, _instanceJQ);
				currentLinksJQuery.each(
					function()
					{
						$(this).addClass(settings.currentPageClass);
					});
			}
			
			///<summary>
			///		Size all Rows to be the same height
			///</summary>
			function sizePanel()
			{
				//var selectorRowsJQuery = _instanceJQ.find(selector).not(navigationContainerClassJQuery);
				var selectorRowsJQuery = $(selector, _instanceJQ).not(navigationContainerClassJQuery);
				
				if($.browser.msie)
				{
					selectorRowsJQuery.css(
						{
							height: settings.height
						}
					);	
				}
				else
				{
					selectorRowsJQuery.css(
						{
							minHeight: settings.height
						});
				}
			}

			///<summary>
			///	Get the height of the tallest element to be paginated
			///</summary>
			function getHighest()
			{
				var highest = 0;
				//_instanceJQ.find(selector).not(navigationContainerClassJQuery).each
				$(selector, _instanceJQ).not(navigationContainerClassJQuery).each
					(
						function()
						{
							if (this.offsetHeight > highest)
							{
								highest = this.offsetHeight;
							}
						}
					);
					
				highest = highest + "px";
				return highest;
			}
						
			function linkWrap()
			{
				//_instanceJQ.find(navigationContainerClassJQuery).find("a").wrap(settings.linkWrap);
				$(navigationContainerClassJQuery + " a", _instanceJQ).wrap(settings.linkWrap);
			}
			
			function bindPageLinkEvents()
			{
				// Attach logic to pagination menu clicking
				$("a", navigationContainerClassJQuery).click(
					function(clickEvent)
					{
						clickEvent.preventDefault();
						PageLink_onClick($(this));
					});
			}

			// Remove previous selected link style and apply to current page link			
			function styleCurrentPageLink()
			{
				//var containerJQ = $(this).find(navigationContainerClassJQuery);
				var containerJQ = $(navigationContainerClassJQuery, _instanceJQ);
				containerJQ.find("a.selected").removeClass("selected");
				containerJQ.find("a[rel='" + (currentPageIndex + 1) + "']").addClass("selected");
			}
			
			function PageLink_onClick(pageLinkJQuery)
			{
				if (pageLinkJQuery.attr('rel') == 'nextPage')
				{
					if ((currentPageIndex + 1) < pageTotal)
					{
						currentPageIndex++;
					}
				}
				else if (pageLinkJQuery.attr('rel') == 'previousPage')
				{ 
					if (currentPageIndex > 0)
					{	
						currentPageIndex--;
					}
				}
				else
				{		
					var pageIndex = pageLinkJQuery.attr('rel');	
					currentPageIndex = (pageIndex - 1);
				}
				
				// Check if the the page group (page range) requires refreshing
				var currentPageOneBasedIndex = (currentPageIndex + 1);
				if (
						(currentPageOneBasedIndex < currentStartPageIndex)
						||
						(currentPageOneBasedIndex > currentEndPageIndex)
						)
				{
					makeNavigation();
					bindPageLinkEvents();
				}
				else
				{
					updateCustomMessage();
				}

				styleCurrentPageLink();
				
				showRows();
				highlightPageIndex();
				
				if (_instanceJQ.pager.onChange != null)
				{
					_instanceJQ.pager.onChange();
				}
				
				return false;
			}
			
			// Setup and create Navigation menu
			initialise();
			bindPageLinkEvents();
		});	
}