// Sortable table script thanks to http://kryogenix.org/code/browser/sorttable/
// Modified to taste by http://go.warwick.ac.uk/webteam

/*
 * STOP
 * 
 * Are you thinking about including this in a template?
 * You probably want sortableTables.js instead, it's much better.
 * 
 * For page content, you probably just want to use the "sortable" checkbox
 * in the editor - read the FAQs.
 */

var SORT_COLUMN_INDEX;
var DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
var FILESIZE_RE = /^\(?([\d\.]+)\s([KM]B)\)?$/;

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)) {
            //initTable(thisTbl.id);
            ts_makeSortable(thisTbl);
        }
    }
    ts_afterInitCallback();
}

//default callback called after all tables have been made sortable.
if (!ts_afterInitCallback) var ts_afterInitCallback = function() {};

//default callback called after the table's been sorted.
var ts_aftersortCallback = function() {};

function ts_makeSortable(table) {
    if (table.rows && table.rows.length > 0) {
        var firstRow = table.rows[0];
    }
    if (!firstRow) return;
    
    // 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];
        
        //13/04/07 only if the cell has a sortable class
        if ((' '+cell.className+' ').indexOf("sortable") != -1) {
        	var txt = ts_getInnerText(cell);
	        var title = (cell.title)? cell.title : txt;
        	cell.title = 'Click to sort by ' + title.toLowerCase();
        	cell.innerHTML = '<a href="#" class="sortheader" '+ 
        	'onclick="ts_resortTable(this, '+i+');return false;">' + 
        	txt+'<span class="sortarrow">&nbsp;&nbsp;&nbsp;</span></a>';
    	}
    }
}

function ts_getInnerText(el) {
	if (typeof el == "string") return el.trim();;
	if (typeof el == "undefined") { return el.trim(); };
	if (el.innerText) return el.innerText.trim();	//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.trim(); //13/04/07 trim the result
}

function ts_resortTable(lnk,clid) {
    // get the span
    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 = clid || td.cellIndex;
    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]);
    sortfn = ts_sort_caseinsensitive;
    // 20/03/07: removed date and currency sorting functions
    if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric;
    
	possdate = itm.match(DATE_RE);
    if (possdate) {
      // looks like a date
      first = parseInt(possdate[1]);
      second = parseInt(possdate[2]);
      if (first > 12) {
        // definitely dd/mm
        sortfn = ts_sort_ddmm;
      } else if (second > 12) {
        sortfn = ts_sort_mmdd;
      } else {
        // looks like a date, but we can't tell which, so assume
        // that it's dd/mm (English imperialism!) and keep looking
        sortfn = ts_sort_ddmm;
      }
    }  
    
    if ((' '+table.rows[0].cells[column].className+' ').indexOf("sortable_filesize") != -1) {
    	sortfn = ts_sort_filesize;
    }  
    
    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]; }
    for (j=1;j<table.rows.length;j++) { newRows[j-1] = table.rows[j]; }

    newRows.sort(sortfn);

    if (span.getAttribute("sortdir") == 'down') {
        ARROW = '&nbsp;&nbsp;&uarr;';
        newRows.reverse();
        span.setAttribute('sortdir','up');
        lnk.className = 'sortheader sortup';
    } else {
        ARROW = '&nbsp;&nbsp;&darr;';
        span.setAttribute('sortdir','down');
        lnk.className = 'sortheader sortdown';
    }
    
    // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
    // don't do sortbottom rows
    for (i=0;i<newRows.length;i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) table.tBodies[0].appendChild(newRows[i]);}
    // 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]);}
    
    // 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?
                allspans[ci].innerHTML = '&nbsp;&nbsp;&nbsp;';
            }
        }
    }

    var parentRow = getParent(lnk,"tr");
    // Unset any other link classes
    var alllinks= parentRow.getElementsByTagName("a");
    for (var ci=0;ci<alllinks.length;ci++) {
        if (alllinks[ci] != lnk) {
            alllinks[ci].className = 'sortheader';
        }
    }
        
    span.innerHTML = ARROW;

    ts_aftersortCallback();
}

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_filesize(a,b) {
	aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
	bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
	
	a_bytes = 0;
	b_bytes = 0;
	
	mtch = aa.match(FILESIZE_RE);
	if (mtch) {
		num = mtch[1]; units = mtch[2];
		if (units == 'MB') {
			a_bytes = num * 1024 * 1024;
		} else {
			a_bytes = num * 1024;
		} 
	}
	mtch = bb.match(FILESIZE_RE);
	if (mtch) {
		num = mtch[1]; units = mtch[2];
		if (units == 'MB') {
			b_bytes = num * 1024 * 1024;
		} else {
			b_bytes = num * 1024;
		} 
	}
	
	return doNumericSort(a_bytes,b_bytes);
}

function ts_sort_numeric(a,b) { 
    return doNumericSort(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]),ts_getInnerText(b.cells[SORT_COLUMN_INDEX]));
}

function doNumericSort(a,b) {
	aa = parseFloat(a);
    if (isNaN(aa)) aa = 0;
    bb = parseFloat(b); 
    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 (String.prototype.trim) {
      aa = aa.trim();
      bb = bb.trim();
    }
    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 ts_sort_ddmm(a,b) {
	aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
    mtch = aa.match(DATE_RE);
    y = mtch[3]; m = mtch[2]; d = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt1 = y+m+d;
    mtch = bb.match(DATE_RE);
    y = mtch[3]; m = mtch[2]; d = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt2 = y+m+d;
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
}

function ts_sort_mmdd(a,b) {
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
    mtch = aa.match(DATE_RE);
    y = mtch[3]; d = mtch[2]; m = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt1 = y+m+d;
    mtch = bb.match(DATE_RE);
    y = mtch[3]; d = mtch[2]; m = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt2 = y+m+d;
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
}

function addEvent(elm, evType, fn, useCapture)
// 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");
  }
}

Event.onDOMReady(sortables_init);
