// thanks to kryogenix.org for the code base at http://www.kryogenix.org/code/browser/sorttable/
// simplified with a couple functions from prototype.js (required)
// autosort, object oriented, adapted and enhanced for Kizash implementation by Dominic Tocci
// assumes table data rows are td elements, and headers and special rows are th

var Table = Class.create();
Table.tableObjects = {}; // regular array, not prototype extended
Table.prototype = {
	sortcolumnindex: 0,
	tblObj: null,
	tableid: "",
	tabletype: null,
//	allData: new Array(),
	tableInfo: new Array(),
	linkclicked: false,
	skipsort: false, // for select boxes in table heads
	showRow: (document.all)?"block" :"table-row",

	initialize: function(elOrId) {
		this.tblObj = $(elOrId);
		this.tableid = this.tblObj.id;
		this.tableInfo = new Array();
		this.sortcolumnindex=0;
		if ((Element.hasClassName(this.tblObj,"interactive")) && (this.tableid)) {
//			this.tableInfo["dataIndex"] = this.tableDataIndex();
//			this.tableInfo["dataRows"] = this.countDataRows();
			if (this.tblObj.hasClassName("autofilter")) {
				this.makeAutoFilter();
			}
			if (this.tblObj.hasClassName("ajax")) {
				this.tabletype = "ajax";
				this.makeClickable();
			}
			else if (this.tblObj.hasClassName("linked")) {
				this.tabletype = "linked";
				this.makeClickable();
			}
			this.makeSortable();
			this.makeRuled();
			this.stripe();

// hack to fix width problems. display:table does not work in firefox when using the paginator via ajax

			tablewidth = Element.getDimensions(this.tblObj)["width"];
			tablediv = Element.getParent(this.tblObj,"div.tablediv");
			if (tablediv){
				tabledivwidth = Element.getDimensions(tablediv)["width"]; // normal tablediv width
				if (tablewidth > tabledivwidth)
					tablediv.style.width=tablewidth + 'px';
			}
/*
			// hacked cross-browser fix for when contained in a fixed width div
			if (thisdiv = Element.getParent(thisTbl,"DIV")){
				if (document.all){ // IE Rendering fix
					thisdiv.style.marginBottom="10px";
				}
				thisTbl.style.marginBottom='10px';
				thisTbl.style.marginTop='5px';
			}
*/

		}

//	Event.observe(window, 'load', this.apply, false);
	},
	makeClickable: function(){
		datarows = $$('#' + this.tblObj.id + ' tbody tr');
		for (var i=0;i<datarows.length;i++){
			Event.observe(datarows[i], "mousedown", this.tableclickdown.bind(this));
			Event.observe(datarows[i], "click", this.tableclickup.bind(this)); // formerly was mouseup, but right click was causing actions
		}
	},
	toObject: function(e){ // converts table to a JSON object based on the click event
		// AJAX FUNCTIONALITY
		// when a table is clicked, the event is passed here
		tdobj = (document.all)?e.srcElement:e.target;
		// td is the clickable element on the table
		trobj = Element.getParent(tdobj,"TR");
		tableobj = Element.getParent(tdobj,"TABLE");
		var captureClick = new Object;
		captureClick["id"] = tableobj.id;
//		captureClick["type"] = "table";
//		captureClick["clickedcell"] = Element.getInnerText(obj);
//		captureClick["clickedcellHTML"] = tdobj.innerHTML;
//		captureClick["rowIndex"]=trobj.rowIndex;
		captureClick["rowId"] = trobj.id.substring(tableobj.id.length+1,trobj.id.length);
//		captureClick["cellIndex"] = tdobj.cellIndex;

//		var tcell = trobj.firstChild;

//		captureClick["row"]=new Object;
//		rupcellcount=0;
//		while (tcell){
//			if (tcell.tagName == "TD"){
//				rowdata = this.getCellData(tcell);
//				rowlabel = Element.getInnerText(tableobj.rows[0].cells[rupcellcount]);
//				captureClick.row[rowlabel]=rowdata;
//				rupcellcount++;
//			}
//			tcell=tcell.nextSibling;
//		}
		return captureClick; // captureClick is a json object
	},
	tableclickdown: function(e){
		if (!this.linkclicked){
			obj = (document.all)?e.srcElement:e.target;
			trobj = Element.getParent(obj,"TR");
			Element.addClassName(trobj,"clicked");
		}
/*		var tcell = trobj.firstChild;
		while (tcell){
			if (tcell.tagName == "TD")
				Element.addClassName(tcell,"clicked");
//				tcell.className="clicked";
			tcell=tcell.nextSibling;
		}
*/
	},
	tableclickup: function(e){
		if (!this.linkclicked){
			if (this.tabletype == "ajax"){
			// AJAX.tableClick(e);
				jsonobject = this.toObject(e);
				gotourl = getAjaxURL();
				var myAjax = new Ajax.Request(gotourl, {method: 'post', postBody: Object.toJSON(jsonobject), 
					onComplete: function(e){
						AJAX.showResponse(e);
						AJAX.complete(this);
					},
					onLoading: function(e){
						AJAX.loading(this);
					},
					onFailure: AJAX.reportError, contentType: 'text/plain; charset=UTF-8'} );

			// END AJAX FUNCTIONALITY
			}
		} else {
			this.linkclicked = false;
		}
		Element.addClassName(trobj,"ruled");
		Element.removeClassName(trobj,"clicked");
/*		var tcell = trobj.firstChild;
		while (tcell){
			if (tcell.tagName == "TD"){
				Element.addClassName(tcell,"ruled");
				Element.removeClassName(tcell,"clicked");
//				tcell.className="ruled";
			}
			tcell=tcell.nextSibling;
		}
*/		
	},
	Rover: function(e){
		obj = (document.all)?e.srcElement:e.target;
		trobj = Element.getParent(obj,"TR");
		Element.removeClassName(trobj,"clicked");
		Element.addClassName(trobj,"ruled");
/*		var tcell = trobj.firstChild;
		while (tcell){
			if (tcell.tagName == "TD"){
				Element.removeClassName(tcell,"clicked");
				Element.addClassName(tcell,"ruled");
//				tcell.className="ruled";
			}
			tcell=tcell.nextSibling;
		}
*/
	},
	Rout: function(e){
		obj = (document.all)?e.srcElement:e.target;
		trobj = Element.getParent(obj,"TR");
		Element.removeClassName(trobj,"clicked");
		Element.removeClassName(trobj,"ruled");
//		classtoset = trobj.className;
/*		var tcell = trobj.firstChild;
		while (tcell){
			if (tcell.tagName == "TD"){
//				Element.removeClassName(tcell,"alternate");
				Element.removeClassName(tcell,"clicked");
				Element.removeClassName(tcell,"ruled");
//				Element.addClassName(tcell,classtoset);
//				tcell.className=classtoset;
			}
			tcell=tcell.nextSibling;
		}
*/
	},
	Hover: function(e){
		obj = (document.all)?e.srcElement:e.target;
		obj = Element.getParent(obj,"TH");
		Element.removeClassName(obj,"colheadover");
		Element.removeClassName(obj,"colheaddepressed");
		Element.addClassName(obj,"colheadover");
//		obj.className='colheadover';
	},
	Hout: function(e){
		obj = (document.all)?e.srcElement:e.target;
		obj = Element.getParent(obj,"TH");
		Element.removeClassName(obj,"colheadover");
		Element.removeClassName(obj,"colheaddepressed");
//		obj.className='';
	},
	Hdown: function(e){
		obj = (document.all)?e.srcElement:e.target;
		obj = Element.getParent(obj,"TH");
		Element.removeClassName(obj,"colheadover");
		Element.removeClassName(obj,"colheaddepressed");
		Element.addClassName(obj,"colheaddepressed");
//		obj.className='colheaddepressed';
	},
	Hup: function(e){
		obj = (document.all)?e.srcElement:e.target;
		obj = Element.getParent(obj,"TH");
		if (!this.skipsort)
			this.resortTable(obj);
		else
			this.skipsort = false;
//		obj.className='colheadover';
		Element.removeClassName(obj,"colheadover");
		Element.removeClassName(obj,"colheaddepressed");
		Element.addClassName(obj,"colheadover");
	},
	stripe: function(){
		classtoset = "";
		if (this.tblObj.rows && this.tblObj.rows.length > 0) {
			for (var i=1;i<this.tblObj.rows.length;i++){
				if (this.tblObj.rows[i].style.display==""){
					classtoset = (classtoset=="")?"alternate":"";
				}
				if (this.tblObj.rows[i].cells[0].tagName=="TD"){
					Element.removeClassName(this.tblObj.rows[i],"alternate");
					Element.addClassName(this.tblObj.rows[i],classtoset);					
//					this.tblObj.rows[i].className=classtoset; // store class name in row element for mouseout behavior
/*					for (var j=0;j<this.tblObj.rows[i].cells.length;j++){
						Element.removeClassName(this.tblObj.rows[i].cells[j],"alternate");
						Element.addClassName(this.tblObj.rows[i].cells[j],classtoset);
//						this.tblObj.rows[i].cells[j].className=classtoset;
					}
*/				}
			}
		}
	},
	makeRuled: function(){
		var datarows = $$('#' + this.tblObj.id + ' tbody tr');
			for (var i=0;i<datarows.length;i++){
				Event.observe(datarows[i],"mouseover", this.Rover.bind(this));
				Event.observe(datarows[i],"mouseout", this.Rout.bind(this));
			}
	},
	makeSortable: function() {
		if (this.tblObj.rows && this.tblObj.rows.length > 0) {
			var firstRow = this.tblObj.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]);
			Event.observe(cell,"mouseover",this.Hover.bind(this));
			Event.observe(cell,"mouseout",this.Hout.bind(this));
			Event.observe(cell,"mousedown",this.Hdown.bind(this));
			Event.observe(cell,"click",this.Hup.bind(this)); // formerly was mouseup, but right click was causing actions
			Event.observe(cell,"selectstart",function () { return false; });
	//		cell.setAttribute("style","-moz-user-select: none; -khtml-user-select: none; user-select: none");

//			var txt = Element.getInnerText(cell);
//			cell.innerHTML = txt+'<span class="sortarrow">&uarr;</span>';

			var sortarrow = document.createElement('span');
			Element.addClassName(sortarrow,'sortarrow');
			sortarrow.innerHTML = '&uarr;';
			cell.appendChild(sortarrow);
		}
		allsortarrows = $$('#' + this.tblObj.id + ' thead tr th span.sortarrow');
		for (var j=0;j<allsortarrows.length;j++){
			allsortarrows[j].style.visibility='hidden';
		}
	},
	getFilters: function(whichselect){ // give it any select box filter and it will return all filters from that filtering row in an array
		var thistr = Element.getParent(whichselect,"TR");
	//	var trholder = whichelement.parentNode;
		var returnArray = new Array();
		for (var i=0;i<thistr.childNodes.length;i++){
			whichbox = thistr.childNodes.item(i);
			while ((whichbox.nodeName.toLowerCase() != "select")&&(whichbox.childNodes.length>0)){
				whichbox = whichbox.childNodes.item(0);
			}
			if (whichbox.nodeName.toLowerCase() == "select"){
				if (whichbox.selectedIndex==0)
					returnArray[i]="";
				else
					returnArray[i]=whichbox.options[whichbox.selectedIndex].text;
			} else
				returnArray[i]="";
		}
		return returnArray;	
	},
	filterTable: function(e){
		whichselect = (document.all)?e.srcElement:e.target;
		thistr = Element.getParent(whichselect,"TR");
		
		tblObj = Element.getParent(thistr,"TABLE"); // get scope
//		var sortRow = this.tableInfo["dataIndex"];

		var newdata = new Array();
//		var newdataindex = 0;
		var filters = this.getFilters(whichselect);
		var hide= true;
		datarows = $$('#' + tblObj.id + ' tbody tr');
		this.showrow = true;
		var compareto = "";
		for(i=0 ; i<datarows.length; i++){
			this.showrow = true; // reset
			for (var j=0;j<tblObj.rows[0].cells.length;j++){
				if (filters[j]!=""){
					cell = datarows[i].cells[j];
					compareto = this.getCellData(cell);
					if (filters[j]!=compareto){
						this.showrow = false;
					}
				}
			}
			datarows[i].style.display = (this.showrow)?"":"none"; // hide="" show="none"
		}
		this.stripe(this.tblObj);
		
	/*
		// hacked rendering fix for when appearing in a fixed width div
		if (mydiv = Element.getParent(thistable,"DIV")){
	//		thistable.style.marginBottom='20px';
	//		myspan.style.overflow='visible';
	//		myspan.style.overflow='auto';
			thistable.style.marginBottom = '10px';
			thistable.style.marginTop = '5px';
	
			mydiv.style.overflow='visible';
			mydiv.style.overflow='auto';
	
		}
	*/
	},
	getCellData: function(cell){
		innertext = Element.getInnerText(cell);
		numchildren = cell.childNodes.length;
		iselement = false;
		if ((numchildren==1)&&(innertext.strip()=="")){
			iselement = true;
			var elementvalue = "";
			switch (cell.firstChild.tagName.toLowerCase()){
			case 'input':
				switch (cell.firstChild.type.toLowerCase()) {
				case 'radio':
				case 'checkbox':
					elementvalue=(cell.firstChild.checked)?"checked":"unchecked";
					break;
				default:
					elementvalue=$F(cell.firstChild);
					break;
				}
				break;
			case 'select':
				elementvalue = $F(cell.firstChild);
				break;
			}
		}
		return (iselement)?elementvalue:innertext
	},
	getColumnData: function(whichcolumn){
		// Work out a type for the column
		var dataarray = new Array();
		datarows = $$('#' + this.tblObj.id + ' tbody tr');
		for (var i=0;i<datarows.length;i++){
			thisrow = datarows[i];
			cell = thisrow.cells[whichcolumn];
			dataarray[dataarray.length] = this.getCellData(cell);
		}
		return dataarray;
	},
	getColumnSortFn: function(whichcolumn){
		dataarray = this.getColumnData(whichcolumn);
		return this.getArraySortFn(dataarray);
	},
	getArraySortFn: function(inArray){ // can use enumerables here?
		// Work out a type for the column
		var sortfn;
		for (var i=0;i<inArray.length;i++){
			itm = inArray[i];
			if (this.is_date(itm)&&(sortfn!=this.sort_percentage)&&(sortfn!=this.sort_currency)&&(sortfn!=this.sort_numeric)&&(sortfn!=this.sort_caseinsensitive))
				sortfn = this.sort_date;
			else if (this.is_percentage(itm)&&(sortfn!=this.sort_currency)&&(sortfn!=this.sort_numeric)&&(sortfn!=this.sort_caseinsensitive))
				sortfn = this.sort_percentage;
			else if (this.is_currency(itm)&&(sortfn!=this.sort_numeric)&&(sortfn!=this.sort_caseinsensitive))
				sortfn = this.sort_currency;
			else if (this.is_numeric(itm)&&(sortfn!=this.sort_caseinsensitive))
				sortfn = this.sort_numeric;
			else 
				sortfn = this.sort_caseinsensitive;
		}
		return sortfn.bind(this);
	},
	// sorts array and eliminates duplicates
	compactArray: function(inArray){
		sortfn = this.getArraySortFn(inArray);
		var sortArray = inArray.sortBy(sortfn);
		var outArray = new Array();
		var outIndex = 0;
		var lastval;
		for (var i=0;i<sortArray.length;i++){
			if (lastval != sortArray[i]){
				outArray[outIndex] = sortArray[i];
				outIndex++;
			}
			lastval = sortArray[i];
		}
		return outArray;
	},
	selectsFromArray: function(whicharray){
		// create the new row
		var newRow = document.createElement("tr");
		// start to output the columns and append them to the row
		for (var column=0;column<whicharray.length;column++){
			// create a th with a form inside, with a select inside of that, with all row data inside of that
			var newTH = document.createElement("th");
//			newTH.className="filtercol";
			whicharray[column] = this.compactArray(whicharray[column]);
			if (whicharray[column].length>1){
				var sortForm = document.createElement("form");
	//			Event.observe(sortForm, 'submit', function(){return false;})
				Event.observe(sortForm, "submit", function(e){Event.stop(e);});
				var selectbox = document.createElement("select");
				selectbox.className="filter";
	//			Event.observe(selectbox, "change", this.filterTable.bind(this), false );
				// add an empty option as first option
				var blankoption = document.createElement("option");
				var selectText = document.createTextNode("show all");
				blankoption.appendChild(selectText);
				selectbox.appendChild(blankoption);
				blankoption.className="filterlabel";
	//			if (document.all)
	//				blankoption.value="filter";
	//			else
	//				sortForm.setAttribute("value","filter");
				// consolidate and alphabetize array whicharray[column]
				// create options for each item in the array
				for (var rownum=0;rownum<whicharray[column].length;rownum++){
					var selectoption = document.createElement("option");
					var newText = document.createTextNode(whicharray[column][rownum]);
					selectoption.appendChild(newText);
					selectbox.appendChild(selectoption);
					selectoption.className="filteroption";
				}
				Event.observe(selectbox, "change", this.filterTable.bind(this));
				sortForm.appendChild(selectbox);
				selectbox = null; // IE Memory Leak fix?
				newTH.appendChild(sortForm);
			} else {
				var blank = document.createTextNode(" ");
				newTH.appendChild(blank);
			}
			newRow.className="filterrow";
			newRow.appendChild(newTH);
		}
		// insert the new row
		this.tblObj.tHead.appendChild( newRow );
		newRow = null; // IE Memory Leak fix???
	},
	makeAutoFilter: function(){
//		if (this.tblObj.rows && this.tblObj.rows.length > 0) {
//			var firstDataRow = this.tableInfo["dataIndex"];
//			var numDataRows = this.tableInfo["dataRows"];
//			if (firstDataRow > 0){
				var filterArray = new Array();
				for (var j=0;j<this.tblObj.rows[0].cells.length;j++) {
					filterArray[j] = this.getColumnData(j); // store an array for each column
				}
				this.selectsFromArray(filterArray);
//				this.tableInfo["dataIndex"]++;
//			}
//		}
	},
/*	isDataRow: function(tablerow){ // checks if the row is in a thead or a tbody
		if (Element.hasClassName(tablerow,"head")||Element.hasClassName(tablerow,"foot")){
			return false;
		}
		return true;
//		return ((Element.getParent(tablerow,"THEAD") == null)&&(Element.getParent(tablerow,"TFOOT") == null))?true:false;
	},*/
	countDataRows: function(){
		var count = 0;
		datarows = $$('#' + this.tblObj.id + ' tbody tr');
		return datarows.length;
	},
//	tableDataIndex: function(){ // returns index of first row with real data or -1 if no data
//		if (this.tblObj.rows.length <= 1)
//			return -1;
//		else {
//			for (i=1;i<this.tblObj.rows.length;i++)
//				if (this.isDataRow(this.tblObj.rows[i]))
//					return i;
//		}
//		return -1;
//	},
	cellIndexFn: function(obj){ // fix for safari, where td.cellIndex always returns 0
		var isSafari = navigator.userAgent.indexOf("Safari") != -1;
		var ci = ( isSafari && obj.cellIndex == 0 ? -1 : obj.cellIndex );
		for ( var x = 0; ci == -1 && x < obj.parentElement.cells.length; x++ ){
			if ( obj === obj.parentElement.cells[x] ) {
				ci = x;
			}
		}
		return ci;
	},
	toggleCheckAll: function(chk){
		var th = Element.getParent(chk,"TH");
		var column = this.cellIndexFn(th); // fix for safari
		datarows = $$('#' + this.tblObj.id + ' tbody tr');
		if (datarows.length>0){
			firsttd = datarows[0].cells[column];
			if (firsttd.childNodes.length>0){
				firstchkbox = firsttd.childNodes[0];
				grp = firstchkbox.form.elements[firstchkbox.name];
				if(grp.length) { 
					for(boxcount=0; boxcount<grp.length; boxcount++)
						grp[boxcount].checked=chk.checked; 
				} 
				else
					grp.checked=chk.checked; 
			}
		}
	},
	resortTable: function(tdobj) {
		// get the span
		var span;
		var td;
		td = Element.getParent(tdobj,"TH"); // if TH it returns itself
		for (var ci=0;ci<td.childNodes.length;ci++)
			if (td.childNodes[ci].tagName && td.childNodes[ci].tagName.toLowerCase() == 'span') 
				span = $(td.childNodes[ci]);
		//  var spantext = getInnerText(span); // not used? Removed for now.
		//var column = td.cellIndex;
		var column = this.cellIndexFn(td); // fix for safari
//		var firstDataRow = this.tableInfo["dataIndex"];
//		var numDataRows = this.tableInfo["dataRows"];
		this.sortcolumnindex = column;
//		if (firstDataRow==-1) return;

		sortfn = this.getColumnSortFn(column);
//		var staticBottom = ((firstDataRow+numDataRows)<this.tblObj.rows.length)?(firstDataRow+numDataRows):-1;
//		table = Element.getParent(column,"TABLE");
		// enumerate the existing rows
		var newRows = $$('#' + this.tblObj.id + ' tbody tr');
		newRows = newRows.sortBy(sortfn);		
//		alert("newRows sorted first row = " + Element.getInnerText(newRows.first().cells[this.sortcolumnindex]));
		
		if (span.hasClassName("sortarrowd")) {
			// already sorted. just reverse.		
			span.className='sortarrowu';
			ARROW = '&uarr;';
//			alert("arrow switch to up. reversing");
			newRows = newRows.reverse();
		} else {
			// set default arrow
			span.className='sortarrowd';
			ARROW = '&darr;';
//			alert("arrow switch to down. not-reversing");
		}
		// prepare to insert
		mytblObj = this.tblObj;
		newRows.each(function(newrow) {
//			if (staticBottom>0)
//				mytblObj.tBodies[0].insertBefore( newrow, mytblObj.tBodies[0].rows[staticBottom] );
//			else
				mytblObj.tBodies[0].appendChild(newrow);
		});
		newRows = null;
		// Delete any other arrows there may be showing
		var allspans = $$("#" + mytblObj.id + " th span");
//		alert("clearing class names");
		var currentclass;
		for (var ci=0;ci<allspans.length;ci++) {
			if (allspans[ci]!=span){
				allspans[ci].innerHTML = '&uarr;';
				allspans[ci].style.visibility = 'hidden';
				allspans[ci].className='sortarrow';
			}
		}
		// restore clicked arrow visibility
		span.style.visibility='visible';
//		alert("class names cleared");
//		alert("writing new arrow");
		span.innerHTML = ARROW;
		span = null;
//		alert("done. restriping.");
		this.stripe(mytblObj);
	},
	sort_date: function(val,index) {
		if (val.cells)
			val = this.getCellData(val.cells[this.sortcolumnindex]);
		return this.dateVal(val);
	},
	sort_currency: function(val,index) {
		if (val.cells)
			val = this.getCellData(val.cells[this.sortcolumnindex]);
		return this.currencyVal(val);
	},
	sort_numeric: function(val,index) {
		if (val.cells)
			val = this.getCellData(val.cells[this.sortcolumnindex]);
		return this.numberVal(val);
	},
	sort_percentage: function(val,index) {
		if (val.cells)
			val = this.getCellData(val.cells[this.sortcolumnindex]);
		return this.percentVal(val);
	},
	sort_caseinsensitive: function(val,index) {
		if (val.cells)
			val = this.getCellData(val.cells[this.sortcolumnindex]);
		return this.caseInsensitiveVal(val);
	},
	is_date: function(itm){
		return ((itm.match(/^\d{1,2}[\/-]\d{1,2}[\/-]\d{2,4}$/))||(itm.match(/^[A-Za-z][\s]\d{1,2}[,\s+]\d{2,4}$/)));
	},
	is_numeric: function(itm){
		return (itm.match(/^[\d\.\,]+$/));
	},
	is_percentage: function(itm){
		return (itm.match(/[%]$/));
	},
	is_currency: function(itm){
		return (itm.match(/^[£$]/));
	},
	caseInsensitiveVal: function(aa){
		if (!aa)
			aa = "";
		aa = aa.toLowerCase();
		return aa;
	},
	percentVal: function(aa){
	//	alert("aa = " + aa + " and bb = " + bb);
		aa = aa.gsub('%','');
		return this.numberVal(aa);
	},
	numberVal: function(aa){
	//	alert("aa = " + aa + " and bb = " + bb);
		aa = aa.gsub(',','');
		aa = parseFloat(aa);
		if (isNaN(aa)) aa = 0;
		return aa;
	},
	dateVal: function(aa){
		// just returns something sortable. not a standard date value.
		if (dateparts = aa.match(/^(\d{1,2})[\/-](\d{1,2})[\/-](\d{2,4})$/)){
			dt1 = new Date(dateparts[3],dateparts[1]-1,dateparts[2]);
		} else {
			dt1 = new Date(aa); // assumes Month day, yyyy. untested...
		}
		return dt1;
	},
	currencyVal: function(aa){
		aa = aa.replace(/[^0-9.]/g,'');
		return parseFloat(aa);
	}
}

BehaviourRules = {
	'table.interactive' : function (table){
		Table.tableObjects[table.id] = new Table(table.id);
		// hack to fix IE quirks
		if (navigator.appVersion.match(/\bMSIE\b/)){
			// fix problems where table grows too large and title does not span the box anymore
			titlebox = Element.getParent(table,"div.titledbox");
			if (titlebox){
				title = $(titlebox.firstChild);
				content = $(titlebox.lastChild);
				if (Element.hasClassName(title,"title")){
					contentwidth = Element.getDimensions(content)["width"];
					title.style.width=contentwidth+'px';
				}
//				Event.observe(window, "resize", function(e){
//				});
			}
			// fix the paginator
			paginator = $(table.id+"_paginator");
			if (paginator){
				paginator.style.display="none"; // temporarily remove the paginator to see what width the tablediv should be
				tablediv = Element.getParent(table,"div.tablediv");
				tabledivwidth = Element.getDimensions(tablediv)["width"]; // normal tablediv width
				paginator.style.display="block"; // switch it back to visible
				tablewidth = Element.getDimensions(table)["width"];
				paginatorwidth = Element.getDimensions(paginator)["width"];
				if (paginatorwidth < tablewidth)
					paginator.style.width=tablewidth+'px'; // hack to fix align center
/*
				if (paginatorwidth > tabledivwidth){ // RIDICULOUS hack for large paginators. only way I can get IE to break the list into multiple lines after a page update.
					for (i=0;i<paginator.childNodes.length;i++)
						paginator.childNodes[i].style.styleFloat="left";
					paginator.style.width=tabledivwidth+'px';
					tablediv.style.width=tabledivwidth+'px';
				}
*/
			}
		}
	},
	'table.interactive td a.rowid' : function (lnk){
		tdwrapper = Element.getParent(lnk,"TD");
		while (lnk.childNodes.length>0){
			tdwrapper.insertBefore(lnk.childNodes[0],lnk);
		}
		tdwrapper.removeChild(lnk);
	},
	'table.interactive.linked td a.directlink' : function (lnk){
		tdwrapper = Element.getParent(lnk,"TD");
		datarow = Element.getParent(tdwrapper,"TR");
		Event.observe(datarow, "click", function(e){document.location.href=lnk.href;}); // formerly was mouseup, but right click was causing actions
		while (lnk.childNodes.length>0){ // then remove the link for pretty formatting.
			tdwrapper.insertBefore(lnk.childNodes[0],lnk);
		}
		tdwrapper.removeChild(lnk);
	},
	'table.interactive td a' : function (lnk){
		Event.observe(lnk, "click", function(e){
			table = Element.getParent(lnk,"TABLE");
			Table.tableObjects[table.id].linkclicked = true; // to prevent propagation to the table ajax functionality when clicking normal links in a table
		});
	},
	'form table.inputtable.interactive input,form table.inputtable.interactive td.checkgroup,form table.inputtable.interactive td.radiogroup' : function (element){
		Event.observe(element,"mousedown", function(e){ // onchange is unreliable cross-browser for checkboxes and radios (see forms.js for similar)
			table = Element.getParent(element,"TABLE");
			Table.tableObjects[table.id].linkclicked = true; // prevent propagation to the table ajax when clicking on form elements within the table, or their cells
		});
	},
	'form table.inputtable th.checkgroup' : function(th){
		var selectall = document.createElement('input');
		selectall.type="checkbox";
		th.insertBefore(selectall,th.childNodes[0]);
		table = Element.getParent(th,"TABLE");
		var thistable = Table.tableObjects[table.id];
		Event.observe(selectall, "click", function(e){ // onchange is unreliable cross-browser for checkboxes
			thistable.skipsort = true; // prevent propagation to the table ajax when clicking on form elements within the table, or their cells
			thistable.toggleCheckAll(selectall);
		});
	}
};
Behaviour.load(BehaviourRules);
function goURL(url){
	document.location.href=url;
}
// explorer clean-up
/*
function cleanUpTables(){
	if (document.all){
		autofilterselects = $$("select.filter");
		autofilterrows = $$("tr.filterrow");
		for (i=0;i<autofilterselects.length;i++){
			autofilterselects[i].removeNode(true);
		}
		for (j=0;j<autofilterrows.length;j++){
			autofilterrows[j].removeNode(true);
		}
	}
}
if (document.all){
	Event.observe(window, "beforeunload", cleanUpTables, false);
}
*/