// ################################################################
// ## collapse / expand functions                                ##
// ################################################################

	var sortBy="";
	var oldCol = "";
	var oldFn = "";
	var oldTable = "";

	//public function (add description)
	function collapseTableColumn(tableName, columnNumber, startPos, endPos) {
		tableObject = getObject(tableName);
		startPos = (startPos) ? startPos : 0;
		columnLength = tableObject.rows.length;
		endPos = (endPos) ? (endPos) : columnLength;
		for (var j=startPos; j < endPos; j++) {
			tableDataContent = tableObject.rows[j].cells[columnNumber].getElementsByTagName("DIV");
			tableDataContent[0].style.display = "none"; tableDataContent[0].style.paddingLeft = "0px"; tableDataContent[0].style.paddingRight = "0px";
			tableDataContent[1].style.display = "block"; tableDataContent[1].style.paddingLeft = "0px"; tableDataContent[1].style.paddingRight = "0px";
		}
		arrayElement = "c" + "." + tableName + "." + columnNumber;
 		if (!inArray(hiddenColumns, arrayElement)) {
 			arrayElement = arrayElement + "." + startPos + "." + endPos;
 			hiddenColumns[hiddenColumns.length] = arrayElement;
 		}
	}

	//public function (add description)
	function expandTableColumn(tableName, columnNumber, startPos, endPos) {
		tableObject = getObject(tableName);
		startPos = (startPos) ? startPos : 0;
		columnLength = tableObject.rows.length;
		endPos = (endPos) ? (endPos) : columnLength;
		for (var j=startPos; j < endPos; j++) {
			elementStatus = nextElementStatus("expand", "column", tableName, j, columnNumber, startPos, endPos-1);
			if (elementStatus == "block") {
				tableDataContent = tableObject.rows[j].cells[columnNumber].getElementsByTagName("DIV");
				tableDataContent[0].style.display = "block"; tableDataContent[0].style.paddingLeft = "5px"; tableDataContent[0].style.paddingRight = "5px";
				tableDataContent[1].style.display = "none"; tableDataContent[1].style.paddingLeft = "5px"; tableDataContent[1].style.paddingRight = "5px";
			}
 		}
 		excludeFromArray(hiddenColumns, "c" + "." + tableName + "." +  columnNumber + "." + startPos + "." + endPos);
	}

// =================== Private Section ===================

	//global variables (add description)
	var hiddenRows = new Array();
	var hiddenColumns = new Array();
	var serializedHiddenRows = new String("");
	var serializedHiddenColumns = new String("");

	//private function (add description)
	function getObject(objectName) {
		return document.getElementById(objectName);
	}
	
	//private function (add description)
	function inArray(arrayObject, searchedObject) {
		var tempString;
		var arrayLength = arrayObject.length;
		if (arrayLength == 0) {
			return false;
		}
		for (var i=0; i<arrayLength; i++) {
			tempString = arrayObject[i].split(".");
			tempString = tempString[0] + "." + tempString[1] + "." + tempString[2];
			if (tempString == searchedObject) {
				return true;
			}
		}
		return false;
	}

	//private function (add description)
	function excludeFromArray(arrayObject, excludeObject) {
		var arrayLength = arrayObject.length;
		if (arrayLength == 0){
			return;
		}
		if (arrayLength == 1) {
			if (arrayObject[0] == excludeObject) {
				arrayObject.length = 0;
			}
			return;
		}
		for (var i=0; i<(arrayLength-1); i++) {			
			if (arrayObject[i] == excludeObject) {
				arrayObject[i] = arrayObject[arrayLength-1];
				arrayObject.length = arrayLength - 1;
				return;
			}
		}
		arrayObject.length = arrayLength - 1;
		return;
	}

	//private function (add description)
	function nextElementStatus(operationType, functionType, tableName, rowNumber, columnNumber, startPos, endPos) {
		var returnStatus = "block";
		var prefix = (operationType == "show") ? "h" : "c";
		switch (functionType) {
			case "row" :
				ifStatement = inArray(hiddenColumns, prefix + "." + tableName + "." + columnNumber);
				break;
			case "column" :
				ifStatement = inArray(hiddenRows, prefix + "." + tableName + "." + rowNumber);
				break;
			default :
				alert("Undefined Switch Case or Function Not Implemented (nextElementStatus 1)!!!");
		}
		if (ifStatement) {
			returnStatus = "none";
			switch (operationType) {
				case "show" :
					tableObject = getObject(tableName);
					tableDataContent = tableObject.rows[rowNumber].cells[columnNumber].getElementsByTagName("DIV");
					if (tableDataContent[0]) {
						returnStatus = "block";
					}
					break;
				case "expand" :
					break;
				default :
					alert("Undefined Switch Case or Function Not Implemented (nextElementStatus 2)!!!");
			}
		}
		return returnStatus;
	}
	
	
// ################################################################
// ## Table sorting functions                                    ##
// ################################################################

addEvent(window, "load", sortables_init);

var SORT_COLUMN_INDEX;

// simple browser detect
var ie4 = document.all;
var ns4 = document.layers;
var ns6 = document.getElementById && !document.all; 

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);
			thisTblId = thisTbl.getAttribute('id').toString();
			
			// sort the table on entry to the page, by first sortable column ie. row[0].cells[1]
			initialSort = parseInt(thisTbl.getAttribute('initialSort'));
			//ts_resortTable(document.getElementById(thisTblId).rows[0].cells[initialSort], initialSort,thisTblId);
			
			// hide the filter dropdowns if in netscape - in row[2]
			//if(ns4 || ns6) document.getElementById(thisTblId).rows[2].style.display = 'none';
			hideFilters(thisTbl); // see if any filters need to be hidden on this table

			ts_makeSortable(thisTbl,thisTblId);
			//ts_makeFilterable(thisTbl,thisTblId);
        }		
    }
	ts_resortTableNew();
}

function hideFilters(thisTbl){
	// hide the filter dropdowns - in row[2]
	nonFilterable = parseInt(thisTbl.getAttribute('nonFilterable'));
	filterRow = document.getElementById(thisTblId).rows[2];
	if(ns4 || ns6){ // hide entire row if in netscape
		filterRow.style.display = 'none';
	}else{ // check nonFilterable attribute, hide as appropriate
		if(nonFilterable && nonFilterable > 0 && nonFilterable != filterRow.cells.length){ // turn off individual filter dropdowns
			for(nf=0; nf<nonFilterable; nf++){
				filterRow.cells[nf].innerHTML = '&nbsp;';
			}
		}else if(nonFilterable && nonFilterable > 0 && nonFilterable == filterRow.cells.length){ // hide entire row, all filters are off
			filterRow.style.display = 'none';
		}
	}
}


function ts_makeSortable(table,tableId) {

	// get number of cols (from left->right) to make non expandable
	nonExpandable = parseInt(table.getAttribute('nonExpandable'));

	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);
		var myHTML = "";
		if(txt == ''){
			cell.innerHTML = '';
		} else {
			txt1 = _TF_trimWhitespace(txt.toString());
			index = txt1.indexOf("Hide#");
			
			if(i==0){

				if(i >= nonExpandable) myHTML += '<div style="display:block;" class="Thd"><a href="javascript:void(0);"><img src="/shared/images/minus.gif" width="10" height="10" border="0" alt="Hide" onClick="collapseTableColumn(\''+tableId+'\', '+i+');"></a><br><br>';
									
				myHTML += txt;
					
				if(i >= nonExpandable) myHTML += '</div><div style="display: none;" class="Thd"><a href="javascript:void(0);"><img src="/shared/images/plus.gif" width="10" height="10" border="0" alt="Unhide" onClick="expandTableColumn(\''+tableId+'\', '+i+')"></a></div>';
						cell.innerHTML = myHTML;

			}else{
				if (index>-1){
					index = (parseInt(index)+5);
					
					if(i >= nonExpandable) myHTML += '<div style="display:block;" class="Thd"><a href="javascript:void(0);"><img src="/shared/images/minus.gif" width="10" height="10" border="0" alt="Hide" onClick="collapseTableColumn(\''+tableId+'\', '+i+');"></a><br><br>';
									
					myHTML += txt1.substring(index,txt1.length);
					
					if(i >= nonExpandable) myHTML += '</div><div style="display: none;" class="Thd"><a href="javascript:void(0);"><img src="/shared/images/plus.gif" width="10" height="10" border="0" alt="Unhide" onClick="expandTableColumn(\''+tableId+'\', '+i+')"></a></div>';
						cell.innerHTML = myHTML;
				}else{
					
					if(i >= nonExpandable) myHTML += '<div style="display:block;" class="Thd"><br><br>'+txt1+'</div>';
					
					if(i >= nonExpandable) myHTML += '</div><div style="display: none;" class="Thd"><br><br>'+txt1+'</div>';
					//myHTML += '<BR><BR>'+txt1;
					cell.innerHTML = myHTML;
				}
			}
			
		}
	}
}

// function: used by filtering also, so best not to delete
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;
}

if (document.images){			
	arrowUpImg = new Image();
	arrowUpImg.src = "/shared/images/arrow_up_moss.gif";
	arrowUpImg_fade = new Image();
	arrowUpImg_fade.src = "/shared/images/arrow_up_moss_fade.gif";
	
	arrowDownImg = new Image();
	arrowDownImg.src = "/shared/images/arrow_down_moss.gif";
	arrowDownImg_fade = new Image();
	arrowDownImg_fade.src = "/shared/images/arrow_down_moss_fade.gif";
}

function rollArrow(lnk,dir,state){
	if (document.images){
		if(lnk.parentNode.getAttribute("sortdir") != false){ // active checks whether col is currently sorted with that arrow, if it is, we dont rollover
			//if(dir == "up") lnk.firstChild.src = eval("arrowUpImg" + state + ".src");
			//if(dir == "down") lnk.firstChild.src = eval("arrowDownImg" + state + ".src");
		}
	}
}

// new table - start
function ts_resortTableNew() {	
  var allspans = document.getElementsByTagName("span");
    for (var ci=0;ci<allspans.length;ci++) {		
		if (allspans[ci].className == 'sortarrow') {
            			allspans[ci].childNodes[0].innerHTML = '<img src="/shared/images/arrow_up_moss_fade.gif"  alt="Ascending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
						allspans[ci].childNodes[0].setAttribute('active',false);						
						allspans[ci].childNodes[2].innerHTML = '<img src="/shared/images/arrow_down_moss_fade.gif" alt="Descending" width="10" height="10" border="0" style="position: relative; top: 2px;">';						
						allspans[ci].childNodes[2].setAttribute('active',false);					
	    }
    }
}
// new table - end

// This function is similar to ts_resortTable except parameters, extra parameters are added 
// for number of rows & columns to be left
function ts_resorttable(lnk,colNum,tableName,sortdir,escpRow,escpCol) {	
     
    // get the span
    var span;
	var spanSort;
	sortBy = sortdir;

	for (var ci=0;ci<lnk.childNodes.length;ci++) {
		if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') {
			span = lnk.childNodes[ci];
		}
	}
   
   /*
	lnkSort = document.getElementById(tableName).rows[1].cells[colNum].firstChild.firstChild;
	for (var cj=0;cj<lnkSort.childNodes.length;cj++) {
		if (lnkSort.childNodes[cj].tagName && lnkSort.childNodes[cj].tagName.toLowerCase() == 'span'){
			spanSort = lnkSort.childNodes[cj];
		}
	}
	*/

	anchorUp = document.getElementById(tableName).rows[escpRow].cells[colNum].firstChild.firstChild.childNodes[0]; // first <a> tag
	// a couple of &nbsp; exist between the two <a> tags, so we skip childNodes[1]
	anchorDown = document.getElementById(tableName).rows[escpRow].cells[colNum].firstChild.firstChild.childNodes[2]; // second <a> tag

		
	if(!span){
		span = document.getElementById(tableName).rows[0].cells[colNum];
		//sortBy = span;
	}
	
    var spantext = ts_getInnerText(span);
    
    var td = lnk.parentNode;
	var column = colNum;
    var table = getParent(td,'TABLE');

    // Work out a type for the column
    if (table.rows.length <= escpCol) return;

	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].childNodes[0].innerHTML = 'Updating';
				}		
        }
    }

    var itmStr = "";
	var numericFn= false;
	var rangeFn = false;
	var dateFn = false;
	var stringFn = false;
	var currencyFn = false;

	// find the datatype with these regexps
	sortfn = ts_sort_caseinsensitive; // default data type
	
		
	for (var index=escpCol; index<table.rows.length; index++)
	{
		itmStr = _TF_trimWhitespace(ts_getInnerText(table.rows[index].cells[column])); // takes a sample data from the first content row				
			
		if(itmStr!=""){			
			// take first line as sample data only, and strip any \n \r characters
			itm = itmStr.toString().split("\n"); itm = itm[0]; // split on \n
			itm = itmStr.toString().split("\r"); itm = itm[0]; // split on \r
			itm = _TF_trimWhitespace(itm); // remove any whitespace
           
			if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) dateFn = true; // is the itm a date?
			if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) dateFn = true; // is the itm a date?
			if (itm.match(/^[£$€¥]/)) currencyFn = true; // is the itm money?
			if (itm.match(/^[\d\.]+$/)) numericFn = true; // is the itm simply a number?	
			if (itm.match(/^[-]?[\d\.]+[ ]([-@]|to)/)) rangeFn = true; // is the itm simply a range?
		}
	}
     
	//alert("itm["+index+"]  = "+itm);	 
	//alert("date["+index+"] = "+dateFn);

	if(stringFn == true){
		sortfn = ts_sort_caseinsensitive;
	} else if(rangeFn == true){
		sortfn = ts_sort_range;
	} else if(currencyFn == true){
		sortfn = ts_sort_currency;
	} else if(dateFn == true){

		sortfn = ts_sort_date;

	} else if(numericFn == true){
		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=escpCol;j<table.rows.length;j++){ 
		newRows[j-escpCol] = table.rows[j];
	}			
    

	
	span.setAttribute('sortdir',sortdir);
	
	if(!span.getAttribute("sortdir")){
		span.setAttribute('sortdir','down');
		//sortBy = span;
	}
	
    if (span.getAttribute("sortdir") == 'up') {
		newRows.sort(sortfn);
        arrowUp = '<img src="/shared/images/arrow_up_moss.gif" alt="Ascending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
		arrowDown = '<img src="/shared/images/arrow_down_moss_fade.gif" alt="Descending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
    	activeDown = true;
		activeUp = false;
	} else {
        arrowUp = '<img src="/shared/images/arrow_up_moss_fade.gif" alt="Ascending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
		arrowDown = '<img src="/shared/images/arrow_down_moss.gif" alt="Descending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
		activeDown = false;
		activeUp = true;		

		if(oldCol != colNum || oldFn !='down' || oldTable!=tableName){
			newRows.sort(sortfn);
			newRows.reverse();
		}
    }

	oldCol = colNum;
	oldFn = span.getAttribute("sortdir");
    oldTable = tableName;
		
	span.setAttribute('oldSort',span.getAttribute("sortdir"));
	span.setAttribute('oldCol',colNum);

    // 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]);}

	    
    // Fade all other arrows
	initialSort = parseInt(document.getElementById(tableName).getAttribute('initialSort'));
    //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].childNodes[0].innerHTML = '<img src="/shared/images/arrow_up_moss_fade.gif"  alt="Ascending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
						allspans[ci].childNodes[0].setAttribute('active',false);						
						allspans[ci].childNodes[2].innerHTML = '<img src="/shared/images/arrow_down_moss_fade.gif" alt="Descending" width="10" height="10" border="0" style="position: relative; top: 2px;">';						
						allspans[ci].childNodes[2].setAttribute('active',false);					
			}			
        }
    }   
	
    anchorUp.innerHTML = arrowUp; anchorUp.setAttribute('active',activeUp);
    anchorDown.innerHTML = arrowDown; anchorUp.setAttribute('active',activeDown);
		
	document.getElementById(tableName).setAttribute('currentSortCol', colNum); // keep a record of the col currently sorted on
	
	//alternateRowColor(table,colNum);

	
}// end of ts_resorttable


function ts_resortTable(lnk,colNum,tableName,sortdir) {	
    
    // get the span
    var span;
	var spanSort;
	sortBy = sortdir;

	for (var ci=0;ci<lnk.childNodes.length;ci++) {
		if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') {
			span = lnk.childNodes[ci];
		}
	}
   
   /*
	lnkSort = document.getElementById(tableName).rows[1].cells[colNum].firstChild.firstChild;
	for (var cj=0;cj<lnkSort.childNodes.length;cj++) {
		if (lnkSort.childNodes[cj].tagName && lnkSort.childNodes[cj].tagName.toLowerCase() == 'span'){
			spanSort = lnkSort.childNodes[cj];
		}
	}
	*/

	anchorUp = document.getElementById(tableName).rows[3].cells[colNum].firstChild.firstChild.childNodes[0]; // first <a> tag
	// a couple of &nbsp; exist between the two <a> tags, so we skip childNodes[1]
	anchorDown = document.getElementById(tableName).rows[3].cells[colNum].firstChild.firstChild.childNodes[2]; // second <a> tag

	if(!span){
		span = document.getElementById(tableName).rows[0].cells[1];
		//sortBy = span;
	}
	
    var spantext = ts_getInnerText(span);
    var td = lnk.parentNode;
	var column = colNum;
    var table = getParent(td,'TABLE');

    // Work out a type for the column
    if (table.rows.length <= 5) return;

	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].childNodes[0].innerHTML = 'Updating';
				}		
        }
    }

    var itmStr = "";
	var numericFn= false;
	var rangeFn = false;
	var dateFn = false;
	var stringFn = false;
	var currencyFn = false;

	// find the datatype with these regexps
	sortfn = ts_sort_caseinsensitive; // default data type
	
	for (var index=5; index<table.rows.length; index++)
	{
		itmStr = _TF_trimWhitespace(ts_getInnerText(table.rows[index].cells[column])); // takes a sample data from the first content row				
			
		if(itmStr!=""){			
			// take first line as sample data only, and strip any \n \r characters
			itm = itmStr.toString().split("\n"); itm = itm[0]; // split on \n
			itm = itmStr.toString().split("\r"); itm = itm[0]; // split on \r
			itm = _TF_trimWhitespace(itm); // remove any whitespace

			if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) dateFn = true; // is the itm a date?
			if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) dateFn = true; // is the itm a date?
			if (itm.match(/^[£$€¥]/)) currencyFn = true; // is the itm money?
			if (itm.match(/^[\d\.]+$/)) numericFn = true; // is the itm simply a number?	
			if (itm.match(/^[-]?[\d\.]+[ ]([-@]|to)/)) rangeFn = true; // is the itm simply a range?
		}
	}
    
	

	if(stringFn == true){
		sortfn = ts_sort_caseinsensitive;
	} else if(rangeFn == true){
		sortfn = ts_sort_range;
	} else if(currencyFn == true){
		sortfn = ts_sort_currency;
	} else if(dateFn == true){
		sortfn = ts_sort_date;
	} else if(numericFn == true){
		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=5;j<table.rows.length;j++){ 
		newRows[j-5] = table.rows[j];
	}			
    

	span.setAttribute('sortdir',sortdir);
	
	if(!span.getAttribute("sortdir")){
		span.setAttribute('sortdir','down');
		//sortBy = span;
	}
	

    if (span.getAttribute("sortdir") == 'up') {
		newRows.sort(sortfn);
        arrowUp = '<img src="/shared/images/arrow_up_moss.gif" alt="Ascending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
		arrowDown = '<img src="/shared/images/arrow_down_moss_fade.gif" alt="Descending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
    	activeDown = true;
		activeUp = false;
	} else {
        arrowUp = '<img src="/shared/images/arrow_up_moss_fade.gif" alt="Ascending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
		arrowDown = '<img src="/shared/images/arrow_down_moss.gif" alt="Descending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
		activeDown = false;
		activeUp = true;		

		if(oldCol != colNum || oldFn !='down' || oldTable!=tableName){
			newRows.sort(sortfn);
			newRows.reverse();
		}
    }

	oldCol = colNum;
	oldFn = span.getAttribute("sortdir");
    oldTable = tableName;
		

    
	span.setAttribute('oldSort',span.getAttribute("sortdir"));
	span.setAttribute('oldCol',colNum);

    // 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]);}
    
    // Fade all other arrows
	initialSort = parseInt(document.getElementById(tableName).getAttribute('initialSort'));
    //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].childNodes[0].innerHTML = '<img src="/shared/images/arrow_up_moss_fade.gif"  alt="Ascending" width="10" height="10" border="0" style="position: relative; top: 2px;">';
						allspans[ci].childNodes[0].setAttribute('active',false);						
						allspans[ci].childNodes[2].innerHTML = '<img src="/shared/images/arrow_down_moss_fade.gif" alt="Descending" width="10" height="10" border="0" style="position: relative; top: 2px;">';						
						allspans[ci].childNodes[2].setAttribute('active',false);					
						
				}
			
        }
    }   

    anchorUp.innerHTML = arrowUp; anchorUp.setAttribute('active',activeUp);
    anchorDown.innerHTML = arrowDown; anchorUp.setAttribute('active',activeDown);
	
	document.getElementById(tableName).setAttribute('currentSortCol', colNum); // keep a record of the col currently sorted on
	alternateRowColor(table,colNum);
}

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_date(a,b) {
	//alert("a->"+a);
	//alert("b->"+b);
	
    aa = _TF_trimWhitespace(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));
    bb = _TF_trimWhitespace(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]));
    
   // alert("aa->"+aa);
   // alert("bb->"+bb);
    
 	if (aa.length == 10) {
        dt1 = aa.substr(6,4)+aa.substr(0,2)+aa.substr(3,2);
       // alert("dt1->"+dt1);
    }else if (aa.length == 9) {
        dt1 = aa.substr(5,4)+aa.substr(0,1)+aa.substr(2,2);
       // alert("dt1->"+dt1); 
		
	}else {
        if(aa.length ==1){
		//do nothing
		}else{ 	
		alert(aa+"\nMake sure date format is mm/dd/yyyy");
		}
    }
    if (bb.length == 10) {
        dt2 = bb.substr(6,4)+bb.substr(0,2)+bb.substr(3,2);
        //alert("dt2->"+dt2);
    }else if (bb.length == 9) {
        dt2 = bb.substr(5,4)+bb.substr(0,1)+bb.substr(2,2);
        //alert("dt2->"+dt2); 
		
	} else {
       if(bb.length ==1){
		//do nothing
		}else{ 	
		alert(aa+"\nMake sure date format is mm/dd/yyyy");
		}

        //alert(bb+"\nMake sure date format is mm/dd/yyyy");
    }
    
   // alert("dt1="+dt1);
   // alert("dt2="+dt2);
        
    if (dt1==dt2){
		myReturn = 0;
	}else if (dt1<dt2){
		myReturn = -1;
	}else{
    	myReturn = 1;
	}
	return myReturn;
}

function getText(txt){
	var finaltxt = "";
	var txtArray = "";
	txtArray = txt.toString().split("\n");
	for(var i=0; i<txtArray.length; i++){
		finaltxt = finaltxt + txtArray[i];
	}

	return finaltxt;
}


function getNo(no, type){
	var nos = "";
	var sortNoBy = sortBy;
	nos = no.toString().split("\n");
	if(sortNoBy=='down'){
		return getMinNo(nos, type);
	}else {
		return getMaxNo(nos, type);	
	}
}

function getMinNo(nos, type){
	var minno="";
	if(type=='no') {
		minno = nos[0];
		for(var i=0; parseFloat(i)<parseFloat(nos.length); i++){
			if(parseFloat(nos[i]) < parseFloat(minno)) {
				minno = nos[i];
			}
		}
	}else{
		token = nos[0].toString().split(" ");
		minno = token[0];	
		for(var i=0; parseFloat(i)<parseFloat(nos.length); i++){
			nexttoken = nos[i].toString().split(" ");
			if(parseFloat(nexttoken [0]) < parseFloat(minno)) {
				minno = nexttoken [0];
			}
		}
	}

	return minno;
}

function getMaxNo(nos, type){
	var maxno="";
	if(type=='no') {
		maxno = nos[0];
		for(var i=0; parseFloat(i) < parseFloat(nos.length); i++){
			if(parseFloat(nos[i]) > parseFloat(maxno)) {
				maxno = nos[i];
			}
		}

	}else{
		token = nos[0].toString().split(" ");
		maxno = token[0];	
		for(var i=0; parseFloat(i) < parseFloat(nos.length); i++){
			nexttoken = nos[i].toString().split(" ");
			if(parseFloat(nexttoken[0]) > parseFloat(maxno)) {
				maxno = nexttoken[0];
			}
		}
	}
	return maxno;
}

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 = getNo(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]),'no');
	} else {
      aa = 0;
	}

    bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])); 
	if (!isNaN(bb)) {
	  bb = getNo(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]),'no'); 
	} else {
	  bb = 0;
	}

    return aa-bb;
}

function ts_sort_caseinsensitive(a,b) {
    aa = getText(_TF_trimWhitespace(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase()));
    bb = getText(_TF_trimWhitespace(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 = getText(_TF_trimWhitespace(ts_getInnerText(a.cells[SORT_COLUMN_INDEX])));
    bb = getText(_TF_trimWhitespace(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])));
    if (aa==bb) return 0;
    if (aa<bb) return -1;
    return 1;
}

function ts_sort_range(a,b) {
	
    aa = parseFloat(getNo(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]), 'range'));
    bb = parseFloat(getNo(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]), 'range'));	
	if (isNaN(aa)) {
		aa=0;
	}

	if (isNaN(bb)) {
		bb=0;
	}
	

	return aa-bb;
}


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");
  }
} 

// ################################################################
// ## Filtering functions                                        ##
// ################################################################

/** PRIVATE FUNCTIONS **/
function _TF_trimWhitespace(txt) {
	var strTmp = txt;
	//trimming from the front
	for (counter=0; counter<strTmp.length; counter++)
		if (strTmp.charAt(counter) != " ")
			break;
	//trimming from the back
	strTmp = strTmp.substring(counter,strTmp.length);
	counter = strTmp.length - 1;
	for (counter; counter>=0; counter--)
		if (strTmp.charAt(counter) != " ")
			break;
	return strTmp.substring(0, counter+1);
}

function _TF_showAll(tb) {
	for (i=0;i<tb.rows.length;i++)
	{
		tb.rows[i].style.display = "";
	}
}

function TF_showAll(tb) {
	for (i=0;i<tb.rows.length;i++)
	{
		tb.rows[i].style.display = "";
	}
}

function _TF_shouldShow(type, con, val) {
	var toshow = false;
	if (type != null) type = type.toLowerCase();
			
			con = _TF_trimWhitespace(con.toString()); // trim any possible whitespace

			valArray = val.toString().split("\n");
			
			for(x=0; x<valArray.length; x++){
				valSingle = valArray[x];
				valSingle = valSingle.replace(/\r/, ""); // strip out the \r carriage returns
				valSingle = _TF_trimWhitespace(valSingle); // then remove any whitespace
				if(toshow == false){ // give a chance to prove that its true
					if(valSingle == con){
						toshow = true; // we have a match! no need to loop thru this for()
					}
					
					for(y=0; y<valSingle.length; y++){
						testChar = valSingle.substr(y,1);
					}
				}
			}			
	return toshow;
}

function _TF_filterTable(tb, conditions) {
	//given an array of conditions, lets search the table
	for (i=0;i<tb.rows.length;i++){ // loop thru table rows
		var show = true;
		var rw = tb.rows[i];
		for (j=0;j<rw.cells.length;j++){ // loop thru cells on this row
			var cl = rw.cells[j];
			for (k=0;k<conditions.length;k++){
				var colKey = cl.getAttribute("TF_colKey");
				if (colKey == null) //attribute not found
					continue; //so lets not search on this cell.
				if (conditions[k].name.toUpperCase() == colKey.toUpperCase())
				{
					var tbVal = ts_getInnerText(cl);
					var conVals = conditions[k].value;
					if (conditions[k].single) //single value
					{ 
						show = _TF_shouldShow(conditions[k].type, conditions[k].value, tbVal);
					} else { //multiple values
						for (l=0;l<conditions[k].value.length;l++)
						{
							innershow = _TF_shouldShow(conditions[k].type, conditions[k].value[l], tbVal);
							if (innershow == true) break;
						}
						if (innershow == false)
							show = false;
					}
				}
			}
			//if any condition has failed, then we stop the matching (due to AND behaviour)
			if (show == false)
				break;
		}
		if (show == true)
			tb.rows[i].style.display = "";
		else
			tb.rows[i].style.display = "none";
	}

	currentSortCol = tb.getAttribute("currentSortCol");
	alternateRowColor(tb, currentSortCol);
}

/** PUBLIC FUNCTIONS **/
//main function
function TF_filterTable(tb, frm) {
	
	var conditions = new Array();
	if (frm.style.display == "none") //filtering is off
		return _TF_showAll(tb);

	var inputs = frm.getElementsByTagName("SELECT");
	//able to do multiple selection box

	for (i=0;i<inputs.length;i++){ //looping thru all SELECT elements
		if (inputs[i].getAttribute("TF_colKey") == null) //attribute not found
			continue; //we assume that this input field is not for us
		var opts = inputs[i].options;
		var optsSelected = new Array();
		for (intLoop=0; intLoop<opts.length; intLoop++){ //looping thru all OPTIONS elements
			if (opts[intLoop].selected && (opts[intLoop].getAttribute("TF_not_used") == null)){
				// gets the selected value
				index = optsSelected.length;
				optsSelected[index] = opts[intLoop].value;
			}
		}
		if (optsSelected.length > 0){ //has selected items
			index = conditions.length;
			conditions[index] = new Object;
			conditions[index].name = inputs[i].getAttribute("TF_colKey");
			conditions[index].type = inputs[i].getAttribute("TF_searchType");
			conditions[index].value = optsSelected;
			conditions[index].single = false;
		}
	}
	//ok, now that we have all the conditions, lets do the filtering proper
	_TF_filterTable(tb, conditions);
}

function _TF_get_value(input) {
			 return input.value;
}

//util function that concat two input fields and set the result in the third
function TF_concat_and_set(salText, salSelect, salHidden) {
	var valLeft = _TF_get_value(salText);
	var valRight = _TF_get_value(salSelect);
	salHidden.value = valLeft + valRight;
}

// added by phil 12.02.04
// function: expands all columns / sorts on first sortable column / resets all filters
// requires: tableId - value of table's id attribute
function resetTable(tableId, formId){	
	tableObject = getObject(tableId);
	if(!ns4 && !ns6){
		// #### RESET THE FILTERS ################################################
		numCols = tableObject.rows[0].cells.length; // how many columns are in the table?
		numCols -= 2; // minus the product and shopping basket icon columns, leaves us with filterable cols only
		for(i=0;i<=numCols;i++){
			if(document.forms[formId]['select'+i]){
					document.forms[formId]['select'+i].selectedIndex = 0; // but the rest of em do
			}
		}
		TF_filterTable(this[tableId], this[formId]); // call function to re-filter the table
	}
	
	// #### RESET THE EXPANDING COLUMNS ################################################
	
	// get number of cols (from left->right) to make non expandable
	nonExpandable = parseInt(tableObject.getAttribute('nonExpandable'));
	
	numCols = tableObject.rows[0].cells.length; // how many columns are in the table?
	numCols -= 1; // minus the shopping basket icon column, leaves us with expandable cols only
	
	for(i=nonExpandable;i<=numCols;i++){
		expandTableColumn(tableId, i); // expand those columns
	}
	
	// #### RESET THE SORTING ################################################
	//ts_resortTable(document.getElementById(tableId).rows[0].cells[1], 1,tableId);
}

function alternateRowColor(table, hiLiteCol){
	k=0;
	for(i=0; i<table.rows.length; i++){
		rowtype = table.rows[i].getAttribute("rowtype").toLowerCase();
		if(rowtype == "content" && table.rows[i].style.display == ""){
			for(j=0; j<table.rows[i].cells.length; j++){
				if(k%2 == 0){ // use k instead of i, so the top row is always 'Thw' regardless of how many header rows
					table.rows[i].cells[j].className = "Thw";
					if(j == hiLiteCol){
						table.rows[i].cells[j].className = "Thw_hi";
					}
				}else{
					table.rows[i].cells[j].className = "Thg";
					if(j == hiLiteCol){
						table.rows[i].cells[j].className = "Thg_hi";
					}
				}
			}
			k++;
		}		
	}	
}


function addNewOption(selectId, val){
	if(!ns4 && !ns6) {
		flag = true;
		for(i=0; i<selectId.length; i++){
			if(selectId.options[i].value==val){
				flag = false;
				break;
			}
		}

		if(flag){
			optionName = new Option(val,val);
			selectId.options[selectId.length]=optionName;
		}
	}	
}

function refreshForm(){
	document.resetTable.submit();
}

function resetTable(frm){
  document.DocumentationList.method="post";
  document.DocumentationList.action="/sps/library/documentationlist.jsp?rootNodeId="+DocumentationListNew.rootNodeId.value+"&nodeId="+DocumentationListNew.nodeId.value+"&Device="+DocumentationListNew.Device.value+"&Results="+DocumentationListNew.Results.value; 
  document.DocumentationList.submit();
}


//Change by r1610z for WR 2474 START 02/01/2005
//Change by r1610z for CCT24499 START 26/07/05
function ts_resortType(sortBy,typeName,isAsc,setPara,maxresult,sAName){

  if(isAsc == 'up'){  
	isAsc='false';
  }
 if(isAsc == 'down'){ 
	isAsc='true';
 }
document.DocumentationList.method="post";
//document.DocumentationList.action="documentationlist.jsp?rootNodeId="+DocumentationList.rootNodeId.value+"&nodeId="+DocumentationListNew.nodeId.value+"&Device="+DocumentationList.Device.value+"&Results="+DocumentationList.Results.value+"&SortBy="+sortBy+"&TypeName="+typeName+"&IsAsc="+isAsc+setPara;
document.DocumentationList.action="documentationlist.jsp?rootNodeId="+DocumentationList.rootNodeId.value+"&nodeId="+DocumentationListNew.nodeId.value+"&Device="+DocumentationList.Device.value+"&Results="+maxresult+"&SortBy="+sortBy+"&TypeName="+typeName+"&IsAsc="+isAsc+setPara+sAName;

document.DocumentationList.submit();
}
//Change by r1610z for WR 2474 END 02/01/2005
//Change by r1610z for CCT24499 END 26/07/05
//Change by r1610z for WR 2475 START 02/01/2005
//Change by r1610z for CCT24499 START 26/07/05
function ts_resortTypeDOC(sortBy,typeName,isAsc,fname,sAName){
  if(isAsc == 'up'){
	isAsc='false';
  }
 if(isAsc == 'down'){ 
	isAsc='true';
 }
 
 if(fname =='ProductSummaryPage'){
	document.ProductSummaryPage.method="post";
	document.ProductSummaryPage.action="prod_summary.jsp?code="+document.ProductSummaryPage.code.value+"&nodeId="+document.ProductSummaryPage.nodeId.value+"&SortBy="+sortBy+"&TypeName="+typeName+"&IsAsc="+isAsc+sAName;
	document.ProductSummaryPage.submit();
 } else { 
	 if(fname =='OverviewPage'){	
		document.OverviewPage.method="post";
		document.OverviewPage.action="overview.jsp?nodeId="+document.OverviewPage.nodeId.value+"&SortBy="+sortBy+"&TypeName="+typeName+"&IsAsc="+isAsc+sAName;
		document.OverviewPage.submit();
	 }else{	
		document.ApplicationPage.method="post";
		document.ApplicationPage.action="application.jsp?nodeId="+document.ApplicationPage.nodeId.value+"&SortBy="+sortBy+"&TypeName="+typeName+"&IsAsc="+isAsc+sAName;
		document.ApplicationPage.submit();
	 }
 }

}
//Change by r1610z for WR 2475 END 02/01/2005
//Change by r1610z for CCT24499 END 26/07/05



