/**
 * Provides front-end pagination for already rendered content.  
 * 
 * Author : vasile.orza
 * 
 *
 * Usage example: 
 * 	$("#container").paginate({
 * 		pageSize: 5,
 * 		linkCount: 2
 * 	});
 * 
 * 	<div id="container">
 *  	<div>1</div>
 *  	<div>2</div>
 *  	<div>3</div>
 *  	<div>4</div>
 *  	<div>5</div>
 *  	<div>6</div>
 *  	<div>7</div>
 * 	</div>
 * 
 */
(function($){
	var defaults = {
		pageSize : 5,
		linkCount : 2,
    topNav   : false
	};

	$.fn.paginate = function(userOptions) {
		var options = $.extend({}, defaults, userOptions);

		return this.each(function() {
			/** Compute the number of pages */
			var $pageContainer = $(this);
			if (options.pageSize < 0) {
				// if pageSize is negative display all items
				options.pageSize = $pageContainer.children().size();
			}

        	var pageCount = Math.ceil($pageContainer.children().size() / options.pageSize);
        	if (pageCount <= 1) {
        		// clean any pagination generated content, if no paging is required
                $pageContainer.next("div:has(.pagination)").remove().end()
                              .prev("div:has(.pagination)").remove().end()
                              .children().show();
        		return;
        	}

        	/** Split container items into pages, adding a custom 'page' CSS class */
        	$pageContainer.children().hide().each(function(itemIndex) {
        		// remove any CSS class added by previously executed paging logic
        		this.className = this.className.replace(/\bpage\d+\b/g, '');

        		// add page index information
        		var pageIndex = Math.ceil((itemIndex + 1) / options.pageSize);
        		$(this).addClass("page" + pageIndex);
        	});

        	/** Build & populate nav list wrapper & add prev/next links */
        	var $navList = $("<ul>").addClass("pagination");
        	for (index=1; index<=pageCount; index++) {
        		$("<li>").html(index).addClass("nav").appendTo($navList);
        	}

        	$("<li>").addClass("pagingPrevious").prependTo($navList);
        	$("<li>").addClass("pagingFirst").prependTo($navList);
        	$("<li>").addClass("pagingNext").appendTo($navList);
        	$("<li>").addClass("pagingLast").appendTo($navList);

        	// remove any old pagination markup
        	$pageContainer.prev("div:has(.pagination)").remove().end()
        				  .next("div:has(.pagination)").remove();

        	// add top pagination if required
        	var $navListTop = $navList.clone();
            if (options.topNav) {
                $navListTop.insertBefore($pageContainer)
                                 .wrap("<div>").addClass("navTop");
            }

            // show first page by default, added nav list content to page
        	$navList.insertAfter($pageContainer)
    				 .wrap("<div>");

    		$.merge($navList, $navListTop).delegate(".nav", "click", function() {
    			// refresh visible page entries
    			var $this = $(this);
                var $navTop = $navListTop.children().eq($this.index());
                var $navBottom = $navList.children().eq($this.index());

    			var pageIndex = $this.index() - 1;
    			$pageContainer.children().hide()
    									 .filter(".page" + pageIndex).show();

                // update visible nav links
                $.merge($navTop, $navBottom).each( function() {
                    var $this = $(this);
                    $this.siblings(".nav").addClass("hidden");
                    
                    if (pageIndex + options.linkCount > pageCount) {
                    	// show the last N nav links
                		var maxCount = (2 * options.linkCount) + 1;
                        $this.siblings(".pagingNext").prevAll(":lt(" + maxCount + ")").removeClass("hidden");

                    } else if (pageIndex - options.linkCount <= 0) {
                    	// show the first N nav links
                    	var maxCount = (2 * options.linkCount) + 1;
                        $this.siblings(".pagingPrevious").nextAll(":lt(" + maxCount + ")").removeClass("hidden");

                    } else {
                    	// show an equal number of nav links to the left and right of the current page link
                        $this.prevAll(":lt(" + options.linkCount + ")").removeClass("hidden").end()
                             .nextAll(":lt(" + options.linkCount + ")").removeClass("hidden");
                    }

                    // move 'current/last' classes
                    $this.parent().children(".nav").removeClass("last")
                         						   .removeClass("current")
                         						   .filter(":visible:last").addClass("last")
                         						   						   .end()
                         						   .end()
         						  .end()
					     .removeClass("hidden")
                    	 .addClass("current")
         				 .siblings(".pagingFirst, .pagingNext, .pagingPrevious, .pagingLast").trigger("showOrHide");
                });

    		}).delegate(".pagingFirst", "click", function() {
    			// 'previous' button behavior
    			$(this).siblings(".nav:first").click();

    		}).delegate(".pagingPrevious", "click", function() {
    			// 'previous' button behavior
    			$(this).siblings(".current").prev(".nav").click();

        	}).delegate(".pagingNext", "click", function() {
        		// 'next' button behavior
        		$(this).siblings(".current").next(".nav").click();

        	}).delegate(".pagingLast", "click", function() {
    			// 'previous' button behavior
    			$(this).siblings(".nav:last").click();

    		}).delegate(".pagingFirst, .pagingPrevious", "showOrHide", function() {
    			// refresh visibility for the 'previous' button
    			var $this = $(this);
    			var isDisabled = $this.nextAll(".nav:first").is(".current");
    			$this.toggleClass("disabled", isDisabled);

    		}).delegate(".pagingLast, .pagingNext", "showOrHide", function() {
    			// refresh visibility for the 'next' button
    			var $this = $(this);
    			var isDisabled = $this.prevAll(".nav:first").is(".current");
    			$this.toggleClass("disabled", isDisabled);
			});

			$navList.children(".nav:first").click();
		});
	};
}) (jQuery)

