addEvent(window, "load", sortables_init);

var SORT_COLUMN_INDEX;
var TABLE_ROW_START;

// This javascript file is a mixture of a sorting Javascript that
// I found on the net and some of my own code to 'pretty up' the tables
// The main alterations to the file include:
//		A) If the table id ends in a single digit number
//			then freeze N bottom rows. This makes it so
//			totals and averages columns don't get mucked in a sort
//		B) Anytime a resort is done, renumber from 1..x the left most
//			column, also freeze the left column so its not sortable
//		C) Redraw the table color bars - anytime someone sorts you
//			need to recolor the table bars. so they are every other..


// We determine if the last rows need to be sorted by the id
// if id0 then all rows but the header, id1 all but last row...

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)) {
			ts_makeSortable(thisTbl);
			ts_colorize(thisTbl);  // swap coloring of rows
        } 

    }
}

function ts_colorize(table) {
	for(var i = 1; i < table.rows.length ; i++) {
		if(table.rows[i].className.indexOf("line_") == -1) { continue; }
		if(i%2 == 0) {
			table.rows[i].className = 'line_even';
		} else {
			table.rows[i].className = 'line_odd';
		}
	} 
}

function ts_makeSortable(table) {

	for(var i = 1; i < table.rows.length; i++) {
		if(table.rows[i].className = 'head') { 
			TABLE_ROW_START = i; 
			break;
		}
	}
	
    if (!TABLE_ROW_START) return;

    for (var i = 1; i < table.rows[TABLE_ROW_START].cells.length; i++) {
		var cell = table.rows[TABLE_ROW_START].cells[i];
		var txt  = ts_getInnerText(cell);
		cell.innerHTML = '<a href="#" class="sortheader" onclick="ts_resortTable(this); return false;">'+txt+'<span class="sortarrow"></span></a>';
   }

	// Increment TABLE_ROW_START to be the index of the first data row
	TABLE_ROW_START++;
}

function ts_renumber(table) {
	if(!table.rows[0]) return;

	var ln_no = 1;
	for(var i = TABLE_ROW_START ; i < table.rows.length; i++) {
		if(table.rows[i].className.indexOf("line_") != -1) {
			var cell = table.rows[i].cells[0];
			if(!cell) return;
			cell.innerHTML = '&nbsp;'+ln_no++;
		}
	}
}

	
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 ts_resortTable(lnk) {
     // This routine takes what is passed by lnk (which is the 'this' passed by the onclick command
     // setup in the sort setup procedure
     // the lnk.childNodes are the nodes within the tags passed by this
    var span;
    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 		= td.cellIndex;
    var table 		= getParent(td,'TABLE');

	if(!TABLE_ROW_START) return;
   
    // Work out a type for the column
	var itm 	= ts_getInnerText(table.rows[TABLE_ROW_START].cells[column]);
	itm = trimText(itm);

    sortfn = ts_sort_caseinsensitive;
	
    if (itm.match(/^\d+[\/-]\d+[\/-]\d+$/))	sortfn = ts_sort_date;
    if (itm.match(/^[£$]/))	sortfn = ts_sort_currency;
    if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric;

    SORT_COLUMN_INDEX = column;

	// Get the column info into an array for sorting.
    var newRows 	= new Array();
    var lastRows 	= new Array(); 
  
	for (var j = TABLE_ROW_START; j < table.rows.length ; j++) { 
		if(table.rows[j].className.indexOf("line_") != -1) {
			newRows.push(table.rows[j]); 
		} else {
			if(newRows.length) lastRows.push(table.rows[j]);
		}

	}

    newRows.sort(sortfn);

    // Set sort order
    // sortdir doesn't exist (== 'null') until the user first clicks
    if (span.getAttribute("sortdir") == 'down') {
		newRows.reverse();
		span.setAttribute('sortdir','up');
	} else {
		span.setAttribute('sortdir','down');
	}
   
    // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
	for (i=0; i < newRows.length ;i++) { 
		table.tBodies[0].appendChild(newRows[i]);
	}

	// Append the rows we didn't want sorted
	for(i=0; i < lastRows.length ; i++) {
		table.tBodies[0].appendChild(lastRows[i]);
	}

	// colorize & renumber
    ts_colorize(table);
    ts_renumber(table);
}


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 pad(num) {
	return(num.length == 1 ? "0" + num : num);
}

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]);

	var reg = /(\d+)\/(\d+)\/(\d+)/;
	var ar  = reg.exec((ts_getInnerText(a.cells[SORT_COLUMN_INDEX])));
	ar[1] = pad(ar[1]);
	ar[2] = pad(ar[2]);
	aa = ar[3]+ar[1]+ar[2];
	
	ar =  reg.exec((ts_getInnerText(b.cells[SORT_COLUMN_INDEX])));
	ar[1] = pad(ar[1]);
	ar[2] = pad(ar[2]);
	bb = ar[3]+ar[1]+ar[2];

	a1 = parseInt(aa,10);
	b1 = parseInt(bb,10);

	if(a1 >  b1) return 1;
	if(a1 == b1) return 0;
	if(a1 <  b1) return -1;
}

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;
}

function trimText(a) {
	while(a.charAt(0) == " " || a.charAt(0) == "\n") { a = a.substring(1); }
	while(a.charAt(a.length-1) == " " || a.charAt(a.length - 1) == "\n")  { a = a.substring(0,a.length-1); }
	return a;
}

function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
{
  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");
  }
} 

