
jQuery.fn.clevertable = function(options) {
	
	if( options ) {

		// actually setup class
		return this.each(function() {
			var element = jQuery(this);
			
			// create object
			var table = new CleverTable(options);
			// register with table node
			element.data('clevertable', table);
			
		});
		
	} else {
		// just return existing table
		return this.data('clevertable');
	}
	
	
	
	// ########################################################################
	
	// declare class
	function CleverTable(options) {
		
		
		// support defaults
		var defaults = {
			
		};
		var opts = jQuery.extend(defaults, options);
	
		this.id = opts.id;
		this.baseUrl = opts.baseUrl;
		this.rowsPerPage = opts.rowsPerPage;
		this.sortBy = opts.sortBy;
		this.sortAsc = opts.sortAsc;
		this.searchFor = opts.searchFor;
		this.searchIn = opts.searchIn;
		this.total = opts.total;
		this.offset = opts.offset;

		this.columnIds = new Array();
		
		
		
		this.refresh = function() {
//			alert("request table data");
			var table = this;
			
			// build url
			
//			var url = this.baseUrl + "/" + this.sortBy + "/" + (this.sortAsc ? 1 : 0) + "/" + searchFor + "/" + searchIn + "/" + this.offset;
			var url = this.baseUrl + "/sort_by=" + $.URLEncode(this.sortBy) + "&sort_asc=" + (this.sortAsc ? 'true' : 'false') + "&offset=" + this.offset;

			var searchFor = $('#' + this.id + ' #search_for').val();
			if(searchFor && searchFor != '') {
				url += "&search_for=" + $.URLEncode(searchFor);
				var searchIn = $('#' + this.id + ' #search_in').val();
				if(searchIn)  url += "&search_in=" + $.URLEncode(searchIn);
			}

//			alert(url);

			// request data
			$.getJSON(url, function(data) {
				table.receivedData(data);
			});
		}

		this.receivedData = function(data) {
			
//			alert( "rx table data");
//			alert('Total=' + data.total);
			var table = this;
			

			// grab stats
			this.total = data.total;
			this.offset = data.offset;
			
			// row content
			$('#' + this.id + ' tbody').empty();
			$.each(data.rows, function(rowIndex, row) {
				var html = '<tr>';
				
				$.each(table.columnIds, function(index, id) {
					var value = row[id];
					if( value == null ) value = '';
					html += '<td>' + value + '</td>';
				});
				
				html += '</tr>';
				$('#' + table.id + ' tbody').append(html);
			});
			
			
			// colour rows
			$('#' + this.id + ' tbody tr:even').addClass('odd');
			
			
			// page buttons
			this.updatePageButtons();

			
		}



		this.updatePageButtons = function() {
			
//			alert("update page buttons");
			var table = this;
			
			var numPages = Math.ceil(this.total / this.rowsPerPage);
			if( numPages > 1 ) {
			
		    	var currentPage = Math.floor(this.offset / this.rowsPerPage);
		    	
		    	// num either side
		    	// first/last
		    	// forward/backwards
		    	var numEitherSide = 2;
		    	var start = Math.max(currentPage - numEitherSide, 0);
		    	var end = Math.min(currentPage + numEitherSide, numPages - 1);

		    	var html = '<p>';
//		    	html += "numPages=" + numPages + " currentPage=" + currentPage + " start=" + start + " end=" + end + "<br />";
		    	

		    	// first
		    	if(start > 0) html += '<a class="pfirst" href="#">First</a> ';
		    	// page back
		    	if(currentPage > 0) html += '<a class="p' + (currentPage - 1) + '" href="#">&lt;</a> ';
		    	// direct
		    	for(var p = start; p <= end; p++) {
		    		if(p != currentPage) html += '<a class="p' + p + '" href="#">' + (p + 1) + '</a> ';
		    			else html += (p + 1) + ' ';
		    	}
		    	// page forward
		   		if(currentPage < numPages - 1) html += '<a class="p' + (currentPage + 1) + '" href="#">&gt;</a> ';
		    	// last
		    	if(end < numPages - 1) html += '<a class="plast" href="#">Last</a>';
		    	
		    	
		    	html += "</p>";
		//alert(html);
		    	// apply html
		    	$('#' + this.id + ' .page_buttons').html(html);
		    	
		    	
		    	
		    	// bind events
		    	
		    	
		    	// first
		    	if(start > 0) {
		    		$('#' + this.id + ' .page_buttons .pfirst').click(function() {
		    			table.pageButtonPressed(0);
						return false;
		    		});
		     	}
		    	
		    	// direct
		   		// inner function to fix scope... there must be a better way.
		    	function bindPageButton(p) {
		    		$('#' + table.id + ' .page_buttons .p' + p).click(function() {
		    			table.pageButtonPressed(p);
						return false;
		    		});	
		    	}
		    	for(var p = start; p <= end; p++) {
		    		if(p != currentPage) {
		    			bindPageButton(p);
		    		}
		    	}
		    	
		    	// last
		    	if(end < numPages - 1) {
		    		$('#' + this.id + ' .page_buttons .plast').click(function() {
		    			table.pageButtonPressed(numPages - 1);
						return false;
		    		});
		    	}    	
		    	
		    	
			} else {
				// just empty it
				$('#' + this.id + ' .page_buttons').empty();
			}



			
		}



		this.pageButtonPressed = function(p) {
//			alert("page button pressed: " + p);
			this.offset = p * this.rowsPerPage;
			this.refresh();
		}


		this.bindColumnHeadings = function() {
			
//			alert("bind column headings");
			var table = this;
			
			// remove link url
			$('#' + this.id + ' thead th a')
				.attr('href', '#');
			
			// get column headings
			$('#' + this.id + ' thead th').each(function() {
					var columnId = this.id;
					columnId = columnId.substring(0, columnId.length - '_heading'.length);
					table.columnIds.push(columnId);
			});
			
			// bind event
			$('#' + this.id + ' thead th a')
				.click(function(event) {
					var columnId = $(event.target).parent().attr('id');
					columnId = columnId.substring(0, columnId.length - '_heading'.length);
					
					
					
//					alert('sort by: ' + columnId );
					
					// apply changes to table
					if( table.sortBy == columnId ) {
						// reverse order
						table.sortAsc = !table.sortAsc;
					} else {
						// change column
						table.sortAsc = true;
						table.sortBy = columnId;
					}
					
					// remove offset
					table.offset = 0;
					

					// remove all the classes from the headings
					$('#' + table.id + ' thead th').removeClass('sort_column').removeClass('asc').removeClass('desc');



					// apply classes to sort column
					$('#' + table.id + ' thead #' + columnId + '_heading')
						.addClass('sort_column')
						.addClass(table.sortAsc ? 'asc' : 'desc');
					
					// request data
					table.refresh();
					
					return false;
				});
		}


		
		
		
		// constructor code
		
//		alert("baseUrl=" + this.baseUrl);
		// bind column headings
		this.bindColumnHeadings();
		// page buttons
		this.updatePageButtons();
		// bind search box & menu
		var table = this;
		$('#' + this.id + ' #search_for').keyup(function(event) {
			table.offset = 0;
			$(this).stopTime('search_delay');
			$(this).oneTime(500, 'search_delay', function() {
				table.refresh();
			});
		});
		
		$('#' + this.id + ' #search_for').parents('form').submit(function() {
			table.offset = 0;
			table.refresh();
			return false;
		});
		
		$('#' + this.id + ' #search_in').change(function(event) {
			table.offset = 0;
			table.refresh();
		});
		
	}
	
	
	// ########################################################################
	

	
};



