//
// new Star.Table( 'my_table', {
//	 zebra: true,		 // Stripe the table, also on initialize
//	 details: false,	// Has details every other row
// });
//
// The above were the defaults.	The regexes in loadConversions test a cell
// begin sorted for a match, then use that conversion for all elements on that
// column.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//

var SortingTable;
SortingTable = new Class({
	
	options: {
		zebra: true,
		details: false,
		alternateRowClassName: 'alternate',
		headerAscClass:	'sortAsc',
		headerDescClass: 'sortDesc',
		sortDirection: 'asc',
		sortColumn: 0
	},
	
	initialize: function(table, options) {
		tic('SortingTable.initialize');
		this.setOptions(options);
		
		this.table = $(table);
		
		this.tbody = $(this.table.getElementsByTagName('tbody')[0]);
		if (this.options.zebra) {
			this.stripeTable();
		}
		
		// State of the sort:
		this.sortColumn		= this.options.sortColumn;
		this.sortDirection	= this.options.sortDirection;
		
		this.headers = new Hash;
		var thead = $(this.table.getElementsByTagName('thead')[0]);
		$each(thead.getElementsByTagName('tr')[0].getElementsByTagName('th'), function( header, index ) {
			var header = $(header);
			this.headers.set( header.getText(), { column: index } );
			header.addEvent( 'mousedown', function(evt){
				var evt = new Event(evt);
				tic('sort');
				this.sortByHeader( $(evt.target).getText() );
				toc('sort');
			}.bind( this ));
		}.bind( this ) );
	
		this.thSet = $(thead.getElementsByTagName('tr')[0]).getChildren();	
		
		this.loadConversions();
		toc('SortingTable.initialize');
	},

	sortByHeader: function( header_text ){
		this.rows = new Array;
		var trs = this.tbody.getChildren();
		while ( trs.length > 0 ) {
			var row = { row: trs.shift().remove() };
			if ( this.options.details ) {
				row.detail = trs.shift().remove();
			}
			this.rows.unshift( row );
		}

		var header = this.headers.get( header_text );
		
		// Remove the sort header class from the was-sorted header:
		this.thSet[this.sortColumn].removeClass(this.options.headerAscClass);
		this.thSet[this.sortColumn].removeClass(this.options.headerDescClass);
		
		this.sortColumn = header.column;
		
		if ( this.sort_column >= 0 && this.sort_column == header.column ) {
			// They were pulled off in reverse
			this.sortDirection = (this.sortDirection == 'asc' ? 'desc' : 'asc');
			dbug.log('reverse, now ' + this.sortDirection);
		} else {
			this.sortDirection = 'asc';
			dbug.log('ascending!');
			
			this.sort_column = header.column;
			if (header.conversion_function) {
				this.conversion_function = header.conversion_function;
			} else {
				// Time to work out what our conversion function should be:
				this.conversion_function = false;
				this.rows.some(function(row){
					var to_match = $(row.row.getElementsByTagName('td')[this.sort_column]).getText();
					if (to_match == ''){ return false }
					this.conversions.some(function(conversion){
						if (conversion.matcher.test( to_match )){
							this.conversion_function = conversion.conversion_function;
							return true;
						}
						return false;
					}.bind( this ));
					if (this.conversion_function){ return true; }
					
					return false;
				}.bind( this ));
					
				// if we made it this far, there is NO data to sort on, so...
				if (!this.conversion_function) {
					dbug.log('Totally empty data, so default conversion_function');
					this.conversion_function = function( row ) {
						return $(row.row.getElementsByTagName('td')[this.sort_column]).getText();
					}
				}
				header.conversion_function = this.conversion_function.bind( this );
				this.headers.set( header_text, header );
			}
			this.rows.each(function(row){
				row.compare_value = this.conversion_function( row );
			}.bind( this ));
			this.rows.sort( this.compareRows.bind( this ) );
		}
		tic('rebuild');
		while (this.rows.length > 0) {
			var row = this.rows.shift();
		//	row.row.injectInside( this.tbody );
		//	if (row.detail){ row.detail.injectInside( this.tbody ) };
			this.tbody.appendChild(row.row);
			if (row.detail){ this.tbody.appendChild(row.detail); };
			
		}
		toc('rebuild');
		this.rows = false;
		
		if (this.options.zebra)
			this.stripeTable();
			
			
		// Now set the header column sort class:
		this.thSet[header.column].addClass(
			this.sortDirection == 'asc' ?
				this.options.headerAscClass : this.options.headerDescClass);
		
	},

	compareRows: function( r1, r2 ) {
		if ( r1.compare_value > r2.compare_value ) { return	1 }
		if ( r1.compare_value < r2.compare_value ) { return -1 }
		return 0;
	},
	
	loadConversions: function() {
		this.conversions = $A([
			// YYYY-MM-DD, YYYY-m-d
			{ matcher: /\d{4}-\d{1,2}-\d{1,2}/,
				conversion_function: function( row ) {
					var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).getText();
					var re = /(\d{4})-(\d{1,2})-(\d{1,2})/;
					cell = re.exec( cell );
					return new Date(parseInt(cell[1]), parseInt(cell[2], 10) - 1, parseInt(cell[3], 10));
				}
			},
			// Numbers
			{ matcher: /^\d+$/,
				conversion_function: function( row ) {
					var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).getText();
					return parseInt(cell);
				}
			},
			// Fallback 
			{ matcher: /.*/,
				conversion_function: function( row ) {
					return $(row.row.getElementsByTagName('td')[this.sort_column]).getText();
				}
			}
		]);
	},
	
	stripeTable: function () {
		tic('stripe');
		var counter = 0;
		var tr_elements = this.tbody.getChildren();
		
		var hasDetails = this.options.details;
		var alternateRowClassName = this.options.alternateRowClassName;
		
		$$(tr_elements).each(function(tr) {
			if (tr.style.display != 'none' && !tr.hasClass('collapsed')) {
				counter++;
			}
			
			var isOdd;
			if (hasDetails)
				isOdd = (Math.floor((counter+1) / 2) % 2 == 1);
			else
				isOdd = (counter % 2 == 1);
			
			if (isOdd)
				tr.removeClass(alternateRowClassName);
			else
				tr.addClass(alternateRowClassName);
			
		}.bind( this ));
		toc('stripe');
	}
});
	
SortingTable.stripeTable = function (tr_elements) {
	var counter = 0;
	$$( tr_elements ).each( function( tr ) {
		if ( tr.style.display != 'none' && !tr.hasClass('collapsed') ) {
			counter++;
		}
		tr.removeClass( 'alt' );	 
		if ( !(( counter % 2 ) == 0) ) {
			tr.addClass( 'alt' );	 
		}
	}.bind( this ));
}

SortingTable.implement(new Options, new Events);