
var isIE5up = (navigator.appVersion.indexOf("MSIE 5") > -1)
	|| (navigator.appVersion.indexOf("MSIE 6") > -1)
	|| (navigator.appVersion.indexOf("MSIE 7") > -1)
	|| (navigator.appVersion.indexOf("MSIE 8") > -1);

function getArrowUp() {
	var arrowUp = document.createElement("SPAN");
	arrowUp.innerHTML = "&nbsp;&#9650;";
	arrowUp.className = "arrow";
	return arrowUp;
}

function getArrowDown() {
	var arrowDown = document.createElement("SPAN");
	arrowDown.innerHTML = "&nbsp;&#9660;";
	arrowDown.className = "arrow";
	return arrowDown;
}

function sortTable (tableNode, nCol, nDataCol, bDesc) {
	var tBody = tableNode.tBodies[0];
	var trs = tBody.childNodes;
	var a = new Array();

	var j = 0;
	for (var i=0; i<trs.length; i++) {
		if (trs[i].tagName == "TR") {
			a[j] = trs[i];
			j++;
		}
	}

	a.sort(compareByColumn(nCol,nDataCol,tableNode.tHead.rows[0].cells[nDataCol].className,bDesc));

	for (var i=0; i<a.length; i++) {
		tBody.appendChild(a[i]);
	}
}

function compareByColumn (nCol, nDataCol, className, bDescending) {
	var c = nCol;
	var cData = nDataCol;
	var dataType = className;
	var d = bDescending;

	function _compare (n1, n2) {
		var v;
		var t1 = getInnerText(n1.cells[cData]);
		var t2 = getInnerText(n2.cells[cData]);
		if (dataType == "float") {
			var n1num = Number(t1);
			var n2num = Number(t2);
			if (isNaN(n1num))
				v = (d) ? -1 : +1;
			else if (isNaN(n2num))
				v = (d) ? +1 : -1;
			else if (n1num < n2num)
				v = (d) ? -1 : +1;
			else if (n1num > n2num)
				v = (d) ? +1 : -1;
			else 
				v = 0;
		} else if (dataType == "date") {
			var splitChar, posD, posM, posY;
			if (t1.indexOf("/") != -1) {
				/* MM/DD/YYYY */
				splitChar = "/";
				posD = 1;
				posM = 0;
				posY = 2;
			} else if (t1.indexOf(".") != -1) {
				/* DD. MM. YYYY */
				splitChar = ".";
				posD = 0;
				posM = 1;
				posY = 2;
			}
			var arr1 = t1.split(splitChar);
			var arr2 = t2.split(splitChar);
			var date1 = new Date(arr1[posY], arr1[posM]-1, arr1[posD]);
			var date2 = new Date(arr2[posY], arr2[posM]-1, arr2[posD]);

			if (date1 < date2)
				v = (d) ? -1 : +1;
			else if (date1 > date2)
				v = (d) ? +1 : -1;
			else {
				/* Look at hours etc. as well. Also helps sort misformatted dates. */
				var hour1 = t1.substr(t1.indexOf(" ")+1);
				var hour2 = t2.substr(t2.indexOf(" ")+1);
				if (hour1 < hour2)
					v = (d) ? -1 : +1;
				else if (hour1 > hour2)
					v = (d) ? +1 : -1;
				else
					v = 0;
			}
		} else {
			/* text */
			if (t1 < t2)
				v = (d) ? -1 : +1;
			else if (t1 > t2)
				v = (d) ? +1 : -1;
			else 
				v = 0;
		}
		/*
		alert("n1: " + getInnerText(n1.cells[cData]) + "\nn2: " + getInnerText(n2.cells[cData]) + "\nv: " + v);
		*/
		return v;
	}

	return _compare;
}

var last;

function sortColumn (e) {
	var tmp, el, tHeadParent;

	tmp = (isIE5up) ? e.srcElement : e.target;

	tHeadParent = getParent(tmp, "THEAD");
	if (tHeadParent.getAttribute("first") != "0")
		tHeadParent.setAttribute("first", "1");
	el = getParent(tmp, "TD");

	if (tHeadParent == null)
		return;

	if (el != null) {
		var p = el.parentNode;
		var i;

		if (el._descending)	/* catch the null */
			el._descending = false;
		else
			el._descending = true;

		if (tHeadParent.getAttribute("first") == "0") {
			if (tHeadParent.arrow.parentNode != el) {
				tHeadParent.arrow.parentNode._descending = null;	/* reset sort order */
			}
			last.removeChild(last.lastChild);
		}

		if (el._descending)
			tHeadParent.arrow = getArrowUp();
		else
			tHeadParent.arrow = getArrowDown();

		el.appendChild(tHeadParent.arrow);

		/* get the index of the td */
		var j = -1;
		for (i=0; i<p.childNodes.length; i++) {
			if (p.childNodes[i].tagName == "TD") {
				j++;
				if (p.childNodes[i] == el) break;
			}
		}

		var table = getParent(el, "TABLE");
		/* can't fail */

		sortTable(table,i,j,el._descending);
	}
	tHeadParent.setAttribute("first", "0");
	last = el;
}


function getInnerText (el) {
	if (isIE5up) return el.innerText.toLowerCase();	/* Not needed but it is faster */

	var str = "";

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

	return str;
}

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


