/*
jQuery Pagination Plugin
========================

Description
-----------
When you have a a large list of items (e.g. search results or news articles), 
you can display them grouped in pages and present navigational elements to move 
from one page to another. This plugin creates these navigational elements. 


Usage
-----
Include jQuery, the pagination plugin script and the pagination.css file in your 
HTML page. In your HTML body create a container tag pair that will hold the link 
elements. Give it an id attribute (e.g. "News-Pagination"). This id will be the
selector for jQuery. It is important to select only one element because the
pagination links won't be synchronized!

Next, write a JavaScript function that has two parameters: page_index and
paging_container. This is the callback function where you react to clicks on the
pagination links. It should select a part from your content, depending on the
page id.

    function handlePaginationClick(new_page_index, pagination_container) {
        // This selects 20 elements from a content array
        for(var i=new_page_id;i<;i++) {
            $('#MyContentArea').append(content[i]);
        }
        return false;
    }

The code in this callback function requires knowledge of the jQuery DOM
manipulation functions. This is where you write your display routines.
    
After you have loaded the contents and know how many items you want to display 
overall, create the pagination like this:

	// First Parameter: number of items
	// Second Parameter: options object
	$("#News-Pagination").pagination(122, {
		items_per_page:20, 
		callback:handlePaginationClick
	});

This will create the navigation links inside the container. You will see the 
numbers 1-7, the first number is highlighted. When you click on another number, 
the highlighting changes and your callback function "handlePaginationClick" 
is called.

The plugin is highly configurable through the option parameter and all elements 
can be styled separately.


Available Options
-----------------
The following list describes what options you have for the option object:

callback
	A callback function that is called when a user clicks on a pagination link. The 
	function receives two parameters: the new page index and the pagination 
	container (a DOM element). If the callback returns false, the event 
	propagation is stopped. Default value: ``function(){return false;}``.
    This callback function is essential for the functionality of the pagination!
    It should contain code that updates your content.
    For a fast user experience you should NOT load content via AJAX in this 
    function. Instead, pre-load some content pages and switch betweem them with
    this function.
current_page
	The page that is selected when the pagination is initialized. Default: 0
items_per_page
	The number of items per page. The maximum number of pages is calculated by 
	dividing the number of items by items_per_page (rounded up, minimum 1). 
	Default: 10
link_to
	Link target of the pagination links. Normally the page selection is 
	triggered through an onclick event. If the link contains the string 
	``__id__``, it will be replaced with the page number. Default: ``#``
num_display_entries
	Maximum number of pagination links that are visible. Set to 0 to display a
	 simple "Previous/Next"-Navigation. Default: 10
next_text
	Text for the "Next"-link that increases the current page number by 1. 
	Leave blank to hide the link. Default: ``Next``
next_show_always
	If this is set to false, the "Next"-link is only shown when the page number 
	can be increased. Default: true
prev_text
	Text for the "Previous"-link that decreases the current page number by 1. 
	Leave blank to hide the link. Default: ``Previous``
prev_show_always
	If this is set to false, the "Previous"-link is only shown when the page 
	number can be decreased. Default: true
num_edge_entries
	If this number is set to 1, links to the first and the last page are always 
	shown, independent of the current position and the visibility constraints 
	set by num_display_entries. You can set it to bigger numbers to show more 
	links. Default: 0
ellipse_text
	When there is a gap between the numbers created by num_edge_entries and the 
	displayed number interval, this text will be inserted into the gap (inside a
	span tag). Can be left blank to avoid the additional tag. Default: ``...``

*/

/**
 * This jQuery plugin displays pagination links inside the selected elements.
 *
 * @author Gabriel Birke (birke *at* d-scribe *dot* de)
 * @version 1.2
 * @param {int} maxentries Number of entries to paginate
 * @param {Object} opts Several options (see README for documentation)
 * @return {Object} jQuery Object
 */
jQuery.fn.pagination = function(maxentries, opts){
	opts = jQuery.extend({
		items_per_page:10,
		num_display_entries:10,
		current_page:0,
		num_edge_entries:0,
		link_to:"#",
		prev_text:"Prev",
		next_text:"Next",
		ellipse_text:"...",
		prev_show_always:true,
		next_show_always:true,
		callback:function(){return false;}
	},opts||{});
	
	return this.each(function() {
		/**
		 * Calculate the maximum number of pages
		 */
		function numPages() {
			return Math.ceil(maxentries/opts.items_per_page);
		}
		
		/**
		 * Calculate start and end point of pagination links depending on 
		 * current_page and num_display_entries.
		 * @return {Array}
		 */
		function getInterval()  {
			var ne_half = Math.ceil(opts.num_display_entries/2);
			var np = numPages();
			var upper_limit = np-opts.num_display_entries;
			var start = current_page>ne_half?Math.max(Math.min(current_page-ne_half, upper_limit), 0):0;
			var end = current_page>ne_half?Math.min(current_page+ne_half, np):Math.min(opts.num_display_entries, np);
			return [start,end];
		}
		
		/**
		 * This is the event handling function for the pagination links. 
		 * @param {int} page_id The new page number
		 */
		function pageSelected(page_id, evt){
			current_page = page_id;
			drawLinks();
			var continuePropagation = opts.callback(page_id, panel);
			if (!continuePropagation) {
				if (evt.stopPropagation) {
					evt.stopPropagation();
				}
				else {
					evt.cancelBubble = true;
				}
			}
			return continuePropagation;
		}
		
		/**
		 * This function inserts the pagination links into the container element
		 */
		function drawLinks() {
			panel.empty();
			var interval = getInterval();
			var np = numPages();
			// This helper function returns a handler function that calls pageSelected with the right page_id
			var getClickHandler = function(page_id) {
				return function(evt){ return pageSelected(page_id,evt); }
			}
			// Helper function for generating a single link (or a span tag if it's the current page)
			var appendItem = function(page_id, appendopts){
				page_id = page_id<0?0:(page_id<np?page_id:np-1); // Normalize page id to sane value
				appendopts = jQuery.extend({text:page_id+1, classes:""}, appendopts||{});
				if(page_id == current_page){
					var lnk = jQuery("<span class='current'>"+(appendopts.text)+"</span>");
				}
				else
				{
					var lnk = jQuery("<a>"+(appendopts.text)+"</a>")
						.bind("click", getClickHandler(page_id))
						.attr('href', opts.link_to.replace(/__id__/,page_id));
						
						
				}
				if(appendopts.classes){lnk.addClass(appendopts.classes);}
				panel.append(lnk);
			}
			// Generate "Previous"-Link
			if(opts.prev_text && (current_page > 0 || opts.prev_show_always)){
				appendItem(current_page-1,{text:opts.prev_text, classes:"prev"});
			}
			// Generate starting points
			if (interval[0] > 0 && opts.num_edge_entries > 0)
			{
				var end = Math.min(opts.num_edge_entries, interval[0]);
				for(var i=0; i<end; i++) {
					appendItem(i);
				}
				if(opts.num_edge_entries < interval[0] && opts.ellipse_text)
				{
					jQuery("<span>"+opts.ellipse_text+"</span>").appendTo(panel);
				}
			}
			// Generate interval links
			for(var i=interval[0]; i<interval[1]; i++) {
				appendItem(i);
			}
			// Generate ending points
			if (interval[1] < np && opts.num_edge_entries > 0)
			{
				if(np-opts.num_edge_entries > interval[1]&& opts.ellipse_text)
				{
					jQuery("<span>"+opts.ellipse_text+"</span>").appendTo(panel);
				}
				var begin = Math.max(np-opts.num_edge_entries, interval[1]);
				for(var i=begin; i<np; i++) {
					appendItem(i);
				}
				
			}
			// Generate "Next"-Link
			if(opts.next_text && (current_page < np-1 || opts.next_show_always)){
				appendItem(current_page+1,{text:opts.next_text, classes:"next"});
			}
		}
		
		// Extract current_page from options
		var current_page = opts.current_page;
		// Create a sane value for maxentries and items_per_page
		maxentries = (!maxentries || maxentries < 0)?1:maxentries;
		opts.items_per_page = (!opts.items_per_page || opts.items_per_page < 0)?1:opts.items_per_page;
		// Store DOM element for easy access from all inner functions
		var panel = jQuery(this);
		// Attach control functions to the DOM element 
		this.selectPage = function(page_id){ pageSelected(page_id);}
		this.prevPage = function(){ 
			if (current_page > 0) {
				pageSelected(current_page - 1);
				return true;
			}
			else {
				return false;
			}
		}
		this.nextPage = function(){ 
			if(current_page < numPages()-1) {
				pageSelected(current_page+1);
				return true;
			}
			else {
				return false;
			}
		}
		// When all initialisation is done, draw the links
		drawLinks();
        // call callback function
        opts.callback(current_page, this);
	});
}


