var TableSorter = Class.create();

TableSorter.prototype = {
	initialize: function(table_el)
	{
		this.config = {
		};
		
		this.compare_func = this.defaultCompareFunc;
		
		this.table_el = table_el; 
		
		this.header_tr_el = false;
		this.header_td_click_events = new Hash();
		this.autoFindHeaderRow();
		
		this.order = 'ASC';
		this.current_selected_col_index = 0;
	},
	autoFindHeaderRow: function()
	{
		this.clearEvents();
		$A(this.table_el.rows).each( function(tr_el, tr_el_index)
		{
			if ( tr_el.select('.table_header').length > 0 )
			{
				this.header_tr_el = tr_el;
				throw $break;
			}
		}.bind(this));
		
		// Events
		$A(this.header_tr_el.cells).each( function(td_el, td_el_index)
		{
			var click_event = function(event)
			{
				this.headerClicked(td_el_index);
			}.bindAsEventListener(this);
			
			td_el.observe('click', click_event);
			td_el.addClassName('table_header_sortable');
			
			this.header_td_click_events.set(td_el_index, click_event);
			
		}.bind(this))
	},
	clearEvents: function()
	{
		this.header_td_click_events.each( function(event_pair, event_pair_index)
		{
			var col_index = event_pair.key;
			var col_event = event_pair.value;
			
			var td_el = Element.extend(this.header_tr_el.cells[col_index]);
			td_el.stopObserving('click', col_event);
			td_el.removeClassName('table_header_sortable');
			
		}.bind(this));
	},
	headerClicked: function(td_el_index)
	{
		// Clear header status
		$A(this.header_tr_el.cells).each( function(td_el, td_el_index)
		{
			td_el.select('.table_header_sortable_asc').invoke('remove');
			td_el.select('.table_header_sortable_desc').invoke('remove');
			
		}.bind(this));
		
		// Confirm which column is selected
		var last_selected_col_index = this.current_selected_col_index;
		this.current_selected_col_index = td_el_index;
		
		// Prepare rows
		var rows = {length: 0};
		$A(this.table_el.rows).each( function(tr_el, tr_el_index)
		{
			if ( tr_el != this.header_tr_el) 
			{
				rows[rows.length] = tr_el;
				rows.length++;
			}
			
		}.bind(this));
		
		var sorted_rows = this.quickSort(rows);
		if ( this.current_selected_col_index == last_selected_col_index && this.order == 'ASC' ) 
		{
			// Reverse
			var reversed_sorted_rows = {length: sorted_rows.length};
			for ( var i = 0; i < sorted_rows.length; i++ ) 
			{
				reversed_sorted_rows[i] = sorted_rows[sorted_rows.length - i - 1];
			}
			sorted_rows = reversed_sorted_rows;
			this.order = 'DESC';
			this.header_tr_el.cells[this.current_selected_col_index].insert(new Element('span').addClassName('table_header_sortable_desc').update('&nbsp;<img src="/img/components/sorter_arrow_up.gif" />'));
		}
		else
		{
			this.order = 'ASC';
			this.header_tr_el.cells[this.current_selected_col_index].insert(new Element('span').addClassName('table_header_sortable_asc').update('&nbsp;<img src="/img/components/sorter_arrow_down.gif" />'));
		}
		for ( var i = 1; i < sorted_rows.length; i++ )
		{
			sorted_rows[i-1].insert({'after':sorted_rows[i]});
		}
	},
	quickSort: function(rows)
	{
		var less_rows = {length: 0};
		var equal_rows = {length: 0};
		var great_rows = {length: 0};

		if ( rows.length <= 0 )
		{
			return rows;
		}
		
		// Pivot
		var pivot_row = rows[0];
		
		// Loop
		for ( var i = 0; i < rows.length; i++ )
		{
			var compare_row = rows[i];
		
			var compare_result = this.compare_func(compare_row, pivot_row); 
			if ( compare_result == -1 )
			{
				less_rows[less_rows.length] = compare_row;
				less_rows.length++;
			}
			else if ( compare_result == 0 )
			{
				equal_rows[equal_rows.length] = compare_row;
				equal_rows.length++;
			}
			else if ( compare_result == 1 )
			{
				great_rows[great_rows.length] = compare_row;
				great_rows.length++;
			}
		}
		
		// Join
		var final_rows = {length: 0};
		
		less_rows = this.quickSort(less_rows);
		Object.keys(less_rows).without('length').each( function(row_index, row_index_index)
		{
			final_rows[final_rows.length] = less_rows[row_index];
			final_rows.length++;
			
		}.bind(this));
		
		Object.keys(equal_rows).without('length').each( function(row_index, row_index_index)
		{
		
			final_rows[final_rows.length] = equal_rows[row_index];
			final_rows.length++;
			
		}.bind(this));
		
		great_rows = this.quickSort(great_rows);
		Object.keys(great_rows).without('length').each( function(row_index, row_index_index)
		{
			final_rows[final_rows.length] = great_rows[row_index];
			final_rows.length++;
			
		}.bind(this));
		
		return final_rows;
	},
	defaultCompareFunc: function(src_row, dest_row)
	{
		var result = 0;
		var src_value = this._getMostDeepValue(src_row.cells[this.current_selected_col_index]).nodeValue;
		var dest_value = this._getMostDeepValue(dest_row.cells[this.current_selected_col_index]).nodeValue;
		
		switch( this.current_selected_col_index )
		{
			default:
				break;
		}
		if ( src_value < dest_value )
		{
			result = -1;
		}
		else if ( src_value == dest_value )
		{
			result = 0;
		}
		else if ( src_value > dest_value )
		{
			result = 1;
		}
		return result;
	},
	_getMostDeepValue: function(el)
	{
		if ( el.childNodes.length > 0 )
		{
			return this._getMostDeepValue(el.childNodes[0]);	
		}
		return el;
	}
}