/**
 * jQuery Ajax Paginator
 * 
 * @package Wilson Cooke
 * @subpackage Compose Commerce
 * @copyright 2011 Wilson Cooke
 * 
 * This plugin provies the functionality to handle an ajax pagination through hashed values in the address bar, the
 * plugin also monitors the adress bar for changes to the hashed value in then loads the associated page.
 * 
 * @usage
 * $(document).ready(function() {
 *   $().ajaxPaginator({
 *     target : 'a.ajax-link',
 *     base_url : '/search/filter',
 *     beforeClick : function() {},
 *     onSuccess : function(data) {}
 *   }
 * });
 * 
 */
$.fn.ajaxPaginator = function (options) {
    var defaults = {
        load_hash : true,
        target : 'a.ajax-link',
        base_url : '/',
        delay : 500,
        additional_params : '&method=ajax',
        beforeClick : function() {},
        appendUrl : function() { return null; },
        onSuccess : function() {}
    }
    // Extend our default options with those provided
    var opts = $.extend({}, defaults, options);
    
    function Ajaxpaginator($obj, $opt) {
        
        // Store our options
        this.options = $opt;

        /**
         * Initialise our plugin, set the last hash to false, check if we need to load a hashed page and sets
         * up our bindings for our click handlers
         */
        this.init = function() {
            this.lastHash = false;
            this.firstRequest = true;
            
            // Check hash
            if (this.options.load_hash) {
                this.isHashed();
            }
            
            // Bind our click event
            this.bindEvent();
        };
        
        /**
         * isHashed - Checks if we have a hash and loads this page, allows the ability to bookmark a paginated
         * link via the hashed value
         */
        this.isHashed = function() {
            // Load our hash
            this.loadHash(this.stripHash());
            
            // Sets an interval to check for changes to the hashed value
            var instance = this;
            setInterval(function () { instance.hashPage(); }, this.options.delay);
        };
        
        /**
         * hashPage - Periodical check for a new hash value in the url which allows us to simulate browser
         * back / forward functionality
         */
        this.hashPage = function() {
            var hash = this.stripHash();
            if(this.lastHash && this.lastHash!=hash) {
                this.loadHash(hash);
            }
        };
        
        /**
         * loadHash - Loads the requested ajax page via the current hashed value
         * 
         * @param hash
         */
        this.loadHash = function (hash) {
            if (hash) {
                this.loadPage(this.options.base_url + '&' + hash);
            } else {
                if (!this.firstRequest) {
                    this.loadPage(this.options.base_url + '&page=1');
                }
            }
        };

        /**
         * loadPage - Loads a page from a url, extracts the hash from the url, If the hash
         * is different from our current hash the new page is loaded
         * 
         * @param url
         */
        this.loadPage = function(url) {
            var dataArray;
            var tmpUrl = (typeof(url) == 'object' ? url.href : url);
            
            // Split our url
            dataArray = this.splitURL(tmpUrl);
            
            // Extract the page from our url and replace any left over ampersands
            hash = dataArray[1];
            if (this.getParam(tmpUrl, 'page')) {
                //hash = hash.replace('&', '');
                hash = 'page=' + this.getParam(tmpUrl, 'page');
            }

            // If our hash is the same, perform no action
            if (this.lastHash && this.lastHash == hash) {
                return false;
            }
            
            // Call our 'beforeClick' callback, allows us to display pre-loaders etc
            this.options.beforeClick();
            
            // Stores our 'last hash'
            this.lastHash = window.location.hash = hash;
            this.firstRequest = false;
            
            // Load the page
            this.getData(tmpUrl);
        };

        /**
         * Performs the ajax request to load the page, and then rebinds the events from the resulting listing
         * 
         * @param url
         */
        this.getData = function(url) {
            var instance = this;
            $.ajax({
                url: url + instance.options.additional_params + instance.options.appendUrl(),
                success: function(data) {
                    if (typeof instance.options.onSuccess == 'function') {
                        instance.options.onSuccess(data);
                        instance.bindEvent();
                    }
                }
            });
        };

        /**
         * bindEvent - Binds our target links click handlers and loads the page on click event
         */
        this.bindEvent = function() {
            var instance = this;
            jQuery(instance.options.target).unbind('click');
            jQuery(instance.options.target).bind('click', function(e) {
                e.preventDefault();
                instance.loadPage($(this).attr('href'));
            });
        };
        
        /* Helpers */
        this.splitURL = function(o) {
            return o.split('?');
        };
        this.stripHash = function() {
            return window.location.hash.replace('#','');
        };
        this.getParam = function(url, name) {
            name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
            var regexS = "[\\?&]"+name+"=([^&#]*)";
            var regex = new RegExp( regexS );
            var results = regex.exec( url );
            if( results == null )
                return "";
            else
                return results[1];
            }
        };

    // For every trigger passed bind our events
    var instance = new Ajaxpaginator($(this), opts);
    instance.init();
};
