/*
 * ============================================================================
 *                   The ProQuality Inc.
 *         Rapid Efficent Low cost And Xtreme (RELAX)
 *	           Advanced Solutions Framework (ASF)
 *                  Cristian Teodorescu
 *                      Version 8.6
 * ============================================================================
 * 
 *    Copyright (C) 1999 The ProQuality Inc. Foundation. All rights reserved.
 * 
 * The use of this software in any form is strictly prohibited unless you have 
 * purchased a license from ProQuality Inc. or you have a software agreement with 
 * ProQuality Inc.
 * 
 * Redistributions of source code must retain copyright statements
 * and notices. Redistributions must also contain a copy of this
 * document.
 *
  THIS SOFTWARE IS PROVIDED BY PROQUALITY AND CONTRIBUTORS ``AS IS'' AND
  ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PROQUALITY OR ITS
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  DAMAGE.
    
 *
 */
var ScrollSortHandler = {
	all				:	{},
	selectedIndex	:	{},
	hilightedIndex	:	{},
	selectedIndexes	:	{},
	selectedRows	:	{},
	selectedTable	:	"",
	selectedRow		:	{},
	groups			:	{},
	formForSubmit	:	{},
	actionForSubmit	:	{},
	tableObject		:	{},
	tableColumnIdNames:	{},
	ieMaxHeight : function (elem, size)
	{
		//dbg("ieMaxHeight called");
		if(elem.scrollHeight > size)
		{
			return size + "px";
		}
		else
		{
			return "auto";
		}
	},
	setSelectedIndex:	function ( node, tableId , loadControlFactor ) 
	{	
		selectRow( tableId, node, loadControlFactor );
	},
	addToSelectedIndexes : function (id, rowIndex, row, loadInitialFactor )
	{				
		// dbg("\naddToSelectedIndexes" );
		var isSelected = ScrollSortHandler.isSelectedIndex(id,rowIndex); // Why not ask thes row itself, i.e. row.isSelected()?		
		if(ScrollSortHandler.all[id].isMultiSelect != null && ScrollSortHandler.all[id].isMultiSelect == true)
		{
			if( isSelected )
			{	
				if( loadInitialFactor != "initialLoad" )
				 delete ScrollSortHandler.selectedIndexes[id][rowIndex];
			}
			else
			{
			   var existingEl = false;
			   if( !isSelected && ScrollSortHandler.getSelectedIndexes(id).length > 0 ){
				 for( var i=0; i < ScrollSortHandler.getSelectedIndexes(id).length; i++ ){
				   if( ScrollSortHandler.getSelectedIndexes(id)[ i ] == rowIndex ){
				   		existingEl = true;
				 		delete ScrollSortHandler.selectedIndexes[id][rowIndex];			
				 	}
				 }
			   }
			  if( !existingEl ) 
			   ScrollSortHandler.selectedIndexes[id][rowIndex] = row;	
			}			
		}
		else
		{
			ScrollSortHandler.clearSelectedIndexes(id);
			ScrollSortHandler.selectedIndexes[id][rowIndex] = row;
		}
	
		ScrollSortHandler.selectedIndex[id] = ScrollSortHandler.getSelectedIndexesAsString(id);
	},
	isSelectedIndex : function(id, rowIndex)
	{
		var selectedIndex = false;
		if(ScrollSortHandler.selectedIndexes[id] != null && ScrollSortHandler.selectedIndexes[id][rowIndex] != null)
		{
			selectedIndex = true;
		}
		//dbg( "isSelectedIndex: " + selectedIndex );
		return selectedIndex;
	},
	getSelectedIndexes : function(id)
	{
		//dbg("\ngetSelectedIndexes");
		var selIndexes = new Array();
		for(var i in ScrollSortHandler.selectedIndexes[id])
		{
			selIndexes[selIndexes.length] = i;
		}

		return selIndexes;
	},
	getSelectedIndexesAsString : function(id)
	{
		//dbg("\ngetSelectedIndexesAsString");
		var out = "";		
		var list = ScrollSortHandler.getSelectedIndexes(id);
		
		if(list.length == 0)
		{
			return "-1";
		}
		for(var i=0; i < list.length; i++)
		{
			if(i>0)
			{
				out += "-";
			}
			out += list[i];
		}
		
		return(out);
	},
	clearSelectedIndexes : function(id)
	{
		//dbg("\nclearSelectedIndexes");
		for(var i in ScrollSortHandler.selectedIndexes[id])
		{
			var row = ScrollSortHandler.selectedIndexes[id][i];
			if(row != null && row != "undefined")
			{
				row.className = row.getAttribute('rowType');
				row.className = ( row.rowIndex % 2 == 0 ) ? "even" : "odd";
				row.selected = false;
			}
		}
		
		ScrollSortHandler.selectedIndexes[id] = {};
	},	
	initSelectedIndexes : function (id, selectedIndexes, rows)
	{
		var indexMap = {};
		ScrollSortHandler.selectedIndex[id] = selectedIndexes;
		ScrollSortHandler.selectedIndexes[id] = {};
		if(selectedIndexes != "-1")
		{
			var indexList = selectedIndexes.split("-");
			for(var i=0; i<indexList.length; i++)
			{
				ScrollSortHandler.addToSelectedIndexes(id, indexList[i], rows[indexList[i]],  "initalLoad" );
				indexMap[indexList[i]] = true;
				ScrollSortHandler.setSelectedIndex(rows[indexList[i]],id, "initialLoad");
			}
		}
		return indexMap;
	},
	resetSelectedIndexes : function(id)
	{
		ScrollSortHandler.selectedIndex[id] = "-1";
		ScrollSortHandler.selectedIndexes[id] = {};
	},
	setForSubmit	: 	function ( node, tableId )
	{
		//dbg("\nsetForSubmit");
		/*
		event = Teams_getEvent( event );
		var target = event.target;
		while ( !target.scrollSortTableId ) {
		  if ( target.nodeName == "BODY" ) {
			return;
		  } else {
			target =  target.parentNode;
		  }
		}
		*/
		
		var table = ScrollSortHandler.all[tableId];
 
		ScrollSortHandler.formForSubmit[tableId] = (node.ownerDocument != null) ? node.ownerDocument.forms[table.formName] : document.forms[table.formName];
		if(node.formAction != null && node.formAction != '')
		{
			ScrollSortHandler.actionForSubmit[tableId] = node.formAction;
		}
	},
	addToGroup		:	function (groupName, id) 
	{
		//dbg("\naddToGroup");
		if(ScrollSortHandler.groups[groupName] == null)
		{
			var a = new Array();
			a[a.length] = id;
			ScrollSortHandler.groups[groupName] = a;
		}
		else
		{
			var a = ScrollSortHandler.groups[groupName];
			a[a.length] = id;
		}
	},
	getSelectedRow : function( index, id ) 
	{
		return ScrollSortHandler.selectedIndexes[id][index];
	}
}

function ScrollSortTable(id, maxHeight, tableSelectedIndexes, sortTypes, groupName, isMultiSelect, onRowSelect, filter, focusable, totalRecords, showRecordCount, formName, sortColumnHiddenField, columnHeaderNames)
{
	//dbg("\nScrollSortTable");
	this.id = id;
	this.rowIndex;
	if (maxHeight)
		this.maxHeight = maxHeight;
	else
		this.maxHeight = 350;
	this.sortTypes = sortTypes;
	this.groupName = groupName;
	this.isMultiSelect = isMultiSelect;
	this.onRowSelect = onRowSelect;
	this.filter = filter;
	this.focusable = focusable;
	this.rowCountStr = "record count: ";
	this.handlerCall = "ScrollSortHandler.all[\"" + this.id + "\"]";
	
	this.sortColumn = null;
	this.descending = null;
	this.formName = formName;
	this.sortColumnHiddenField = sortColumnHiddenField;

	this.sortOrderIndices = "";
	this.sortOrderNames = "";
	this.sortOrderArray = new Array();
	this.sortOrderIndexArray = new Array();
	this.columnHeaderNames = columnHeaderNames;
	this.showRecordCount = showRecordCount;

	ScrollSortHandler.all[this.id] = this;
	if(ScrollSortHandler.selectedIndex[this.id] != -1)
	{
		ScrollSortHandler.selectedTable = this.id;
	}

	if(this.groupName != null)
	{
		ScrollSortHandler.addToGroup(this.groupName, this.id);
	}
	
	if(ScrollSortTable.gecko)
	{
		var tbl = document.getElementById(this.id);
		var tHead = tbl.tHead;
		var tBody = tbl.tBodies[0];
	}
	else
	{
		this.tbl = document.getElementById(this.id + "OuterTable");
		this.tHead = document.getElementById(this.id + "HeaderTable").tBodies[0];
		this.tBody = document.getElementById(this.id + "BodyTable").tBodies[0];
		this.divCntr = document.getElementById(this.id + "BodyRowDiv");
		
		ScrollSortTable.addEvent(this.tBody.parentNode, "resize", new Function("", this.handlerCall + ".checkHeaderRowWidth()"))
		
		this.divCntr.style.overflow = "auto";
		this.divCntr.style.setExpression( "height", "ScrollSortHandler.ieMaxHeight(this, "+maxHeight+")" );
		document.recalc();
		
		this.divHead = document.getElementById(this.id + "HeaderRowDiv");
		
		var tbl = this.tbl;
		var tHead = this.tHead;
		var tBody = this.tBody;
	}
	
	if(this.filter)
	{
		this.filters = {};
		this.headerArray = new Array();
		this.origTable = tBody.cloneNode(true);
		var cells = tHead.rows[0].cells;
		var l = cells.length;
		for(var i = 0; i < l; i++)
		{
			var columnId = cells[i].getAttribute('columnId');
			this.filters[columnId] = "";
			this.headerArray[this.headerArray.length] = columnId;
		}
	}

	var indexMap = ScrollSortHandler.initSelectedIndexes(this.id, tableSelectedIndexes, tBody.rows);

	if (this.showRecordCount)
	{
		//add record count row
		var recordCountTxt;
		if ( totalRecords == 0 )
			recordCountTxt = this.rowCountStr + " 0 of 0"
		else
			recordCountTxt = this.rowCountStr + tBody.rows.length + " of " + totalRecords

		if ( ScrollSortTable.gecko )
		{
			var tFoot = document.createElement("TFOOT");
			var tfRow = tFoot.insertRow(0);
			var tfCell = tfRow.insertCell(0);
			tfCell.setAttribute("colspan", tHead.rows[0].cells.length);
			tfCell.className = "tblFooter";
			tfCell.id = "tblFooter";
			tfCell.innerHTML =  recordCountTxt;
			tbl.appendChild(tFoot);
		}
		else
		{
			this.rcCell = tbl.insertRow(tbl.rows.length).insertCell(0);
			this.rcCell.className = "tblFooter";
			this.rcCell.id = "tblFooter";
			this.rcCell.innerHTML = recordCountTxt;
		}
	}

	if(this.focusable)
	{
		this.txtview = document.createElement("INPUT");
		this.txtview.type = "text";
		this.txtview.name = this.id + "_hidden";
		this.txtview.id = this.id + "_hidden";
		this.txtview.value = this.id;
		this.txtview.style.zIndex = -1;
		this.txtview.style.width = 0;
		this.txtview.style.height = 0;
		this.txtview.style.borderBottomWidth = 0;
		this.txtview.style.borderTopWidth = 0;
		this.txtview.style.borderLeftWidth = 0;
		this.txtview.style.borderRightWidth = 0;
		tbl.appendChild(this.txtview);

		ScrollSortTable.addEvent(this.txtview, "keydown", ScrollSortTable_OnKeyDown);
		ScrollSortTable.addEvent(this.txtview, "focus", ScrollSortTable_OnFocus);
		ScrollSortTable.addEvent(this.txtview, "blur", ScrollSortTable_OnBlur);
	}
	
	var oThis = this;
    if (this.sortTypes.length == 0)
    {
        this._headerOnclick = null;
    }
    else
    {
        this._headerOnclick = function(e)
        {
            oThis.headerOnclick(e);
        };
    }

	var win = document.defaultView || document.parentWindow;
	this._onunload = function () {
		oThis.destroy();
	};
	ScrollSortTable.addEvent(win, "unload", this._onunload);

	this.initHeader(this.sortTypes || []);

	var sortTypeLength = this.sortTypes.length
	var sortTypeHasCombo = false;
	var count = 0;
	for ( count = 0;count<sortTypeLength; count++ )
	{
		if ( this.sortTypes[count] == "ComboBox" )
		{
			sortTypeHasCombo = true;
			break;
		}
	}
	if (sortTypeHasCombo)
	{
        this._cellOnDblclick = function(e)
        {
            oThis.cellOnDblclick(e);
        };
		this.setEventOnDblClickForCell(count);		
	}
}

ScrollSortTable.prototype.setEventOnDblClickForCell = function (column) {
	var tBody = this.tBody || tbl.tBodies[0];
	var rows = tBody.rows;
	
	var l = rows.length;
	var r, c;
	for (var i = 0; i < l; i++) {
		r = rows[i].cells;
		c = r[column];

		if (typeof c.addEventListener != "undefined")
			c.addEventListener("dblclick", this._cellOnDblclick, false);
		else if (typeof c.attachEvent != "undefined")		
			c.attachEvent("ondblclick", this._cellOnDblclick);
	}
};

ScrollSortTable.prototype.cellOnDblclick = function (e) {
	var el = e.target || e.srcElement;
	while (el.tagName != "TD")
		el = el.parentNode;

	var rowIdx;
	if ( el.parentNode.tagName == "TR" )
		rowIdx = el.parentNode.rowIndex;
	else if ( el.parentNode.parentNode.tagName == "TR" )
		rowIdx = el.parentNode.parentNode.rowIndex;

	tHead = this.tHead || document.getElementById(this.id).tHead;
	var col = tHead.rows[0].cells[ el.cellIndex ];

	generateComboAndBuildOnCell(el, this.id, col.columnId, rowIdx);
};

ScrollSortTable.stopEvent = function(ev) {
	//dbg("\nScrollSortTable.stopEvent");
	if (ScrollSortTable.isIE) {
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
	return false;
}

ScrollSortTable.addEvent = function(el, evname, func) {
	//dbg("\nScrollSortTable.addEvent");
	if (el.attachEvent) // IE
	{
		el.attachEvent("on" + evname, func);
	} 
	else if (el.addEventListener) // Gecko / W3C
	{
		el.addEventListener(evname, func, true);
	}
}

ScrollSortTable.removeEvent = function(el, evname, func) {
	//dbg("\nScrollSortTable.removeEvent");
	if (el.detachEvent) // IE 
	{
		el.detachEvent("on" + evname, func);
	} 
	else if (el.removeEventListener) // Gecko / W3C
	{
		el.removeEventListener(evname, func, true);
	}
}

ScrollSortTable.getElement = function(ev) 
{
	//dbg("\nScrollSortTable.getElement");	
	if (ScrollSortTable.isIE) 
	{
		return window.event.srcElement;
	}
	else
	{
		return ev.currentTarget;
	}
}

ScrollSortTable.getTargetElement = function(ev) 
{
	//dbg("\nScrollSortTable.getTargetElement");
	if (ScrollSortTable.isIE)
	{
		return window.event.srcElement;
	}
	else
	{
		return ev.target;
	}
}	

ScrollSortTable.gecko = navigator.product == "Gecko";
ScrollSortTable.msie = /msie/i.test(navigator.userAgent);
// Mozilla is faster when doing the DOM manipulations on
// an orphaned element. MSIE is not
ScrollSortTable.removeBeforeSort = ScrollSortTable.gecko;

ScrollSortTable.prototype.checkHeaderRowWidth = function () 
{
	//dbg("\nScrollSortTable.prototype.checkHeaderRowWidth");
	var tbl = document.getElementById(this.id);
	var tHead = this.tHead || tbl.tHead;
	var tBody = this.tBody || tbl.tBodies[0];
	if(ScrollSortTable.gecko || tBody.rows.length == 0 )
		return;
		
	//unknown why but sometimes correct widths are not determined unless these calls are made first
	tHead.rows[0].offsetWidth;
	tBody.rows[0].offsetWidth;
	
	var headerWidth = tHead.rows[0].offsetWidth;
	var bodyWidth = tBody.rows[0].offsetWidth;
	
	var scrollPadding = -1;
	if(headerWidth < bodyWidth)
	{
		scrollPadding = 0;
	}
	else if(headerWidth > bodyWidth)
	{
		scrollPadding = headerWidth - bodyWidth;
	}
	
	var outerHeaderRowDiv = document.getElementById(this.id + "HeaderRowDiv");
	if(scrollPadding > -1 && outerHeaderRowDiv != null)
	{
		outerHeaderRowDiv.style.paddingRight = scrollPadding + "px";
	}
}

ScrollSortTable.prototype.onsort = function () {/*dbg("\nScrollSortTable.prototype.onsort");*/};

// adds arrow containers and events
// also binds sort type to the header cells so that reordering columns does
// not break the sort types
ScrollSortTable.prototype.initHeader = function (oSortTypes, tHead) {
	//dbg("\nScrollSortTable.prototype.initHeader");
	tHead = this.tHead || document.getElementById(this.id).tHead;
	var cells = tHead.rows[0].cells;
	
	var l = cells.length;
	var img, c;
	for (var i = 0; i < l; i++) {
		c = cells[i];
		img = document.createElement("IMG");
		img.src = "/base/images/blank.png";
		c.appendChild(img);
		if (oSortTypes[i] != null) {
			c._sortType = oSortTypes[i];
		}
		if (typeof c.addEventListener != "undefined")
			c.addEventListener("click", this._headerOnclick, false);
		else if (typeof c.attachEvent != "undefined")		
			c.attachEvent("onclick", this._headerOnclick);
	}
	this.updateHeaderArrows(tHead);
};

// remove arrows and events
ScrollSortTable.prototype.uninitHeader = function (tHead) {
	//dbg("\nScrollSortTable.prototype.uninitHeader");
	tHead = this.tHead || document.getElementById(this.id).tHead;
	var cells = tHead.rows[0].cells;
	var l = cells.length;
	var c;
	for (var i = 0; i < l; i++) {
		c = cells[i];
		c.removeChild(c.lastChild);
		if (typeof c.removeEventListener != "undefined")
			c.removeEventListener("click", this._headerOnclick, false);
		else if (typeof c.detachEvent != "undefined")
			c.detachEvent("onclick", this._headerOnclick);
	}
};

ScrollSortTable.prototype.updateHeaderArrows = function (tHead) {
	//dbg("\nScrollSortTable.prototype.updateHeaderArrows");
	var cells = tHead.rows[0].cells;
	var l = cells.length;
	var img;
	for (var i = 0; i < l; i++) {
		img = cells[i].lastChild;
		if (i == this.sortColumn)
			img.className = "sort-arrow " + (this.descending ? "descending" : "ascending");
		else
			img.className = "sort-arrow";			
	}
};

ScrollSortTable.prototype.headerOnclick = function (e) {
	//dbg("\nScrollSortTable.prototype.headerOnclick");
	// find TD element
	var el = e.target || e.srcElement;
	while (el.tagName != "TD")
		el = el.parentNode;

	var tBody = this.tBody || document.getElementById(this.id).tBodies[0];

	this.addSortCriteria(el.cellIndex, el.firstChild.data);
	
	//this.sort(el.cellIndex);
	
	ScrollSortHandler.hilightedIndex[this.id] = 0;
	var row = tBody.rows[0];
	if(row)
	{
		row.className = "tableHighlight";			
	}

	var tblele = document.getElementById(this.id + "_hidden");
	if(tblele)
	{
		tblele.focus();
	}
};

ScrollSortTable.prototype.getSortType = function (nColumn, tHead) {
	//dbg("\nScrollSortTable.prototype.getSortType");
	var cell = tHead.rows[0].cells[nColumn];
	var val = cell._sortType;
	if (val != "")
		return val;
	return "String";
};

ScrollSortTable.prototype.addSortCriteria = function (colNumber, colName) {
var buildNames = "";
//if the descending marker is modified, the java code in ScrollSortTableTag
//must also be updated.
var colNameDesc =  colName+"(d)";
var colNumberDesc = "^"+colNumber;

//check for reversal (ascending/descending)
if ((this.sortOrderArray[this.sortOrderArray.length-1] == colName) || (this.sortOrderArray[this.sortOrderArray.length-1] == colNameDesc)) {
	
	if (this.sortOrderArray[this.sortOrderArray.length-1] == colName) {
		this.sortOrderArray[this.sortOrderArray.length-1] = colNameDesc;
		this.sortOrderIndexArray[this.sortOrderIndexArray.length-1] = colNumberDesc;
	} else {
		this.sortOrderArray[this.sortOrderArray.length-1] = colName;	
		this.sortOrderIndexArray[this.sortOrderIndexArray.length-1] = colNumber;
	}
	
	for (var i=0; i < this.sortOrderArray.length;i++) {
		buildNames += this.sortOrderArray[i];
		if(i != (this.sortOrderArray.length-1)) {
			buildNames +=",";
		}
	}
	this.sortOrderNames = buildNames;

} else {

	for (var i=0; i < this.sortOrderArray.length;i++) {
		if ((this.sortOrderArray[i] == colName) || this.sortOrderArray[i] == colNameDesc){
			//column has already been added.
			return;
		}
		buildNames += this.sortOrderArray[i] +",";
	}
	this.sortOrderArray.push(colName);
	this.sortOrderIndexArray.push(colNumber);
	this.sortOrderIndices += colNumber+",";
	this.sortOrderNames = buildNames + colName;
}


var indices = "";
for (var i=0; i < this.sortOrderIndexArray.length;i++) {
		indices += this.sortOrderIndexArray[i];
		if(i != (this.sortOrderIndexArray.length-1)) {
			indices +=",";
		}
	}

var scField = document.getElementById(this.sortColumnHiddenField);
	if (scField) {
			scField.value = indices;		
	}

var displayText = document.getElementById("sortDisplay_"+this.id);
displayText.innerHTML = this.sortOrderNames;
}

ScrollSortTable.prototype.clearSortCriteria = function () {
	this.sortOrderIndices = "";
	this.sortOrderNames = "";
	var displayText = document.getElementById("sortDisplay_"+this.id);
	displayText.innerHTML = this.sortOrderNames;
	var scField = document.getElementById(this.sortColumnHiddenField);
	if (scField) {
			scField.value = "";		
	}
	this.sortOrderArray = new Array();
	this.sortOrderIndexArray = new Array();
	this.sortOrderIndices = "";
	this.sortOrderNames = "";
	
}


// only nColumn is required
// if bDescending is left out the old value is taken into account
// if sSortType is left out the sort type is found from the sortTypes array

ScrollSortTable.prototype.sort = function (nColumn, bDescending, sSortType) {
	//dbg("\nScrollSortTable.prototype.sort");
	
	var tbl = document.getElementById(this.id);
	var tHead = this.tHead || tbl.tHead;
	var tBody = this.tBody || tbl.tBodies[0];
	
	
	if (sSortType == null)
		sSortType = this.getSortType(nColumn, tHead);

	// exit if 6	
	if (sSortType == "None")
		return;
	
	// tests to see if the passed column is the same column that was previously sorted
	// if not, it sets descending to true. if it is, set descending to opposite value
	if (bDescending == null) {
		if (this.sortColumn != nColumn)
			this.descending = false;
		else
			this.descending = !this.descending;
	}	
	
	this.sortColumn = nColumn;
	
	if (typeof this.onbeforesort == "function")
		this.onbeforesort();
	
	var f = this.getSortFunction(sSortType, nColumn);
	var a = this.getCache(sSortType, nColumn, tBody);
		
	a.sort(f);
	
	if (this.descending)
		a.reverse();
		
	if (ScrollSortTable.removeBeforeSort) {
		// remove from doc
		var nextSibling = tBody.nextSibling;
		var p = tBody.parentNode;
		p.removeChild(tBody);
	}
	
	// insert in the new order
	var l = a.length;
	for (var i = 0; i < l; i++)
		tBody.appendChild(a[i].element);
	
	if (ScrollSortTable.removeBeforeSort) {	
		// insert into doc
		p.insertBefore(tBody, nextSibling);
	}
		
	this.updateHeaderArrows(tHead);
	
	this.destroyCache(a);
	
	this.updateRows(tBody);

	var scField = document.getElementById(this.sortColumnHiddenField);
	if (scField) {
		if (this.descending) {
			scField.value = "^"+nColumn;
		} else {
			scField.value = nColumn;
		}
		
	}
};

ScrollSortTable.prototype.updateRows = function(tBody)
{
	for (var i = 0; i < tBody.rows.length; i++) 
	{
		var row = tBody.rows[i];
		// row.tblIndex = i;
		changeRowType(row, i);
		changeRowClass(row, i);
	}
};

ScrollSortTable.prototype.asyncSort = function (nColumn, bDescending, sSortType) {
	//dbg("\nScrollSortTable.prototype.asyncSort");
	var oThis = this;
	this._asyncsort = function () {
		oThis.sort(nColumn, bDescending, sSortType);
	};
	window.setTimeout(this._asyncsort, 1);	
};

ScrollSortTable.prototype.getCache = function (sType, nColumn, tBody) {
	//dbg("\nScrollSortTable.prototype.getCache");
	var rows = tBody.rows;
	var l = rows.length;
	var a = new Array(l);
	var r;
	for (var i = 0; i < l; i++) {
		r = rows[i];
		if (r.origIndex == null) {
			r.origIndex = i;
		}
		a[i] = {
			value:		this.getRowValue(r, sType, nColumn),
			element:	r
		};
	}
	return a;
};

ScrollSortTable.prototype.destroyCache = function (oArray) {
	//dbg("\nScrollSortTable.prototype.destroyCache");
	var l = oArray.length;
	for (var i = 0; i < l; i++) {
		oArray[i].value = null;
		oArray[i].element = null;
		oArray[i] = null;
	}
}

ScrollSortTable.prototype.getRowValue = function (oRow, sType, nColumn) {
	//dbg("\nScrollSortTable.prototype.getRowValue");
	return this.getValueFromString(this.getRowText(oRow, nColumn), sType);
};

ScrollSortTable.prototype.getRowText = function (oRow, nColumn) {
	//dbg("\nScrollSortTable.prototype.getRowText");
	var s;
	var c = oRow.cells[nColumn];
	if (typeof c.innerText != "undefined")
		s = c.innerText;
	else
		s = ScrollSortTable.getInnerText(c);
	return s;
};

ScrollSortTable.getInnerText = function (oNode) {
	//dbg("\nScrollSortTable.getInnerText");
	var s = "";	
	var cs = oNode.childNodes;
	var l = cs.length;
	for (var i = 0; i < l; i++) {
		switch (cs[i].nodeType) {
			case 1: //ELEMENT_NODE
				s += ScrollSortTable.getInnerText(cs[i]);
				break;
			case 3:	//TEXT_NODE
				s += cs[i].nodeValue;
				break;
		}
	}
	return s;
}

ScrollSortTable.prototype.setScrollSortTableFooter = function (recordCount) {
	if (this.showRecordCount)
	{
		//add record count row
		var recordCountTxt;
		if ( recordCount == 0 )
			recordCountTxt = this.rowCountStr + " 0 of 0"
		else
			recordCountTxt = this.rowCountStr + this.tBody.rows.length + " of " + recordCount

		var tFoot = document.getElementById("tblFooter");
		tFoot.innerHTML =  recordCountTxt;
	}
}

ScrollSortTable.prototype.setSortOrderValues = function (sortOrderIndices) {
	this.sortOrderIndices = sortOrderIndices;
	if (sortOrderIndices != "" && sortOrderIndices.length > 0)
	{
		var sortOrderIndicesArr = sortOrderIndices.split(",");
		var sOrderNames	= "";
		for ( var arr = 0; arr<sortOrderIndicesArr.length; arr++ )
		{
			var indices = sortOrderIndicesArr[arr];
			var columnName = this.columnHeaderNames[indices];
			this.sortOrderIndexArray.push( indices );
			this.sortOrderArray.push( columnName );
			sOrderNames += columnName + ",";
		}

		if ( sOrderNames != "" && sOrderNames.length > 0 )
		{
			sOrderNames = sOrderNames.substring( 0, sOrderNames.length-1 );
			this.sortOrderNames = sOrderNames;
		}
	}
	else
	{
		var displayText = document.getElementById("sortDisplay_"+this.id);
		displayText.innerHTML = "";
	}
}

ScrollSortTable.prototype.setSortOrderNames = function (sOrderNames) {
	this.sortOrderIndices = sOrderNames;
}

ScrollSortTable.prototype.setSortOrderIndices = function (sOrderIndices) {
	this.sortOrderIndices = sOrderIndices;
}

ScrollSortTable.prototype.addSortOrderArray = function (sOrderName) {
	this.sortOrderArray.push(sOrderName);
}

ScrollSortTable.prototype.addSortOrderIndexArray = function (sOrderIndex) {
	this.sortOrderIndexArray.push(sOrderIndex);
}

ScrollSortTable.prototype.getValueFromString = function (sText, sType) {
	//dbg("\nScrollSortTable.prototype.getValueFromString");
	switch (sType) {
		case "Number":
			return Number(sText);
		case "CaseInsensitiveString":
			return sText.toUpperCase();
		case "Date":
			var parts = sText.split("-");
			var d = new Date(parseInt(parts[2],10), parseInt(parts[0],10) - 1, parseInt(parts[1],10));
			return d.valueOf();		
	}
	return sText;
};

ScrollSortTable.prototype.getSortFunction = function (sType, nColumn) {
	//dbg("\nScrollSortTable.prototype.getSortFunction");
	return function compare(n1, n2) {
		if (n1.value < n2.value)
			return -1;
		if (n2.value < n1.value)
			return 1;
		return 0;
	};
};

ScrollSortTable.prototype.applyFilter = function (columnId, value)
{
	//dbg("\nScrollSortTable.prototype.applyFilter");
	
	var tBody = this.tBody || document.getElementById(this.id).tBodies[0];
	
	this.filters[columnId] = value;
	
	var parent = tBody.parentNode;
	var newTable = this.origTable.cloneNode(true);
	
	var filters = this.getFilters();
	var rowCount = 0;
	if(filters.length > 0)
	{
		for(var i = 0; i < newTable.rows.length; i++)
		{
			var row = newTable.rows[i];
			if(this.filterRow(row, filters))
			{
				var rowParent = row.parentNode;
				rowParent.removeChild(row);
				i--;
			}
			else
			{
				row.tblIndex = rowCount++;
			}
		}
	}
	
	parent.replaceChild(newTable, tBody);
	tBody = newTable;
	this.updateRows(tBody);
	this.checkHeaderRowWidth();
	ScrollSortHandler.hilightedIndex[this.id] = 0;
	ScrollSortHandler.resetSelectedIndexes(this.id);
}

ScrollSortTable.prototype.filterRow = function(row, filters)
{
	//dbg("\nScrollSortTable.prototype.filterRow");
	var filter = false;
	for(var i = 0; i < filters.length; i++)
	{
		if(filters[i].value != this.getRowText(row, filters[i].index))
		{
			filter = true;
			break;
		}
	}
	return filter;
}

ScrollSortTable.prototype.getFilters = function()
{
	//dbg("\nScrollSortTable.prototype.getFilters");
	var filters = new Array();
	for(var i = 0; i < this.headerArray.length; i++)
	{
		if(this.filters[this.headerArray[i]] != "")
		{
			filters[filters.length] = new ScrollSortFilter(i, this.filters[this.headerArray[i]]);
		}
	}
	return filters;
}

function ScrollSortFilter(index, value)
{
	//dbg("\nScrollSortFilter");
	this.index = index;
	this.value = value;
}

ScrollSortTable.prototype.destroy = function () {
	//dbg("\nScrollSortTable.prototype.destroy");
	
	tHead = this.tHead || document.getElementById(this.id).tHead;
	
	this.uninitHeader(tHead);
	var win = document.defaultView || document.parentWindow;
	ScrollSortTable.removeEvent(win, "unload", this._onunload);
	
	this.id = null;
	this.maxHeight = null;
	this.sortTypes = null;
	this.groupName = null;
	this.isMultiSelect = null;
	this.onRowSelect = null;
	this.filter = null;
	this.focusable = null;
	this.rowCountStr = null;
	this.sortColumn = null;
	this.descending = null;
	this.divCntr = null;
	this.divHead = null;
	this.filters = null;
	this.headerArray = null;
	this.origTable = null;
	this._onunload = null;
	this.txtview = null;
	this._onunload = null;
	this.element = null;
	this._headerOnclick = null;
	this.sortTypes = null;
	this._asyncsort = null;
	this.onsort = null;
	this.tBody = null;
	this.tHead = null;
};

// Triggered by onmouseover
function changeRowStyleClass( HTMLTableRowElement, newClass, tableName )
{
	// dbg("\nchangeRowStyleClass");
	var rowIndex = HTMLTableRowElement.rowIndex;
	if ( ScrollSortTable.gecko ) {
	  --rowIndex;
	}

	if (HTMLTableRowElement.origIndex != null) {
		rowIndex = HTMLTableRowElement.origIndex;
	}
	if(!ScrollSortHandler.isSelectedIndex(tableName,rowIndex))
	{
		HTMLTableRowElement.className = newClass;
	}
	
	ScrollSortHandler.hilightedIndex[tableName] = rowIndex;
	
	/*
	var tblele = document.getElementById(tableName + "_hidden");
	if(tblele != null)
	{
		tblele.focus();
	}
	*/
}

// Triggered by onmouseout
function changeSortableTableRowStyleClass( HTMLTableRowElement , tableName)
{
	//dbg("\nchangeSortableTableRowStyleClass");
	var rowIndex = HTMLTableRowElement.rowIndex;
	if ( ScrollSortTable.gecko ) {
	  --rowIndex;
	}
	if( ! HTMLTableRowElement.selected )
	{
		HTMLTableRowElement.className = ( rowIndex % 2 == 0 ) ? "even" : "odd";
	}
}

function ScrollSortTable_OnKeyDown(evt)
{	
	//dbg("\nScrollSortTable_OnKeyDown");
	var evt = getEvent(evt);
		
	if (evt)
	{		
		var key = evt.keyCode;
		var pass = true;
		var id = ScrollSortHandler.selectedTable;
		var hlidx = ScrollSortHandler.hilightedIndex[id];
		var div = ScrollSortHandler.all[id].divCntr;
		var row = null;
		var tBody = ScrollSortHandler.all[id].tBody || document.getElementById(id).tBodies[0];
		var refObj = ScrollSortTable.gecko ? tBody : div;

		if(key == 40) //down arrow
		{ 
			hlidx++;
			if(hlidx < tBody.rows.length)
			{
				row = tBody.rows[hlidx];
				rowPosition(refObj, row);
			}
		}
		else if(key == 38) //up arrow
		{ 
			if(hlidx > 0) 
			{
				hlidx--;
				var row = tBody.rows[hlidx];
				rowPosition(refObj, row);
			}
		}
		else if(key == 32) //space
		{
			row = tBody.rows[hlidx];				
			selectRow(id, row);
		}
		else if(key == 9) //tab
		{
			ScrollSortHandler.hilightedIndex[id] = hlidx;
			return true;
		}
		else 
		{
			pass = false;
		}
		
		if(pass)
		{
			row = tBody.rows[hlidx]
			if(row)
			{	
				if(ScrollSortHandler.isSelectedIndex(id, hlidx))
				{
					row.className='tableSelected';
				}
				else
				{
					row.className = "tableHighlight";
				}
				
				var brow = tBody.rows[hlidx - 1];
				if(brow && !ScrollSortHandler.isSelectedIndex(id, hlidx - 1))
				{
					changeSortableTableRowStyleClass(brow, id);
				}
				
				var arow = tBody.rows[hlidx + 1];
				if(arow && !ScrollSortHandler.isSelectedIndex(id,hlidx + 1))
				{
					changeSortableTableRowStyleClass(arow, id);
				}	
				
				ScrollSortHandler.hilightedIndex[id] = hlidx;
			}
		}				
		return true;
	}
}

function ScrollSortTable_OnFocus(evt)
{	
	//dbg("\nScrollSortTable_OnFocus");
	var evt = Teams_getEvent( evt );
	if(evt)
	{
		var id = getSelectedTable(evt);
		
		if(id)
		{
			ScrollSortHandler.selectedTable = id;
		}
		id = ScrollSortHandler.selectedTable;
		
		var hlidx = ScrollSortHandler.hilightedIndex[id];
		var tBody = ScrollSortHandler.all[id].tBody || document.getElementById(id).tBodies[0];
		if((hlidx != null) && (hlidx > -1) && (hlidx < tBody.rows.length))
		{	
			var row = tBody.rows[hlidx];
			var rowIndex = row.rowIndex;
			if ( ScrollSortTable.gecko ) {
			  --rowIndex;
			}
			if(!ScrollSortHandler.isSelectedIndex(id, rowIndex))
			{
				row.className = "tableHighlight";	
			}
		}
		else
		{
			ScrollSortHandler.hilightedIndex[id] = 0;
			var row = tBody.rows[0];
			if(row)
			{
				row.className = "tableHighlight";			
			}
		}
	}
}

function ScrollSortTable_OnBlur(evt)
{
	//dbg("\nScrollSortTable_OnBlur");
	var evt = getEvent(evt);
	if(evt)
	{
		var id = getSelectedTable(evt);
		if(id)
		{
			ScrollSortHandler.selectedTable = id;
		}
		
		var hlidx = ScrollSortHandler.hilightedIndex[id];
		var tBody = ScrollSortHandler.all[id].tBody || document.getElementById(id).tBodies[0];
		if((hlidx != null) && (hlidx > -1) && (hlidx < tBody.rows.length))
		{
			var row = tBody.rows[hlidx];
			changeSortableTableRowStyleClass(row, id);
		}
	}
}

/*
 * changes the rowType for a rowElement based on the rowIndex
 * passed in. Used by the table sorting.
 *
 */
function changeRowType(rowElement, rowIndex)
{
	//dbg("\nchangeRowType");
	var newType = (rowIndex % 2 == 0 ? "even" : "odd");
	var currentRowType = rowElement.getAttribute('rowType');
	if(currentRowType != newType)
	{
		rowElement.removeAttribute('rowType');
		rowElement.setAttribute('rowType', newType);
	}
}

/*
 * changes the class for a rowElement based on the rowIndex
 * passed in. Used by the table sorting.
 *
 */
function changeRowClass(rowElement, rowIndex)
{
	//dbg("\nchangeRowClass");
	var origIndex = rowElement.rowIndex;
	if ( ScrollSortTable.gecko ) { // TODO: Determine whether addToSelectedIndexes cares if rowIndex is offset by one when browser is Gecko. This is due to different HTML rendering in Gecko: The header row is in the same table.
	  --origIndex;
	}
	if (rowElement.origIndex != null) {
		origIndex = rowElement.origIndex;
	}
	if(origIndex == ScrollSortHandler.selectedIndex[this.id])
	{
		rowElement.className = 'tableSelected';
	}
	else
	{
		rowElement.className = (rowIndex % 2 == 0 ? "even" : "odd");
	}
}

function getEvent(evt)
{
	var isIE = document.attachEvent ? true : false;
	var isNN = document.addEventListener ? true : false;

	evt = (evt) ? evt : ((event) ? event : null);
	return evt;
}

function getSelectedTable(evt)
{
	//dbg("\ngetSelectedTable");
	var isIE = document.attachEvent ? true : false;
	var id;
	if(isIE)
	{
		id = evt.srcElement.id.split("_");
	}
	else //Netscape
	{		
		id = evt.target.id.split("_");
	}
	return id[0];
}

function rowPosition(refObj, row)
{
	//dbg("\nrowPosition");
	if(((row.offsetTop + row.offsetHeight) - refObj.scrollTop) > (refObj.offsetHeight - 3))
	{
		refObj.scrollTop = (row.offsetTop + row.offsetHeight) - (refObj.offsetHeight - 3);
	}
	else if((row.offsetTop - refObj.scrollTop) < 0)
	{
		refObj.scrollTop =  row.offsetTop;
	}
}

function isSelected(row) {
  if ( row.selected ) {
    return true;
  } else {
    return false;
  }
}

function select(row) {
  row.className = "tableSelected";
  row.selected = true;
}

function deselect(row) {
  row.selected = false;
}

function selectRow(id, HTMLTableRowElement, loadControlFactor)
{
	//dbg("\nselectRow");
	
	ScrollSortHandler.selectedTable = id;
	var rowIndex = HTMLTableRowElement.rowIndex;
	
	if ( ScrollSortTable.gecko ) { 
	// TODO: Determine whether addToSelectedIndexes cares if rowIndex is offset by one when browser is Gecko. This is due to different HTML rendering in Gecko: The header row is in the same table.
	  --rowIndex;
	}
	if (HTMLTableRowElement.origIndex != null) {
		rowIndex = HTMLTableRowElement.origIndex;
	}

	if( loadControlFactor != "initialLoad"){
		ScrollSortHandler.addToSelectedIndexes( id, rowIndex, HTMLTableRowElement );
	}
	var table = ScrollSortHandler.all[id];
	if(table.onRowSelect)
	{
		if(! HTMLTableRowElement.onRowSelect)
		{
			HTMLTableRowElement.onRowSelect = new Function("", table.onRowSelect);
		}
		HTMLTableRowElement.onRowSelect();			
	}
	
	if( !isSelected(HTMLTableRowElement) )
	{
		select(HTMLTableRowElement);
	}
	else
	{
		deselect(HTMLTableRowElement);
		if(ScrollSortHandler.selectedRow[id] != null && !ScrollSortHandler.all[id].isMultiSelect)
		{
			ScrollSortHandler.selectedRow[id].className = ScrollSortHandler.selectedRow[id].getAttribute('rowType');
		}
	}
	ScrollSortHandler.selectedRow[id] = HTMLTableRowElement;
	
	var tblele = document.getElementById(id + "_hidden");
	
/* Commented By Rajesh Kumar SC - Bug 5538
	if(tblele && !tblele.focus())
	{
		tblele.focus();
	}
*/
	if(ScrollSortHandler.formForSubmit[id])
	{
		var form = ScrollSortHandler.formForSubmit[id];
		form.selectedIndexId.value = ScrollSortHandler.selectedIndex[id];
		form.selectedTable.value = id;
		//TODO JT form.applicantRowType.value = "applicantType";
		if(ScrollSortHandler.actionForSubmit[id])
		{
			form.action = ScrollSortHandler.actionForSubmit[id];
		}
		
		form.submit();
	}
}

function focusTableToRowNumber(rowNumber, tableId) {
	var div = ScrollSortHandler.all[tableId].divCntr;
	var tBody = ScrollSortHandler.all[tableId].tBody || document.getElementById(tableId).tBodies[0];
		var refObj = ScrollSortTable.gecko ? tBody : div;
	rowPosition(refObj, tBody.rows[rowNumber]);
}