//Put class="sortable" on the table and on each header field you want to sort by.
//Make sure the table has an ID.
//You can also put an element with ID of "ord" and one with ID of "asc"

addEvent(window, "load", sortables_init);

var SORT_COLUMN_INDEX;
var SHOW_ARRS = true;
var ARR_EMPTY	= "&nbsp;";
//var ARR_EMPTY	= "<img src='images/empty.gif' border=0>";
//var ARR_DOWN	= "<img src='images/arrow_up.gif' border=0>";
//var ARR_UP = "<img src='images/arrow_down.gif' border=0>";
var ARR_UP	= "&uarr;";
var ARR_DOWN= "&darr;";
//var ARR_UP	= "";
//var ARR_DOWN= "";
var cssClass = "men";


function sortables_init() {
	// Find all tables with class sortable and make them sortable
	if (!document.getElementsByTagName) return;
	tbls = document.getElementsByTagName("table");
	for (ti = 0; ti < tbls.length; ti++) {
		thisTbl = tbls[ti];
		if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) {
			ts_makeSortable(thisTbl);
		}
	}
}

function ts_makeSortable(table) {
	cssClass = cssClass ? 'class='+cssClass : '';

	if (table.rows && table.rows.length > 0) {
			var firstRow = table.rows[0];
	}
	if (!firstRow) return;

	var firstOne = true;

	// We have a first row: assume it's the header, and make its contents clickable links
	for (var i = 0; i < firstRow.cells.length; i++) {
		var cell = firstRow.cells[i];
		if((' '+cell.className+' ').indexOf("sortable") == -1) {
			continue;
		}

		var txt = ts_getInnerText(cell);

		if(SHOW_ARRS == true)
			cell.innerHTML = '<a '+cssClass+' href="#" title="Sort the table by ' + txt + '." class="sortheader" '+
				'onclick="ts_resortTable(this, '+i+');return false;">' +
				txt+'<span class="sortarrow">&nbsp;&nbsp;&nbsp;</span></a>';
		else {
			var ordVar = document.getElementById("ord");
			var ascVar = document.getElementById("asc");

			ARRAY = ARR_EMPTY;
			if(ordVar && ordVar.value == i) {
				ARRAY = ascVar.value == 'asc' ? ARR_DOWN : ARR_UP;
			}
			cell.innerHTML = '<a  '+cssClass+' href="#" title="Sort the table by ' + txt + '" class="sortheader" onclick="ts_resortTable(this, '+i+');return false;">' +
			txt+'<span class="sortarrow">'+ARRAY+'</span></a>';
		}
		if(firstOne) {
			firstOne = false;
			cell.innerHTML += "<input type='hidden' name='colnum' value='0' id='colnum'>";
		}
	}
}

function ts_getInnerText(el) {
	if (typeof el == "string") return el;
	if (typeof el == "undefined") { return el };
	if (el.innerText) return el.innerText;	//Not needed but it is faster
	var str = "";

	var cs = el.childNodes;
	var l = cs.length;
	for (var i = 0; i < l; i++) {
		switch (cs[i].nodeType) {
			case 1: //ELEMENT_NODE
				str += ts_getInnerText(cs[i]);
				break;
			case 3:	//TEXT_NODE
				str += cs[i].nodeValue;
				break;
		}
	}
	return str;
}

function getChildValue(obj) {
	while(obj.firstChild) {
		obj = obj.firstChild;
	}
	return obj.value;
}


function ts_resortTable(lnk, clid) {
    // get the span
	var ordVar = document.getElementById("ord");
	var ascVar = document.getElementById("asc");
	if(ordVar) ordVar.value = clid;
	var span;
	var SearchByValue = false;
	for (var ci = 0; ci < lnk.childNodes.length; ci++) {
		if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span')
			span = lnk.childNodes[ci];
	}
	var spantext = ts_getInnerText(span);

	var td = lnk.parentNode;
	var column = clid;
	var table = getParent(td,'TABLE');

	// Work out a type for the column
	if (table.rows.length <= 1) return;
	var itm = ts_getInnerText(table.rows[1].cells[column]);

	if(!itm) {
		itm = getChildValue(table.rows[1].cells[column]);
		if(!itm)
			return;
		SearchByValue = true;
	}

	sortfn = ts_sort_caseinsensitive;
	if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) sortfn = ts_sort_date;
	else if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) sortfn = ts_sort_date;
	else if (itm.match(/^[£$]/)) {sortfn = ts_sort_currency;}
	//else if (itm.match(/[0-9\.]/)) {sortfn = ts_sort_currency; }
	else if (itm.match(/^[\d\.]/)) {sortfn = ts_sort_numeric; }
	else if (itm.match(/^[\d\.]+%/)) {sortfn = ts_sort_numeric; }
	else if (SearchByValue == true) {
		sortfn = ts_sort_by_values_numeric;
	}

	SORT_COLUMN_INDEX = column;
	var firstRow = new Array();
	var newRows = new Array();
	for (i = 0; i < table.rows[0].length; i++) {
		firstRow[i] = table.rows[0][i];
	}


	// Check if there is a 'Total' line
	var total = 0;
	if(table.rows[table.rows.length - 1].className.indexOf("Total") != -1) {
	   total = 1;
	   var totalRow = table.rows[table.rows.length - 1];
	}
	// ------------------------

	for (j = 1; j < (table.rows.length - total); j++) {
		newRows[j-1] = table.rows[j];
	}
	newRows.sort(sortfn);
	var colNum = document.getElementById("colnum");
	if(colNum.value != clid) {
		span.setAttribute('sortdir','down');
		colNum.value = clid;
	}
	if (span.getAttribute("sortdir") == 'up') {
		if(SHOW_ARRS == true)
			ARROW = '&nbsp;&darr;&nbsp;&nbsp;';
		else
			ARROW = ARR_DOWN;
		if(ascVar) ascVar.value = 'asc';
		span.setAttribute('sortdir','down');
	}
	else {
		if(SHOW_ARRS == true)
			ARROW = '&nbsp;&uarr;&nbsp;&nbsp;';
		else
			ARROW = ARR_UP;
		newRows.reverse();
		span.setAttribute('sortdir','up');
		if(ascVar) ascVar.value = 'desc';
	}
	// We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
	// don't do sortbottom rows
	var bgColors = new Array();
 	bgColors[0] = '#ffffff';
 	bgColors[1] = '#EDF3F5';

	jj = 0;
	for (i=0;i<newRows.length;i++) {
		if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) {
			newRows[i].bgColor = bgColors[jj];
			table.tBodies[0].appendChild(newRows[i]);
			jj = jj ? 0 : 1;
		}
	}
	// do sortbottom rows only
	for (i=0;i<newRows.length;i++) {
		if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1))
			table.tBodies[0].appendChild(newRows[i]);
	}

	// if there is a 'Total' line, 'append' it as the last one
	if(total)
	   table.tBodies[0].appendChild(totalRow);

	// Delete any other arrows there may be showing
	var allspans = document.getElementsByTagName("span");

	for (var ci = 0; ci < allspans.length; ci++) {
		if (allspans[ci].className == 'sortarrow') {
			if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us?

				if(SHOW_ARRS == true)
					allspans[ci].innerHTML = '&nbsp;&uarr;&darr;';
				else
					allspans[ci].innerHTML = ARR_EMPTY;
			}
		}
	}
	span.innerHTML = ARROW;
}

function getParent(el, pTagName) {
	if (el == null) return null;
	else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())	// Gecko bug, supposed to be uppercase
		return el;
	else
		return getParent(el.parentNode, pTagName);
}

function ts_sort_date(a,b) {
	// y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
	aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
	bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
	if (aa.length == 10) {
		dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
	}
	else {
		yr = aa.substr(6,2);
		if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
		dt1 = yr+aa.substr(3,2)+aa.substr(0,2);
	}
	if (bb.length == 10) {
			dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
	}
	else {
		yr = bb.substr(6,2);
		if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
		dt2 = yr+bb.substr(3,2)+bb.substr(0,2);
	}
	if (dt1==dt2) return 0;
	if (dt1<dt2) return -1;
	return 1;
}

function ts_sort_by_values_numeric(a, b) {
	aa = getChildValue(a.cells[SORT_COLUMN_INDEX]);
	bb = getChildValue(b.cells[SORT_COLUMN_INDEX]);

	if (isNaN(aa)) aa = 0;
	if (isNaN(bb)) bb = 0;
	return aa-bb;
}

function ts_sort_currency(a,b) {
	aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
	bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
	return parseFloat(aa) - parseFloat(bb);
}

function ts_sort_numeric(a,b) {
	aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));
	if (isNaN(aa)) aa = 0;
	bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]));
	if (isNaN(bb)) bb = 0;
	return aa-bb;
}

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

function ts_sort_default(a,b) {
	aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
	bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
	if (aa==bb) return 0;
	if (aa<bb) return -1;
	return 1;
}


// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
function addEvent(elm, evType, fn, useCapture) {
	if (elm.addEventListener) {
		elm.addEventListener(evType, fn, useCapture);
		return true;
	}
	else if (elm.attachEvent) {
		var r = elm.attachEvent("on"+evType, fn);
		return r;
	}
	else {
		alert("Handler could not be removed");
	}
}
