var PageableDataset = function(options) {
  this.options = options; // TBD: merge with default options
  this.pages = [];
  this.pagelinks = [];
  this.page = 1;
  this.oldpage = 1;
  this.dataset = jQuery(this.options.dataset);
  this.pagesize = this.options.pagesize;
  this.resultcounterTemplate = this.options.resultcounter;
  this.resultcounterCSSClass = this.options.resultcounterCSSClass;
  this.scrollTo = (this.options.scrollToOnRefresh) ? jQuery(this.options.scrollToOnRefresh) : "";
  this.callback = this.options.callback || "";
  this.datacount = this.dataset.size();
  this.pagecount = Math.ceil(this.datacount / this.pagesize);
	if(this.pagecount > 1) {
		this.pagenav = jQuery("<p>").appendTo(this.options.navcontainer).addClass(this.options.navCSSClass);
	}
  this.createPages();
};

PageableDataset.prototype = {
  createPages: function() {
    // divide the dataset into pages, caching each pageset as a jquery object in the pages[] array
    var me = this, page = 1;
  	this.dataset.each(function(i) {
  		jQuery(this).addClass("page" + page);
  		if((i + 1) % me.pagesize === 0) {
  			me.pages[page] = me.dataset.filter(".page" + page);
  			page += 1;
  		}
  	});
  	if(this.dataset.size() % this.pagesize) {
      // load the final, partial page into the pages[] array
      this.pages[page] = this.dataset.filter(".page" + page);
	  }

      if(this.pagenav) {
      // insert previous page link
      this.previouslink = jQuery('<a href="#prev" title="View previous page">&lt;</a>').appendTo(this.pagenav).addClass("disabled").bind("click", function() {
        if(me.page == 1) {
          return false;
        }
        me.page -= 1;
        me.switchPage();
        return false;
      });
  
      // insert direct page links
      for(var i = 1; i <= this.pagecount; i++) {
        this.pagelinks[i] = jQuery('<a href="#' + i + '" title="View page ' + i + '">' + i + '</a>').appendTo(this.pagenav).bind("click", {page: i}, function(event) {
          me.page = event.data.page;
          me.switchPage();
          return false;
        });
        if(i < this.pagecount) {
          this.pagenav.append("<span>|</span>");
        }
      }
  
      // insert next page link
      this.nextlink = jQuery('<a href="#next" title="View next page">&gt;</a>').appendTo(this.pagenav).bind("click", function() {
        if(me.page == me.pagecount) {
          return false;
        }
        me.page += 1;
        me.switchPage();
        return false;
      });
      
      if(this.resultcounterTemplate) {
        this.resultcounterTemplate = this.resultcounterTemplate.replace(/%1/, "<span id=\"pds-first\">" + this.page + "</span>");
        this.resultcounterTemplate = this.resultcounterTemplate.replace(/%2/, "<span id=\"pds-last\">" + (this.pagesize * this.page) + "</span>");
        this.resultcounterTemplate = this.resultcounterTemplate.replace(/%3/, "<span>" + this.datacount + "</span>");
        this.resultcounter = jQuery("<span>" + this.resultcounterTemplate + "</span>").insertAfter(this.nextlink).addClass(this.resultcounterCSSClass);
        this.resultcountervalues = [];
        this.resultcountervalues.push(this.resultcounter.find("#pds-first"));
        this.resultcountervalues.push(this.resultcounter.find("#pds-last"));
      }
      
      // show paging nav
      this.pagenav.show();
    }
    
    // reveal the pagination
    this.switchPage();
  },
  
  showAll: function() {
    if(this.pagenav) {
      this.pagenav.hide();
    }
    this.dataset.show();
  },
  
  showCurrent: function() {
    if(this.pagenav) {
      this.pagenav.show();
    }
    this.switchPage();
  },
  
  switchPage: function() {
    this.dataset.hide();
    this.pages[this.page].show();
    
    // scroll to top of results on page change
    if(this.scrollTo && this.oldpage != this.page) {
      var offset = this.scrollTo.offset();
      if(offset.top < jQuery().scrollTop()) {
        window.scrollTo(0, offset.top);
      }
    }
    
    if(this.pagenav) {
      // highlight current page in nav
      this.pagelinks[this.oldpage].removeClass("current");
      this.pagelinks[this.page].addClass("current");
      this.oldpage = this.page;
      
      // update result counter
      if(this.resultcounter) {
        var first = (this.page - 1) * this.pagesize + 1;
        var last = (this.pagesize * this.page > this.datacount) ? this.datacount : this.pagesize * this.page;
        this.resultcountervalues[0].html(first);
        this.resultcountervalues[1].html(last);
      }
      
      // show/hide previous link
      if(this.page == 1) {
        this.previouslink.addClass("disabled");
      } else {
        this.previouslink.removeClass("disabled");
      }
      
      // show/hide next link
      if(this.page == this.pagecount) {
        this.nextlink.addClass("disabled");
      } else {
        this.nextlink.removeClass("disabled");
      }
    }
    
    if(this.callback) {
      this.callback();
    }
  }
};