// Table manipulation functionality



///////////////////////////////////////////////////////////////////////////////
/////////////////////////* Behavioural definitions *///////////////////////////
///////////////////////////////////////////////////////////////////////////////

if(Behaviour && Behaviour.register){
var behave = {
	'table.sortable thead tr th' : function(el){
		Behaviour.addEventObserver(el, 'click', function(){
			var i, tbody = this.parentNode.parentNode.parentNode.getElementsByTagName('tbody');
			for(i = 0; i < tbody.length; i++){
				Sort.Table(tbody[i], this.cellIndex);
			}
		});

	}, 
	'ul.sortable li.sort'	: function(el){
		Behaviour.addEventObserver(el, 'click', function(){
			Sort.List(this.parentNode, true);
		});
	}
}
Behaviour.register(behave);
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////* Sorting core functionality *//////////////////////////
///////////////////////////////////////////////////////////////////////////////


var Sort	= new Object();
Sort.reversal	= new Array();
Sort.caseSensitive	= false; // Default
Sort.checkTypes		= true;	// Handle numbers gracefully, etc

Sort.Flip	= function (obj, supp){
	if(typeof(obj) != 'object' || !obj.nodeName) return false;
	if(typeof(supp) != 'string') supp = '';
	if(!obj.id) obj.setAttribute('id', 'sorting-' + this.reversal.length);
	var id = obj.nodeName + '#' + obj.id + supp;
	this.reversal[id] = (typeof(this.reversal[id]) != 'boolean')
		? false
		: !this.reversal[id];

//	alert('Sort [' + id + '] ' + this.reversal[id]);
	
	return this.reversal[id];
}
Sort.typeHandler	= function(t){
	if(typeof(t) == 'string' && !this.caseSensitive)  t = t.toLowerCase();
	if(this.isNumeric(t)) t = Number(t);

	return t;
}
Sort.typeCompare = function(a, b){
	a = this.typeHandler(a);
	b = this.typeHandler(b);

	if(a > b) return 1;
	if(b > a) return -1;
	return 0;
}

Sort.isNumeric = function(t){
	if(typeof(t) == 'number') return true;
	if(typeof(t) != 'string') return null;
	var valid	= "0123456789.";
	var i, s;
	for(i = 0; i < t.length; i++){
		s = valid.indexOf(t.charAt(i));
		if(s < 0) return false;
	}
	return true;
}

Sort.ElementValue = function(el){
	if(!el.nodeName) return false;
	switch(el.nodeName.toLowerCase()){
		case 'td':
		case 'li': return (el.textContent) ? el.textContent : el.innerText ;
		default: return null;
	}
	return null;
}






///////////////////////////////////////////////////////////////////////////////
/////////////////////////* List sorting support *//////////////////////////////
///////////////////////////////////////////////////////////////////////////////



Sort.List	= function(lst, s, rev){
	if(!lst.nodeName || lst.nodeName.toLowerCase() != 'ul') return false;
	var i, reverse = (typeof(rev) =='boolean') ? rev : this.Flip(lst);	

	if(typeof(s) == 'boolean' && s){
		// sort sublists first
		var sublists = lst.getElementsByTagName('ul');
		for(i = 0; i < sublists.length; i++){
			this.List(sublists.item(i), s, reverse); 
		}
	}
	
	var listitems = this.getListItems(lst);
	listitems = listitems.sort(this.ListItemCompare).reverse();
	if(reverse) listitems = listitems.reverse();

	for(var i = 0; i < listitems.length; i++){
		lst.insertBefore(listitems[i], lst.firstChild);
	}
}

Sort.ListItemCompare	= function(a, b){
	return Sort.typeCompare(Sort.ElementValue(a), Sort.ElementValue(b));
}

Sort.getListItems = function(lst){
	var items = new Array();
	for(var i = 0; i < lst.childNodes.length; i++){
		if(this.isListItem(lst.childNodes.item(i)))
			items.push(lst.childNodes.item(i));
	}
	return items;
}

Sort.isListItem = function(li){
	return (li.nodeName.toLowerCase() == 'li' && li.className.indexOf('sort') < 0);
}







///////////////////////////////////////////////////////////////////////////////
//////////////////////////* Table sorting support *////////////////////////////
///////////////////////////////////////////////////////////////////////////////


// If this function receives a tbody instead of a table, 
// the behaviour should be identical, except with regard
// to the scope of the sorting operation as implied by 
// the table structure.

Sort.Table	= function(table, cellindex){
	var reversed = this.Flip(table, '.' + cellindex);
	var i, t, sortvalues = new Array();

	for(i = 0; i < table.rows.length; i++){
		t = Sort.ElementValue(table.rows[i].cells[cellindex]);
		sortvalues.push([t, table.rows[i]]);
	}

	sortvalues = sortvalues.sort(this.TableRowCompare).reverse();
	if(reversed) sortvalues = sortvalues.reverse(); // reverse it again if desired

	for(i = 0; i < sortvalues.length; i++){
		table.insertBefore(sortvalues[i][1], table.firstChild);
	}
	return sortvalues.length;
	
}

Sort.TableRowCompare = function(a, b){
	return Sort.typeCompare(a[0], b[0]);
}

