/*	tablesorter.js
 *
 *	All tables marked with class sortable will be processed
 *	All columns with table headers without the 'static' class will be sortable.
 *	All sortable column headers will be marked with a sortheader class
 *	The currently sorted column's header will be marked with a listHeaderSortDesc or listHeaderSortAsc class
 */

addEvent(window, 'load', sortables_init);

var SORT_COLUMN_INDEX = -1;
var ts_sort_default = ts_sort;

function sortables_init()
{
	if (!document.getElementsByTagName)	{return;}
	var tbls=document.getElementsByTagName('table');
	for (var ti=0;ti<tbls.length;ti++){
		if (tbls[ti].className.indexOf('sortable')!=-1){
			ts_makeSortable(tbls[ti]);
		}
	}
}


function ts_makeSortable(table)
{
	if (!table.tHead.rows||table.tHead.rows.length==0)	{return;}

	function getOnFunc(s,c){return function(){ts_resortTable(s,c);};}
	var firstRow=table.tHead.rows[0];

	for (var i=0; i<firstRow.cells.length; i++)
	{
		if (firstRow.cells[i].className.indexOf('static') !=-1){
			continue;
		}

		firstRow.cells[i].onclick=getOnFunc(firstRow.cells[i],i);
		firstRow.cells[i].className+=' sortheader';
	}
}

function ts_resortTable(td, i)
{
	var reversing=(SORT_COLUMN_INDEX==i);
	var down=(reversing && td.getAttribute('sortdir')!='down');

	var table=getParent(td,'table');
	var body=table.tBodies[0];
	var tr=td.parentNode;

	SORT_COLUMN_INDEX=i;

	//Work out a type for the column
	var sortfn=ts_sort_default;
	for (i=0;i<body.rows.length; i++)
	{
		var txt=getText(body.rows[i].cells[SORT_COLUMN_INDEX]);

		if (!txt.match(/^\s*$/))
		{
			if (!isNaN(parseFloat(txt)))					sortfn=ts_sort_numeric;
			if (txt.match(/^[$£]\d*\.?\d+$/))				sortfn=ts_sort_numeric_pcrap;
			if (txt.match(/^\d+\.?\d*[%]$/))				sortfn=ts_sort_numeric_pcrap;
			if (txt.match(/^\d\d\d\d[^\d]\d\d[^\d]\d\d$/))	sortfn=ts_sort_date;
			if (txt.match(/^[^@]+@.+\.[a-z]{2,4}$/))		sortfn=ts_sort_caseinsensitive;
			break;
		}
	}

	//cycle through all the theads and remove the listHeaderSort[Asc|Desc] classes
	for (i=0; i<tr.cells.length; i++)
		tr.cells[i].className=tr.cells[i].className.replace(/\bsorted(De|A)sc/, ' ');

	var newRows=[];
	for (i=0; i<body.rows.length; i++)
		newRows[i]=body.rows[i];

	if (reversing)	newRows.reverse();
	else			newRows.sort(sortfn);

	td.className+=down?' sortedDesc':' sortedAsc';
	td.setAttribute('sortdir',down?'down':'up');

	for (i=0; i<newRows.length; i++)
		body.appendChild(newRows[i]);
}


function ts_sort_date(a,b)
{
	var aa=getText(a.cells[SORT_COLUMN_INDEX]);
	var bb=getText(b.cells[SORT_COLUMN_INDEX]);
	//		xxxx		  .		xx		 .	xx
	return (aa.substr(0,4)+aa.substr(5,2)+aa.substr(8,2)) -
		   (bb.substr(0,4)+bb.substr(5,2)+bb.substr(8,2));
}
function trimcrap(s)
{
	var i=0,j=s.length-1;
	while (i<=j&&isNaN(s[i])&&s[i]!='-'&&s[i]!='.')	i++;
	while (i<=j&&isNaN(s[j])&&s[j]!='-'&&s[j]!='.')	j--;
	return s.substr(i,j-i+1);
}
function ts_sort_numeric_pcrap(a,b)
{
	var aa=parseFloat(trimcrap(getText(a.cells[SORT_COLUMN_INDEX])));
	var bb=parseFloat(trimcrap(getText(b.cells[SORT_COLUMN_INDEX])));

	if (isNaN(aa))	aa=Number.MIN_VALUE;
	if (isNaN(bb))	bb=Number.MIN_VALUE;

	return aa-bb;
}
function ts_sort_numeric(a,b)
{
	var aa=parseFloat(getText(a.cells[SORT_COLUMN_INDEX]));
	var bb=parseFloat(getText(b.cells[SORT_COLUMN_INDEX]));

	if (isNaN(aa))	aa=Number.MIN_VALUE;
	if (isNaN(bb))	bb=Number.MIN_VALUE;

	return aa-bb;
}
function ts_sort(a,b)
{
	var aa=getText(a.cells[SORT_COLUMN_INDEX]);
	var bb=getText(b.cells[SORT_COLUMN_INDEX]);

	if (aa<bb)	return -1;
	if (aa>bb)	return 1;
	return 0;
}
function ts_sort_caseinsensitive(a,b)
{
	var aa=getText(a.cells[SORT_COLUMN_INDEX]).toLowerCase();
	var bb=getText(b.cells[SORT_COLUMN_INDEX]).toLowerCase();

	if (aa<bb)	return -1;
	if (aa>bb)	return 1;
	return 0;
}

function addEvent(e,type,fn,uC) 
{
	if (e.addEventListener)	{ e.addEventListener(type,fn,uC); return true; }
	else if (e.attachEvent)	{ return e.attachEvent('on'+type,fn); }
	else					{ e['on'+type] = fn; return null; }
}
function getParent(e,tag)
{
	for (tag=tag.toLowerCase(); e!=null && e.tagName.toLowerCase()!=tag; e=e.parentNode)
		;
	return e;
}
function getText(e)
{
	if (typeof(e)!='object')	return e;
	if (e.textContent)			return e.textContent;	//DOM 3
	if (e.innerText) 			return e.innerText;		//IE

	var str='';
	for (var i=0; i<e.childNodes.length; ++i)
	{
		switch (e.childNodes[i].nodeType)
		{
			case 1:	str += getText(e.childNodes[i]);	break;	//ELEMENT_NODE
			case 3:	str += e.childNodes[i].nodeValue;	break;	//TEXT_NODE
			default:break;
		}
	}
	return str;
}
function wrap(e,w)
{
	while (e.hasChildNodes())
		w.appendChild(e.removeChild(e.firstChild));
	e.appendChild(w);
}
