/*
 * This file was originally written by Stuart Langridge and distributed
 * under the MIT License.  I have modified it to handle some of the
 * exceptions generally found in my data.
 * File $Id: sorttable.js 1112 2006-10-06 03:43:40Z hkw2 $
 */

addEvent(window, "load", sortables_init);

var SORT_COLUMN_INDEX;

var months = {};
months["January"] = 1;
months["February"] = 2;
months["March"] = 3;
months["April"] = 4;
months["May"] = 5;
months["June"] = 6;
months["July"] = 7;
months["August"] = 8;
months["September"] = 9;
months["October"] = 10;
months["November"] = 11;
months["December"] = 12;

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) {
  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];
    var txt = ts_getInnerText(cell);
    cell.innerHTML = 
      '<a href="" class="sortheader" onclick="ts_resortTable(this);return false;">'+txt+'<span class="sortarrow"></span></a>';
  }
}

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) {
  // get the span
  var span;
  var itm;
  var i;
  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');
    
  // Work out a type for the column
  if (table.rows.length <= 1) return;
  i = 1;
  while (itm == null) {
    itm = ts_getInnerText(table.rows[i++].cells[column]);
  }
  itm = itm.replace(",","");
    
  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(/^\w+ \d\d \d\d\d\d$/)) {
    sortfn = ts_sort_textdate;
  } else if (itm.match(/^[£$]/)) {
    sortfn = ts_sort_currency;
  } else if (itm.match(/^[\d\.]+$/)) {
    sortfn = ts_sort_numeric;
  } else {
    sortfn = ts_sort_caseinsensitive;
  }
  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;&uarr;';
    newRows.reverse();
    span.setAttribute('sortdir','up');
  } else {
    ARROW = '&nbsp;&darr;';
    span.setAttribute('sortdir','down');
  }
    
  // 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 = '';
      }
    }
  }
        
  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_textdate(a,b) {
  aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
  bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
 
  re = /^(\w+) (\d\d), (\d\d\d\d)$/;

  if (aa == null && bb == null)
    return 0;
  else if (aa == null)
    return 1;
  else if (bb == null)
    return -1;

  a_data = aa.match(re);
  a_num = a_data[3] * 10000 + months[a_data[1]] * 100 + a_data[2];

  b_data = bb.match(re);
  b_num = b_data[3] * 10000 + months[b_data[1]] * 100 + b_data[2];

  return a_num-b_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]);
  
  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_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) { 
  var aaa, bbb;

  aaa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
  if (aaa == null) {
    aa = 999999999;
  } else {
    aa = parseFloat(aaa.replace(",",""));
  }
  
  bbb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
  if (bbb == null) {
    bb = 999999999;
  } else {
    bb = parseFloat(bbb.replace(",",""));
  }

  return aa-bb;
}

function ts_sort_caseinsensitive(a,b) {
  var a_text = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
  var b_text = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
  
  if (a_text == null)
    a_text = "9999-99-99";
  if (b_text == null)
    b_text = "9999-99-99";
  aa = a_text.toLowerCase();
  bb = b_text.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 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");
  }
} 
