
/*===============================================================================
	Pagination.js
	John Larson
	2/27/08
	
	Component for generating pagination.  Also optionally allows history
	management of page clicks for AJAX/JS actions on clicking page numbers.
	
	Example:
	<span class="pageScrollLinks"></span>
	 ...
	<span class="pageScrollLinks"></span>
	
	new Pagination($$('.pageScrollLinks'), loadPageFunction, 14, {windowSize: 10});
	
	would imply a pagination of 14 pages where 10 links will show at most.
	
	Dependencies:
		HistoryManager.js
	
	To Do:
		- Implement includeFirstLast functionality
	
===============================================================================*/


var Pagination = new Class({
	
	options: {
		manageHistory:			true,
		pageLinksSpanClass:		'pageLinks',
		pageLinkCurrentClass:	'pageLink-current',
		pageLinkClass:			'pageLink',
		manageHistory:			true,
		currentPage:			1,
		includePrevNext:		true,
		prevText:				'<',
		nextText:				'>',
		includeFirstLast:		false,
		firstText:				'«',
		lastText:				'»',
		windowSize:				10,
		windowLookBehind:		3,
		skipIfOnePage:			true,
		prefix:					'Page: ',
		suffix:					'',
		separator:				' '
	},
	
	initialize: function(pagingDivs, clickAction, totalPages, options){
		
		if($type(pagingDivs) == 'string')
			pagingDivs = $(pagingDivs);
		
		if(!$$(pagingDivs).length)
			throw('No paging divs passed to Pagination contructor (' + pagingDivs + ')');
		
		if ($type(clickAction) != 'function')
			throw new Error('Non-function passed to click action.');
		
		this.pagingDivs = $$(pagingDivs);
		
	//	dbug.log(this.pagingDivs);
		this.clickAction = clickAction;
		
		Pagination.instanceCount++;
		
		this.setOptions(options);
		
		if (this.options.manageHistory) {
			this.historyKey = 'Pagination' + Pagination.instanceCount;
			this.history = HistoryManager.register(
				this.historyKey,
				[this.options.currentPage],
				function(values) {
					this.goToPage(parseInt(values[0]));
				}.bind(this),
				function(values) {
					return this.historyKey + '(' + values[0] + ')';
				}.bind(this),
				this.historyKey + '\\((\\d+)\\)');
		}
		
		this.currentPage = Math.max(Math.min(this.options.currentPage, totalPages), 1);
		this.totalPages = totalPages;
		
		this.writePagination();
		this.updatePagination();
	},
	

	writePagination: function() {
		
		var startPage = Math.min(this.totalPages - this.options.windowSize+1,
							Math.max(1, this.currentPage - 
								this.options.windowLookBehind));
		var endPage = Math.min(this.totalPages, 
							startPage + this.options.windowSize-1);
		
	//	dbug.log('will write start to end, ' + startPage + ' to ' + endPage);
		
		(this.pagingDivs).each(function(theSpan) {
			theSpan.empty(); // clear out whatever is already there
			
			if(this.options.skipIfOnePage  &&  this.totalPages <= 1)
				return;
			
			theSpan.appendText(this.options.prefix);
			
			if(this.options.includePrevNext) {
				var thisItem = new Element('a');
				thisItem.addClass(this.options.pageLinkClass);
				thisItem.setText(this.options.prevText);
				thisItem.addEvent('click', function(e) {
					e = new Event(e);
					e.stop();
					this.moveBy(-1);
					return false;
				}.bind(this));
				theSpan.adopt(thisItem);
				theSpan.appendText(this.options.separator);
			}
			
			for(var i = 1; i <= this.totalPages; i++) {
				
				var thisPageNumber = new Element('a');
				thisPageNumber.addClass(i == this.currentPage ? 
					this.options.pageLinkCurrentClass : this.options.pageLinkClass);
				
				thisPageNumber.setText(i);
				thisPageNumber.addEvent('click', function(e) {
					e = new Event(e);
					e.stop();
					
					this.goToPage(parseInt(e.target.getText()));
					return false;
				}.bind(this));
				theSpan.adopt(thisPageNumber);
				theSpan.appendText(this.options.separator);
			}
			
			if(this.options.includePrevNext) {
				theSpan.appendText(this.options.separator);
				var thisItem = new Element('a');
				thisItem.addClass(this.options.pageLinkClass);
				thisItem.setText(this.options.nextText);
				thisItem.addEvent('click', function(e) {
					e = new Event(e);
					e.stop();
					this.moveBy(1);
					return false;
				}.bind(this));
				theSpan.adopt(thisItem);
			}
			
			theSpan.appendText(this.options.suffix);
		}, this);
	},
	
	
	updatePagination: function() {
		
		var startPage = Math.min(this.totalPages - this.options.windowSize+1,
							Math.max(1, this.currentPage - 
								this.options.windowLookBehind));
		var endPage = Math.min(this.totalPages, 
							startPage + this.options.windowSize-1);
		
		// Update our paging link classes (current vs. the rest):
		(this.pagingDivs).each(function(theSpan) {
			
			$ES('a', theSpan).each(function(theLink, index) {
			//	dbug.log('index=' + index + ', text=' + theLink.getText());
				if(this.options.includePrevNext  &&  index == 0) {
					// this is our 'previous page' link:
					if(this.currentPage == 1) // no previous applies so hide:
						theLink.setStyle('visibility', 'hidden');
					else
						theLink.setStyle('visibility', 'visible');
				}
				else if(this.options.includePrevNext  &&  index == this.totalPages+1) {
					// this is our 'next page' link:
					if(this.currentPage == this.totalPages) // no next applies:
						theLink.setStyle('visibility', 'hidden');
					else
						theLink.setStyle('visibility', 'visible');
				}
				else {
					if (index < startPage  ||  index > endPage) {
						// outside of our window, so hide:
						theLink.setStyle('display', 'none');
					}
					else {  // in our window, style it as current page or not:
						
						theLink.setStyle('display', '');
						
						if(theLink.getText() == (this.currentPage + '')) {
							theLink.removeClass(this.options.pageLinkClass);
							theLink.addClass(this.options.pageLinkCurrentClass);
						}
						else {
							theLink.removeClass(this.options.pageLinkCurrentClass);
							theLink.addClass(this.options.pageLinkClass);
						}
					}
				}
				
			}, this);
		}, this);
	},
	
	
	goToPage: function(pageNumber) {
		
		pageNumber = Math.max(Math.min(this.totalPages, pageNumber), 1);
		
		if (pageNumber == this.currentPage) {
		//	dbug.log('skipping out!');
			return;
		}
	//	dbug.log('going to page ' + pageNumber);
		
		var oldCurrentPage = this.currentPage;
		this.currentPage = pageNumber;
		
		this.updatePagination();
		
		if (this.options.manageHistory)
			this.history.setValue(0, pageNumber);
		this.clickAction(pageNumber);
		return false;
	
	},
	
	moveBy: function(byAmount) {
		this.goToPage(this.currentPage + byAmount);
	}
	
	
});

Pagination.implement(new Options, new Events);
Pagination.instanceCount = 0;
