(function($){

	$.fn.tablePagination = function(settings) {
		var defaults = {
			rowsPerPage: 10,
			currPage: 1,
			optionsForRows: [5,10,25,50,100],
			ignoreRows: []
		};
		settings = $.extend(defaults, settings);

		return this.each(function(index) {
			var table = $(this)[0];
			var divId, divSel, rowsPerPageSel, firstPageSel, prevPageSel, nextPageSel, lastPageSel, anyPageSel, tableSel;

			// Get a unique ID for this paginator
			if( table.id )
				divId = 'table_pagination_'+table.id;
			else
				divId = 'table_pagination_tbl'+index;

			// Get unique selectors for all components of this paginator
			divSel = '#'+divId;
			rowsPerPageSel = divSel+' .table_pagination_rowsPerPage';
			firstPageSel = divSel+' .table_pagination_firstPage';
			prevPageSel = divSel+' .table_pagination_prevPage';
			nextPageSel = divSel+' .table_pagination_nextPage';
			lastPageSel = divSel+' .table_pagination_lastPage';
			anyPageSel = divSel+' .table_pagination_pageNum';
			pageNumsSel = divSel+' .table_pagination_pageNums';
			paginatorSel = divSel+' .table_pagination_paginator';

			// Get all rows in this table that we're going to paginate
			var possibleTableRows = $.makeArray($('tbody tr', table));
			var tableRows = $.grep(possibleTableRows, function(value, index) {
				return ($.inArray(value, defaults.ignoreRows) == -1);
			}, false)

			// Calculate total number of rows/pages
			var numRows = tableRows.length
			var totalPages = Math.ceil( numRows / defaults.rowsPerPage );

			// Make sure our "rows per page" dropdown includes the current rowsPerPage
			var currPage = (defaults.currPage > totalPages) ? 1 : defaults.currPage;
			if( $.inArray(defaults.rowsPerPage, defaults.optionsForRows) == -1 )
				defaults.optionsForRows.push(defaults.rowsPerPage);

			// Show one page worth of results (pageNum starts at 1)
			function selectPage( pageNum ) {
				pageNum = parseInt( pageNum );
				//alert( 'selectPage( '+pageNum+' of totalPages '+totalPages+' )' );
				if( pageNum <= 0 || pageNum > totalPages )
					return;
				currPage = pageNum;

				// Show just the table rows for this page
				var startIndex = (pageNum - 1) * defaults.rowsPerPage;
				var endIndex = (startIndex + defaults.rowsPerPage - 1);
				$(tableRows).show();
				for( var i=0; i < tableRows.length; i++ ) {
					if( i < startIndex || i > endIndex )
						$(tableRows[i]).hide()
				}

				// Set this page number button as active
				if( pageNum == 1 ) {
					$(firstPageSel).addClass('disabled');
					$(prevPageSel).addClass('disabled');
				} else {
					$(firstPageSel).removeClass('disabled');
					$(prevPageSel).removeClass('disabled');
				}
				if( pageNum == totalPages ) {
					$(nextPageSel).addClass('disabled');
					$(lastPageSel).addClass('disabled');
				} else {
					$(nextPageSel).removeClass('disabled');
					$(lastPageSel).removeClass('disabled');
				}
				$(divSel+' .table_pagination_pageNum').removeClass('selected');
				$(divSel+' #'+divId+'_'+pageNum).addClass('selected');
			}

			// Reset number of rows per page, and go back to first page
			function setRowsPerPage( rowsPerPage ) {
				// Recalculate total number of pages
				defaults.rowsPerPage = rowsPerPage;
				totalPages = Math.ceil( numRows / rowsPerPage );

				// Write out new page number buttons
				var html = '';
				for( var i = 1; i <= totalPages; i++ )
					html += '<a href="#" id="'+divId+'_'+i+'" class="table_pagination_pageNum">'+i+'</a>';
				$(pageNumsSel).html( html );

				// Only 1 page? Hide paginator
				if( totalPages == 1 )
					$(paginatorSel).hide();
				else
					$(paginatorSel).show();
			}

			function createPaginationElements() {
				var htmlBuffer = [];
				htmlBuffer.push('<div id="'+divId+'" class="table_pagination">');
				htmlBuffer.push('<span class="table_pagination_perPage">');
				htmlBuffer.push('<select class="table_pagination_rowsPerPage">');
				for( var i in defaults.optionsForRows )
					htmlBuffer.push('<option value="'+defaults.optionsForRows[i]+'"'+(defaults.optionsForRows[i]==defaults.rowsPerPage?' selected="selected"':'')+'>'+defaults.optionsForRows[i]+'</option>');
				htmlBuffer.push('</select>');
				htmlBuffer.push('per page');
				htmlBuffer.push('</span>');
				htmlBuffer.push('<span class="table_pagination_paginator">');
				htmlBuffer.push('<a href="#" class="table_pagination_firstPage">First</a>');
				htmlBuffer.push('<a href="#" class="table_pagination_prevPage">Prev</a>');
				htmlBuffer.push('<span class="table_pagination_pageNums">');
				for( var i = 1; i <= totalPages; i++ )
					htmlBuffer.push('<a href="#" id="'+divId+'_'+i+'" class="table_pagination_pageNum">'+i+'</a>');
				htmlBuffer.push('</span>');
				htmlBuffer.push('<a href="#" class="table_pagination_nextPage">Next</a>');
				htmlBuffer.push('<a href="#" class="table_pagination_lastPage">Last</a>');
				htmlBuffer.push('</span>');
				htmlBuffer.push('</div>');
				return htmlBuffer.join('').toString();
			}

			// Create pagination div, if it's not already created
			if( $(divSel).length == 0 )
				$(this).before( createPaginationElements() );

			// Store current paginator status
			setRowsPerPage( defaults.rowsPerPage );
			selectPage( defaults.currPage );

			// Click handlers for page buttons
			$(firstPageSel).bind('click', function (e) {
				selectPage(1);
				return false;
			});

			$(prevPageSel).bind('click', function (e) {
				selectPage(currPage - 1);
				return false;
			});

			$(nextPageSel).bind('click', function (e) {
				selectPage(currPage + 1);
				return false;
			});

			$(lastPageSel).bind('click', function (e) {
				selectPage(totalPages);
				return false;
			});

			$(anyPageSel).bind('click', function (e) {
				selectPage( this.id.substr( divId.length+1 ) );
				return false;
			});

			$(rowsPerPageSel).bind('change', function (e) {
				setRowsPerPage( parseInt(this.value, 10) );
				selectPage( 1 );
				return false
			});

		})
	};
})(jQuery);

