/*
 * Paginate Class
 * 
 * @author: d.
 * 
 */

var Paginate = new Class({
	
	Implements: [Options, Events, Chain],
	
	options: {
		node: 'div.node',
		nodesContainer: 'paginate',
		paginationClass: 'pagination',
		separator: '|',
		nodesFilter: null,
		startPage: 1,
		nodesPerPage: 10,
		onShowPage: $empty,
		onHidePage: $empty
	},
	
	initialize: function(options) {
		this.setOptions(options);
		
		this.nodesContainer = $(this.options.nodesContainer); 
		if (this.nodesContainer) {
			this._attach();
			this._display();
		}
	},
	
	swap: function(page) {
		if (this.currentPage != page && page >= 1 && this.swapReady) {
			this.swapReady = false;
			
			if (this.visible) {
				this._hidePage().chain(function() {
					this._showPage(page).chain(function() {
						this.swapReady = true;
					}.bind(this));
				}.bind(this));
			} else {
				this._showPage(page).chain(function() {
					this.swapReady = true;
				}.bind(this));
			}
			
			return true;
		}
		
		return false;
	},
	
	refresh: function(nodesFilter) {
		if (this.refreshReady) {
			this.refreshReady = false;
			if (this.visible) {
				this._hidePage().chain(function() {
					this._detach();
					this._attach(nodesFilter);
					this._display();
				}.bind(this));
			} else {
				this._detach();
				this._attach(nodesFilter);
				this._display();
			}
		}
	},
	
	_display: (function() {
		// if the result set is paginated emulate clicking on start page link
		if (this.paginationElements) {
			var links = this.paginationElements[0].getElements('a');
			for (var i=0; i<links.length; i++) {
				if (links[i].retrieve('page').toInt() == this.options.startPage) {
					links[i].fireEvent('click');
					break;
				}
			}
		// just show first page (all nodes)
		} else {
			this._showPage(1);
		}		
	}).protect(),
	
	_attach: (function(nodesFilter) {
		// attach nodes
		this.nodes = this.nodesContainer.getElements(this.options.node);
		this.nodes.setStyles({
			'display': 'none',
			'opacity': 0
		});
		
		var filter = nodesFilter || this.options.nodesFilter; 
		if (filter) {
			this.nodes = this.nodes.filter(function(node) {
				return node.hasClass(filter)
			});
		}
		
		if (this.nodes) {
			this.nodesFx = new Fx.Elements(this.nodes, {
				duration: 'normal',
				transition: Fx.Transitions.Sine.easeIn
			});
		
			// attach pagination elements
			this.swapReady = true;
			this.currentPage = false;
			this.visible = false;
			
			if (this.nodes.length > this.options.nodesPerPage) {
				this.paginationElements = [];
				this.paginationElements.push(this._createPaginationElement('top'));
				this.paginationElements.push(this._createPaginationElement('bottom'));
				this.nodesContainer.adopt(this.paginationElements);
			}
		}
	}).protect(),
	
	_detach: (function() {
		if (this.nodes) {
			// detach nodes
			this.nodes = null;
			this.nodesFx = null;
			
			// detach pagination elements
			this.swapReady = false;
			this.currentPage = false;
			this.visible = false;
			
			if (this.paginationElements) {
				this.paginationElements.each(function(element) {
					element.destroy();
				});
				this.paginationElements = null;
			}
		}
	}).protect(),
	
	_showPage: (function(page) {
		this.currentPage = page;

		var nodesFxSettings = {};
		this.nodes.each(function(node, index) {
			if ((this.options.nodesPerPage*page-this.options.nodesPerPage) <= index && index < this.options.nodesPerPage*page) {
				node.setStyle('display', 'block');
				nodesFxSettings[index] = {
					'opacity': 1
				};
			}
		}, this);
		
		this.nodesFx.start(nodesFxSettings).chain(function(){
			this.visible = true;
			this.refreshReady = true;
			this.callChain();
			this.fireEvent('showPage');
		}.bind(this));
		
		return this;
	}).protect(),
	
	_hidePage: (function() {
		this.currentPage = null;
		
		var nodesFxSettings = {};
		this.nodes.each(function(node, index) {
			nodesFxSettings[index] = {
				'opacity': 0
			};
		});
		
		this.nodesFx.start(nodesFxSettings).chain(function(){
			this.nodes.each(function(node) {
				node.setStyle('display', 'none');
			});
			this.visible = false;
			this.callChain();
			this.fireEvent('hidePage');
		}.bind(this));
		
		return this;
	}).protect(),
		
	_createPaginationElement: (function(typeClass) {
		// store reference to main object
		var instance = this;
		
		// define pagination element
		var paginationElement = new Element('div', {
			'class': this.options.paginationClass
		});
		if (typeClass) {
			paginationElement.addClass(typeClass);
		}
		
		// add page links to pagination element
		var linksCount = Math.ceil(this.nodes.length / this.options.nodesPerPage);
		for (var i=1; i<=linksCount; i++) {
			
			// create link
			var link = new Element('a', {
				href: 'javascript:;',
				html: i,
				events: {
					'click': function(e) {
						if (e) e.stop();
						if (instance.swap(this.retrieve('page').toInt())) {
							for (var i=0; i<instance.paginationElements.length; i++) {
								instance.paginationElements[i].getElements('a').each(function(element) {
									if (element.hasClass('active')) {
										element.removeClass('active');
									}
									if (element.retrieve('page') == this.retrieve('page')) {
										element.addClass('active');
									}
								}, this);
							}
						}
					}
				}
			});
			link.store('page', i);
			
			// grab link
			paginationElement.grab(link);
			if (i!=linksCount) {
				paginationElement.grab(new Element('span', {
					html: this.options.separator
				}));
			}
		}
		
		return paginationElement;
	}).protect()
	
});