/***************************************************************************
 * mootools-mootable.js
 * ---------------
 *   author		-> Tyson Cox
 *   started	-> Tuesday, Jan 6th, 2009
 *   modified	-> Tuesday, Jan 6th, 2009
 *   copyright	-> 
 *   email     	-> tyson@imagin8.com
 *   version    -> 1.0
 *
 * file description
 * ------------------
 * Provides a dynamically generated table allowing sorting and filtering
 *
 *
 * change log
 * ------------------
 * 1.0			Initial development
 *
 ***************************************************************************/


MooTable = new Class({
	                /*--------------------------------------------------------o
	----------------\                     Member Variables                    |
	    variables    \-------------------------------------------------------*/
	                
	tableFrame: null,
	tableHeaders: Array(),
	headerCount: 0,
	tableData: Array(),
	rowParams: Array(),
	dataCount: 0,
	
	sortMode: null,
	sortDir: null,
	page: 1,
	rowsPerPage: 2,
	
	options: null,
	rowInactiveState: null,
	rowActiveState: null,
	
	
	                /*--------------------------------------------------------o
	----------------\                    Internal Functions                   |
	     internal    \-------------------------------------------------------*/
		
	initialize: function(elem, options) {
		this.tableFrame = elem;
		
		if ( !options )
			options = {};
			
		this.page = (options.page) ? options.page : 1;
		this.rowsPerPage = (options.rowsPerPage) ? options.rowsPerPage : 25;
		this.rowInactiveState = (options.rowInactiveState) ? options.rowInactiveState : null;
		this.rowActiveState = (options.rowActiveState) ? options.rowActiveState : null;
		
	},

	                /*--------------------------------------------------------o
	----------------\                   List Setup Functions                  |
	      setup      \-------------------------------------------------------*/
	
	addHeader: function(text, sortable, sortcode) {
		this.tableHeaders[this.headerCount] = {		'title':	text,
													'sortable':	(sortable) ? true : false,
													'sortcode':	(sortcode) ? sortcode : null
												};
		
		this.headerCount++;
	},
	
	
	addRow: function(values, params) {
		this.tableData[this.dataCount] = values;
		this.tableData[this.dataCount]['params'] = (params) ? params : {}
//		this.rowParams[this.dataCount] = (params) ? params : {};
		
		this.dataCount++;
	},
	
	
	
	                /*--------------------------------------------------------o
	----------------\                      List Rendering                     |
	      render     \-------------------------------------------------------*/
	
	render: function() {
		if ( !this.tableFrame )
			return;
			
		this.tableFrame.empty();
		
		var mooTable = new Element('table', {	'class':	'mooTable', 'cellpadding': 0, 'cellspacing': 0	});
		var mooTBody = new Element('tbody', {});
		
		this.generateHeaders(mooTBody);
		this.generateRows(mooTBody);
		
		mooTable.adopt(mooTBody);
		this.tableFrame.adopt(mooTable);
		
		this.generatePagination();
	},
	
	
	generateHeaders: function(tbody) {
		var row = new Element('tr', {'class':	'moo_table header'});
		var tObj = this;
		
		$each(this.tableHeaders, function(header, idx) {
			var tHeader = new Element('th', {	'class': 	'moo_data header'+((header.sortable) ? ' sortable' : '')+((header.sortcode) ? ' '+header.sortcode : ''),
												'text':		header.title
										});
			
			if ( header.sortable ) {
				tHeader.addEvent('click', function() {	tObj.sortTable(header.sortcode);	});
			}
			
			row.adopt(tHeader);
		});
		
		tbody.adopt(row);
	},
	
	
	generateRows: function(tbody) {
		var startIdx = (this.page - 1) * this.rowsPerPage;
		var endIdx = this.page * this.rowsPerPage;
		var mooTable = this;
		
		// If there's records, show them... otherwise show an error / not found message
		if ( this.tableData.length ) {
			$each(this.tableData, function(item, idx) {
				if ( idx >= startIdx && idx < endIdx ) {
					var row = new Element('tr');
					
					$each(item, function(field, x) {
						if ( x != 'params' ) {
							row.adopt(new Element('td', {	'html': field	}));
						}
					});
					
					
					// Add row transitions if they were defined
					if ( this.rowInactiveState && this.rowActiveState ) {
						row.fx = new Fx.Morph(row, {'duration': 1000, 'wait': false, 'transition': Fx.Transitions.Quad.easeOut})
						
						row.addEvent('mouseover', function() {	this.fx.start(mooTable.rowActiveState);		}	);
						row.addEvent('mouseout', function() {	this.fx.start(mooTable.rowInactiveState);	}	);
					}
					
					
					// Add optional row class
					if ( item.params.rowClass ) {
						row.addClass(item.params.rowClass);
					}
					
					
					// Add optional click event
					if ( item.params.click ) {			row.addEvent('click', item.params.click);				}
					
					// Add optional mouseup event
					if ( item.params.mouseup ) {		row.addEvent('mouseup', item.params.mouseup);			}
					
					// Add optional contextmenu event
					if ( item.params.contextmenu ) {	row.addEvent('contextmenu', item.params.contextmenu);	}
					
					
					tbody.adopt(row);
				}
			}, this);
		} else {
			var row = new Element('tr');
			
			row.adopt(new Element('td', {	'text': 'No records to display',
											'colspan': this.tableHeaders.length,
											'class': 'no-records'
										}));
							
			tbody.adopt(row);
		}
	},
	
	
	generatePagination: function() {
		var pagination = new Element('div', {'class': 'pagination_frame'});
		var pages = Math.ceil(this.tableData.length / this.rowsPerPage);
		var tObj = this;
		
		// First page link
		var navFirst = new Element((this.page == 1) ? 'span' : 'a',	
											{	'href': 		void(0),
												'class':		'pagination nav_first',
												'text':			'«« first'
											});
		if ( this.page != 1) {	 navFirst.addEvent('click', function() { 	tObj.firstPage();		});		}
		
		
		// Prev page link
		var navPrev =  new Element((this.page == 1) ? 'span' : 'a',	
											{	'href': 		void(0),
												'class':		'pagination nav_prev',
												'text':			'« prev'
											});
		if ( this.page != 1) {	 navPrev.addEvent('click', function() { 	tObj.prevPage();		});		}
		
		
		// Next page link
		var navNext =  new Element((this.page == pages || !pages) ? 'span' : 'a',	
											{	'href': 		void(0),
												'class':		'pagination nav_next',
												'text':			'next »'
											});
		if ( this.page != pages) {	 navNext.addEvent('click', function() { 	tObj.nextPage();		});		}
		
		// Last page link
		var navLast =  new Element((this.page == pages || !pages) ? 'span' : 'a',
											{	'href': 		void(0),
												'class':		'pagination nav_last',
												'text':			'last »»'
											});
		if ( this.page != pages) {	 navLast.addEvent('click', function() { 	tObj.lastPage();		});		}

		
		// Page jump-to navigation
		var navPages =  new Element('div',	{	'href': 		void(0),
												'class':		'pagination nav_pages'
											});

		if ( pages ) {		
			for ( x = 1; x <= pages; x++ ) {
				if ( x == this.page ) {
					var pageLink =  new Element('span', {	'class':		'pagination nav_link_current',
															'text':			x
														});
				} else {
					var pageLink =  new Element('a', {	'href': 		void(0),
														'class':		'pagination nav_link',
														'text':			x,
														'pageNum':		x
													});
					pageLink.addEvent('click', function() { 	tObj.changePage(this.getProperty('pageNum'));		});
				}
				
				navPages.adopt(pageLink);
			}
		} else {
			var pageLink =  new Element('span', {	'class':		'pagination nav_link_current',
													'text':			' '
												});
			navPages.adopt(pageLink);
		}
		
		// Adopt everything
		pagination.adopt(navFirst, navPrev, navPages, navNext, navLast);
		
		this.tableFrame.adopt(pagination);
	},
	
	
	                /*--------------------------------------------------------o
	----------------\                Sorting and Data Handling                |
	     sorting     \-------------------------------------------------------*/
	                
	sortTable: function(column) {
		this.sortDir = (this.sortBy == column) ? ((this.sortDir == 'asc') ? 'desc' : 'asc') : 'asc';
		this.sortBy = column;
		var tObj = this;
		
		this.tableData = this.tableData.sort(function(a, b) {
			if ( tObj.sortDir == 'asc' ) {
				if ( eval('a.'+tObj.sortBy) == eval('b.'+tObj.sortBy) ) {
					return 0;
				} else if ( eval('a.'+tObj.sortBy) < eval('b.'+tObj.sortBy) ) {
					return -1
				} else {
					return 1;
				}
			} else {
				if ( eval('a.'+tObj.sortBy) == eval('b.'+tObj.sortBy) ) {
					return 0;
				} else if ( eval('a.'+tObj.sortBy) < eval('b.'+tObj.sortBy) ) {
					return 1
				} else {
					return -1;
				}
			}
		});

		this.render();
	},
	
	
	                /*--------------------------------------------------------o
	----------------\                 Pagination and Navigation               |
	    pagination   \-------------------------------------------------------*/
	                
	changePage: function(page) {
		this.page = parseInt(page);
		this.render();
	},
	
	
	firstPage: function() {
		this.page = 1;
		this.render();
	},
	
	
	prevPage: function() {
		this.page = (this.page > 1) ? parseInt(this.page) - 1 : 1;
		this.render();
	},
	
	
	nextPage: function() {
		this.page = (this.page < Math.ceil(this.tableData.length / this.rowsPerPage)) ? parseInt(this.page) + 1 : this.page;
		this.render();
	},
	
	
	lastPage: function() {
		this.page = Math.ceil(this.tableData.length / this.rowsPerPage);
		this.render();
	}
	
});