(function($) {
	$.fn.paginator = function(p, o) {
		var options = $.extend(true, {}, $.fn.paginator.defaults, o);
		
		var Paginator = Class.create({
			initialize: function(container, paginationSelector) {
				this.photos = [];
				this.size = 0;
				this.currentPage = 0;
				
				this.container = container;
				this.pagination = new Pagination(this, paginationSelector);
			},
			
			loadPhotos: function(offset, photos) {
				var count = photos.length;
				if(offset > 0) {
					
				}
				
				var page = (offset / options.photos.perPage) - 1;
				for(var c = 0; c < count; c++) {
					if(c % options.photos.perPage == 0) {
						page++;
						this.photos[page] = [];
					}
					this.photos[page].push(photos[c]);
				}
			},
			
			clearPhotos: function(size) {
				this.photos = [[]];
				this.size = size;
				this.currentPage = 0;
				this.pagination.reset(size);
			},
			
			changePage: function(page) {
				this.currentPage = page;
				this.render();
			},
			
			preloadImages: function() {
				var photos = this.photos[this.currentPage+1];
				if(!photos)
					return;
				for(var c = 0; c < photos.length; c++) {
					var i = new Image();
					i.src = photos[c].thumbnail;
				}
			},
			
			render: function() {
				var photos = this.photos[this.currentPage], c = 0;
				var html = "<table class='photoDetailTable'>";
					while(true) {
						html += "<tr>";
						
						var stop = c+options.photos.perRow;
						if(stop > photos.length)
							stop = photos.length;
						
						for(; c < stop; c++)
							html += "<td class='tablePhoto'>"+this.renderPhoto(photos[c])+"</td>";
							
						html += "</tr>";
						
						if(stop >= photos.length)
							break;
					}
				html += "</table>";
				this.container.html(html);
				this.preloadImages();
			},
			
			renderPhoto: function(photo) {
				return options.templates.photo.gsub('%title', photo.title).gsub('%caption', photo.caption).gsub('%thumbnail', photo.thumbnail).gsub('%preview', photo.preview).gsub('%show', photo.show);
			}
		});
		var Pagination = Class.create({
			initialize: function(paginator, containerSelector) {
				this.paginator = paginator;
				this.container = $(containerSelector);
			},
			
			reset: function(size) {
				this.size = size;
				this.currentPage = 0;
				this.pageCount = this.size / options.photos.perPage;
				this.pageCount -= (this.pageCount % 1);
				if(this.size % this.pageCount != 0)
					this.pageCount += 1;
				this.render();
			},
			
			render: function() {
				var html = '<table><tr>';
				
				if(this.currentPage > 0)
					html += '<td class="leftArrowContainer">'+this.renderLink('&laquo; <span class="arrowText">previous</span>', this.currentPage-1, options.classes.leftArrow)+'</td>';
				
				if(this.pageCount != 1) {
					html += '<td>';
					html += this.renderLink(1, 0, options.classes.pageLink);
					var needLeftDots = true, needRightDots = true;
					var startNumber = this.currentPage - options.pagination.spacing, stopNumber = this.currentPage + options.pagination.spacing;
					
					if(startNumber <= 1) {
						startNumber = 1;
						needLeftDots = false;
					}
					if(stopNumber >= (this.pageCount-2)) {
						stopNumber = this.pageCount-2;
						needRightDots = false;
					}
					
					if(needLeftDots)
						html += options.templates.dots;
						
					for(var c = startNumber; c <= stopNumber; c++)
						html += this.renderLink(c+1, c, options.classes.pageLink);
					
					if(needRightDots)
						html += options.templates.dots;
					
					if(stopNumber < this.pageCount-1)
						html += this.renderLink(this.pageCount, this.pageCount-1, options.classes.pageLink);
						
					html += '</td>';
					if(this.currentPage < this.pageCount-1)
						html += '<td class="rightArrowContainer">'+this.renderLink('<span class="arrowText">next</span> &raquo;', this.currentPage+1, options.classes.rightArrow)+'</td>';
					
				}
				html += "</tr></table><span class='clear'></span>";
				
				this.container.html(html);
				this.bindEvents();
			},
			
			renderLink: function(text, pageNumber, clas) {
				if(pageNumber == this.currentPage)
					return options.templates.activePage.gsub('%class', options.classes.activePage).gsub('%text', text);
				return options.templates.pageLink.gsub('%class', clas).gsub('%page', pageNumber).gsub('%text', text);
			},
			
			bindEvents: function() {
				var t = this;
				this.container.find('a').click(function(e) {
					var page = parseInt($(this).attr('page'));
					t.paginator.changePage(page);
					t.currentPage = page;
					t.render();
					
					e.preventDefault();
					return false;
				});
			}
		});
		
		return new Paginator(this, p);
	}
	
	$.fn.paginator.defaults = {
		classes: {
			activePage: 'activePageLink',
			pageLink: 'pageLink',
			rightArrow: 'rightArrow',
			leftArrow: 'leftArrow'
		}, photos: {
			perPage: 24,
			perRow: 4
		}, pagination: {
			spacing: 10
		}, templates: {
			activePage: "<a class='%class' page='%page'>%text</a> ",
			pageLink: "<a class='%class' page='%page'>%text</a> ",
			dots: "<span class='dots'>...</span>",
			photo: "<a href='%preview' onclick='return hs.expand(this);'><img src='%thumbnail' alt='%title' class='tableImage' /></a><div style='display: none;' class='highslide-caption'>%caption</div>"
		}
	};
})(jQuery);