//usage onclick="return SortColumn.byNoCase(this)"
var SortColumn = function(){
	var defaultDirection = 'down';	//'up'|'down'
	function getSortFnc(type, index){
		var regEx;
		switch(type){
			case 'byDate':
				regEx = /\-/g;
				return function (n1,n2){
					var d1 = n1.cells[index];
					var d2 = n2.cells[index];
					if(!d1.sortKey)d1.sortKey = Date.parse(getInnerText(d1).replace(regEx, '/'));
					if(!d2.sortKey)d2.sortKey = Date.parse(getInnerText(d2).replace(regEx, '/'));
					var dif = d1.sortKey - d2.sortKey;
					if(dif < 0){
						return -1;
					}else if(dif > 0){
						return 1;
					}else{
						return 0;
					}
				};
			case 'byNoCase':
				return function(n1,n2){
					var d1 = n1.cells[index];
					var d2 = n2.cells[index];
					if(!d1.sortKey)d1.sortKey = getInnerText(d1).toUpperCase();
					if(!d2.sortKey)d2.sortKey = getInnerText(d2).toUpperCase();
					if(d1.sortKey < d2.sortKey){
						return -1;
					}else if(d1.sortKey > d2.sortKey){
						return 1;
					}else{
						return 0;
					}
				};
			case 'byNumber':
				regEx = /[^0-9\.]/g;
				return function (n1,n2){
					var d1 = n1.cells[index];
					var d2 = n2.cells[index];
					if(!d1.sortKey)d1.sortKey = (+getInnerText(d1).replace(regEx, ""));
					if(!d2.sortKey)d2.sortKey = (+getInnerText(d2).replace(regEx, ""));
					var dif = d1.sortKey - d2.sortKey;
					if(dif < 0){
						return -1;
					}else if(dif > 0){
						return 1;
					}else{
						return 0;
					}
				};
			case 'byCase':
			default:
				return function(n1,n2){
					var d1 = n1.cells[index];
					var d2 = n2.cells[index];
					if(!d1.sortKey)d1.sortKey = getInnerText(d1);
					if(!d2.sortKey)d2.sortKey = getInnerText(d2);
					if(d1.sortKey < d2.sortKey){
						return -1;
					}else if(d1.sortKey > d2.sortKey){
						return 1;
					}else{
						return 0;
					}
				};
		}
	}
	function getParent(el, pTagName) {
		if(el != null){
			if((el.nodeType == 1)&&
				(el.tagName.toUpperCase() == pTagName.toUpperCase())){
				return el;
			}else if(el.parentNode){
				return getParent(el.parentNode, pTagName);
			}
		}
		return null;
	}
	function getDecendentByTagName(el, dTagName) {
		var ndList;
		if(el.getElementsByTagName){
			ndList = el.getElementsByTagName(dTagName)
		}else if(el.all){
			ndList = el.all.tags(dTagName);
		}
		if(!ndList){
			ndList = [];
		}else if(typeof ndList.length == 'undefined'){
			ndList = [ndList];
		}
		return ndList;
	}
	function getInnerTextQ(el){	//IE and Opera 7
		return el.innerText;
	}
	function getInnerTextW(el){	//other DOM 2 browsers
		var str = "";
		for (var i=0; i<el.childNodes.length; i++) {
			switch (el.childNodes.item(i).nodeType){
				case 1:	//ELEMENT_NODE
					str += arguments.callee(el.childNodes.item(i));	//recursive call to this function
					break;
				case 3:	//TEXT_NODE
					str += el.childNodes.item(i).nodeValue;
					break;
				default:
					break;
			}
		}
		return str;
	}
	var getInnerText;

	function SortTable(rowAr, contRow){
		function getTableRows(){
			var a = [];
			for(var c = rowAr.length;c--;){
				a[c] = rowAr[c];
			}
			return a;
		}
		function SortColumn(index, conCell){
			function sortIt(){
				var tableEl = parentEl.parentNode;
				direction = (direction == 'up')?'down':'up';
				for(var c = contRow.length;c--;){
					contRow[c].displayOff();
				}
				if(!orderedRows)orderedRows = getTableRows().sort(getSortFnc(type, index));
				tableEl.removeChild(parentEl);
				if(direction == 'up'){
					for(var c = 0;c < orderedRows.length;c++){
						parentEl.appendChild(orderedRows[c]);
					}
				}else{
					for(var c = orderedRows.length;c--;){
						parentEl.appendChild(orderedRows[c]);
					}
				}
				tableEl.appendChild(parentEl);
				arrowParent.replaceChild(indicator['arrow'+direction],dispNode);
				dispNode = indicator['arrow'+direction];
				return false;
			}
			var direction = defaultDirection;
			var arrowParent, dispNode, orderedRows;
			var type = '';
			var indicator = {
				arrow:(arrow.cloneNode(true)),
				arrowup:(arrowUp.cloneNode(true)),
				arrowdown:(arrowDown.cloneNode(true))
			};
			var ndList = getDecendentByTagName(conCell, 'IMG');
			if((ndList)&&(ndList.length > 0)){
				dispNode = ndList[0];
				arrowParent = dispNode.parentNode;
			}else{
				arrowParent = conCell;
				dispNode = arrowParent.appendChild(indicator.arrow);
			}
			ndList = getDecendentByTagName(conCell, 'A');
			if((ndList)&&(ndList.length > 0)){
				for(var c = ndList.length;c--;){
					if(typeof ndList[c].onclick == 'function'){
						var s = ''+ndList[c].onclick;
						var i = s.indexOf('SortColumn');
						if(i >= 0){
							s = s.substring((i+11),s.length);
							type = s.substring(0,s.indexOf('('));
							ndList[c].onclick = sortIt;
							break;
						}
					}
				}
			}
			var parentEl = rowAr[0].parentNode;
			//orderedRows = getTableRows().sort(getSortFnc(type, index));
			this.displayOff = function(){
				if(indicator.arrow != dispNode){
					arrowParent.replaceChild(indicator.arrow, dispNode);
					dispNode = indicator.arrow;
				}
			}
			this.finalize = function(){
				var ndList = getDecendentByTagName(conCell, 'A');
				if((ndList)&&(ndList.length > 0)){
					for(var c = ndList.length;c--;){
						ndList[c].onclick = null;
					}
				}
				arrowParent = (ndList = (conCell =
				(this.arrow =
				(this.arrowup =
				(this.arrowdown =
				(dispNode = null))))));
			};
		}

		var temp;
		var arrow = document.createElement("SPAN");
		temp = document.createElement("IMG");
		temp.src = "images/sortBlank.gif";
		temp.alt = (temp.title = "");
		arrow.appendChild(temp);
		var arrowUp = document.createElement("SPAN");
		temp = document.createElement("IMG");
		temp.src = "images/sortUp.gif";
		temp.alt = (temp.title = "(Sorted Ascending)");
		arrowUp.appendChild(temp);
		var arrowDown = document.createElement("SPAN");
		temp = document.createElement("IMG");
		temp.src = "images/sortDown.gif";
		temp.alt = (temp.title = "(Sorted Descending)");
		arrowDown.appendChild(temp);
		temp = [];
		for(var c = 0;c < contRow.length;c++){
			temp[c] = new SortColumn(c, contRow[c]);
		}
		contRow = temp;
		temp = null;
		if(typeof finalizeMe != 'undefined'){
			finalizeMe(
				function(){
					for(var c = contRow.length;c--;){
						contRow[c].finalize();
						contRow[c] = null;
					}
					for(var c = rowAr.length;c--;){
						rowAr[c] = null;
					}
					arrowDown = (arrowUp = (arrow = (contRow = (rowAr = null))));

				}
			);
		}
	};

	function init(obj){
		var switchRow = getParent(obj, "TR");
		if((switchRow)&&(switchRow.cells)&&(switchRow.parentNode)&&
				  (switchRow.replaceChild)&&(switchRow.cloneNode)&&
				  (document.createElement)&&(switchRow.appendChild)){
			if(typeof switchRow.innerText != 'undefined'){
				getInnerText = getInnerTextQ;
			}else if(typeof switchRow.childNodes != 'undefined'){
				getInnerText = getInnerTextW;
			}
			if(getInnerText){
				var contTable = getParent(switchRow, "TABLE");
				if(contTable){
					var rowArr = [];
					var rowList;
					var ndList = getDecendentByTagName(contTable, 'TBODY');
					for(var c = ndList.length;c--;){
						rowList = getDecendentByTagName(ndList[c], 'TR');
						for(var i = rowList.length;i--;){
							rowArr[rowArr.length] = rowList[i];
						}
					}
					var switchCells = switchRow.cells;
					new SortTable(rowArr, switchCells);
					rowList = (ndList = (rowArr = null));
					return;
				}
			}

		}
		arguments.callee.byCase =
		(arguments.callee.byDate =
		(arguments.callee.byNoCase =
		(arguments.callee.byNumber = function(){return true;})));
	}
	init.byNumber = function(obj){
		init(obj);
		if(arguments.callee == init.byNumber){
			return obj.onclick();	//trigger the sorting for this cell by calling the dynamically generated onclick method that is now attached to the A element.
		}else{
			return true;	//script was disabled so fall back to server side.
		}
	}
	init.byNoCase = function(obj){
		init(obj);
		if(arguments.callee == init.byNoCase){
			return obj.onclick();
		}else{
			return true;
		}
	}
	init.byCase = function(obj){
		init(obj);
		if(arguments.callee == init.byCase){
			return obj.onclick();
		}else{
			return true;
		}
	}
	init.byDate = function(obj){
		init(obj);
		if(arguments.callee == init.byDate){
			return obj.onclick();
		}else{
			return true;
		}
	}
	return init;
}();