// Filename: dyntable.js
// Function: Sortable Scrolling Table
// Author: Kurt Brunner
// Application: ReMark, LabDesk, EnglishWeb
// Version: 2.1
// Created: 10/30/2006 
// Modified: 12/11/2006
// Changes: Added Fullscreen Mode 
// Use: var name = new dynTable(<id or node>);
//      name.setHeight(height)
//      name.fullScreen(callback) 
//	name.linkColumn(column,[replace])
//	name.setCallback(callback,column)
//	name.selectRow(array)
//	name.findRow(search,[column])
//	name.singleSelect([force])
//	name.multiSelect()
//	name.disableSelect()
//	name.clearSelection()
//	name.getSelected(column)
//	name.enableSort()
//	name.disableSort()
//	name.Sort(column) 
//--------------------------------------------

function dynTable(table)
{
	var multiSelect = false;
	var forceSelect = false;
	
	table = document.getElementById(table) || table;
	if(table && table.tagName)
	{
		var divArea = document.createElement('div');
		var divHead = document.createElement('div');
		var divData = document.createElement('div');
		var divFoot = document.createElement('div');
		var rowClass = new Array();
		divArea.appendChild(divHead);
		divArea.appendChild(divData);
		divArea.appendChild(divFoot);
		var parNode = table.parentNode;
		parNode.replaceChild(divArea,table);
		divData.style.overflow = 'auto';
		divData.appendChild(table);
		divArea.style.width = table.offsetWidth * 100 + 'px';		
		setTableWidth();
		divArea.style.width = table.offsetWidth + 19 + 'px';				
		var header = table.cloneNode(true);
		while(header.rows.length>1)
			header.deleteRow(1);
		divHead.appendChild(header);
		table.deleteRow(0);
		storeRowClass();
		setTableHeader();
		setTableBorder();
		setTableMouseover();
		var footer = header.cloneNode(true);		
		divFoot.style.height = '1px';
		divFoot.style.overflow = 'hidden';
		divFoot.appendChild(footer);
	}
	
	function setTableWidth()
	{
		for(var c=0;c<table.rows[0].cells.length;c++)
		{
			var width = table.rows[0].cells[c].offsetWidth;
			table.rows[0].cells[c].width = width;
			table.rows[1].cells[c].width = width;
		}
	}
	
	function setTableBorder()
	{
		var last = table.rows.length - 1;
		for(var c=0;c<table.rows[0].cells.length;c++)
		{
			table.rows[0].cells[c].style.borderTop = 'none';
			table.rows[last].cells[c].style.borderBottom = 'none';
		}
		table.rows[0].style.borderTop = 'none';
		table.rows[last].style.borderBottom = 'none';
		table.style.borderTop = 'none';
		table.style.borderBottom = 'none';
	}
	
	function setTableHeader()
	{
		for(var c=0;c<header.rows[0].cells.length;c++)
		{
			header.rows[0].cells[c].sortType = getColumnType(c);
			header.rows[0].cells[c].sortAsc = false;
			header.rows[0].cells[c].column = c;
		}
	}
	
	function storeRowClass()
	{
		for(var r=0;r<table.rows.length;r++)
			rowClass[r] = table.rows[r].className;
	}
	
	//------------------
	// Mouseover Effects
	//------------------
	function setTableMouseover()
	{
		for(var r=0;r<table.rows.length;r++)
		{
			table.rows[r].onmouseover = rowHighlight;
			table.rows[r].onmouseout = rowNormal;
		}
	}
	
	function rowHighlight()
	{
		this.oldClass = this.className
		this.className = 'hover';
	}

	function rowNormal()
	{
		this.className = this.oldClass;
		this.removeAttribute('oldClass');
	}	
	
	//-----------------------
	// Table Height Functions
	//-----------------------
	this.setHeight = function(height)
	{
		if(height)
		{
			divData.style.height = '0';
			if(typeof height == 'string')
				divArea.style.height = height;
			if(typeof height == 'number')
				divArea.style.height = height + 'px';		
			var dataHeight = divArea.offsetHeight - (1 + header.offsetHeight);
			if(dataHeight<table.offsetHeight)
			{
				divData.style.height = dataHeight + 'px';
				return;
			};
		};
		divArea.style.height = '';	
		divData.style.height = '';	
	};
	
	this.fullScreen = function(callback)
	{
		divArea.style.height = '';	
		divData.style.height = '';	
		document.body.scroll = 'no';
		document.body.style.height = '100%';
		document.body.style.margin = '0px';
		document.body.style.overflow = 'hidden';
		var temp = document.createDocumentFragment();
		temp.appendChild(divArea);
		document.body.innerHTML = ''
		document.body.appendChild(divArea);
		adjustScreen();
		window.onresize = adjustScreen;
		if(callback)
			callback(divArea.offsetWidth,divArea.offsetHeight);
//		if(parent.setFrameSize)
//			parent.setFrameSize(divArea.offsetWidth,divArea.offsetHeight);		
//		if(parent.document.bgColor)
//			document.body.style.backgroundColor = parent.document.bgColor;
	};

	function adjustScreen()
	{
		var height = getWindowHeight() - (1 + header.offsetHeight);
		if(height<table.offsetHeight)
			divData.style.height = height + 'px';
		else
			divData.style.height = '';	
	};

	//--------------------
	// Table Link Functions
	//--------------------
	this.linkColumn = function(column,replace)
	{
		for(var r=0;r<table.rows.length;r++)
		{
			var links = table.rows[r].cells[column].getElementsByTagName('a');
			if(links.length>0) 
			{
				table.rows[r].value = links[0].href;
				table.rows[r].target = links[0].target;
				table.rows[r].cells[column].innerHTML = links[0].innerHTML;
				if(replace) table.rows[r].onclick = eventReplace
				else        table.rows[r].onclick = eventLoad;
				try      { table.rows[r].style.cursor = 'pointer' }
				catch(e) { table.rows[r].style.cursor = 'hand' }
			};
		};	
	};
	
	this.setCallback = function(callback,column)
	{
		for(var r=0;r<table.rows.length;r++)
		{
			var value = new String(r);
			if(column>=0) value = getInnerText(table.rows[r].cells[column]);
			if(!isWhitespace(value))
			{
				table.rows[r].value = value;
				table.rows[r].onclick = callback;
				try      { table.rows[r].style.cursor = 'pointer' }
				catch(e) { table.rows[r].style.cursor = 'hand' }	
			};
		};
	};

	//-----------------------
	// Table Select Functions
	//-----------------------
	this.selectRow = function(arr)
	{
		clearSelection();
		if(arr.length)
		{
			for(var i=0;i<arr.length;i++)
				if(table.rows[parseInt(arr[i])+0])
					table.rows[parseInt(arr[i])+0].selected = true;
		}
		else
		{
			for(var i=0;i<arguments.length;i++)
				if(table.rows[parseInt(arguments[i])+0])
					table.rows[parseInt(arguments[i])+0].selected = true;
		};
		drawTable();
		scrollToFirst();
	};
	
	this.findRow = function(search,column)
	{
		clearSelection();
		if(column>=0)
		{
			for(var r=0;r<table.rows.length;r++)
				if(getInnerText(table.rows[r].cells[column]) == search)
					table.rows[r].selected = true;
		}
		else
		{
			for(var r=0;r<table.rows.length;r++)
				for(var c=0;c<table.rows[r].cells.length;c++)
					if(getInnerText(table.rows[r].cells[c]) == search)
						table.rows[r].selected = true;
		};
		drawTable();
		scrollToFirst();
	};
	
	this.singleSelect = function(force)
	{
		if(force) forceSelect = true 
		else forceSelect = false;
		multiSelect = false;
		for(var r=0;r<table.rows.length;r++)
		{
			table.rows[r].onclick = eventSelect;
			try      { table.rows[r].style.cursor = 'pointer' }
			catch(e) { table.rows[r].style.cursor = 'hand' }	
		};
	};

	this.multiSelect = function()
	{
		multiSelect = true;
		forceSelect = false;
		for(var r=0;r<table.rows.length;r++)
		{
			table.rows[r].onclick = eventSelect;
			try      { table.rows[r].style.cursor = 'pointer' }
			catch(e) { table.rows[r].style.cursor = 'hand' }	
		};
	};

	this.disableSelect = function()
	{
		for(var r=0;r<table.rows.length;r++)
		{
			table.rows[r].onclick = null;
			table.rows[r].style.cursor = null;
		};
	};	
	
	this.clearSelection = function()
	{
		clearSelection();
		drawTable();
	}
	
	this.getSelected = function(column)
	{
		var myArray = new Array();
		if(column>=0)
		{
			for(var r=0;r<table.rows.length;r++)
				if(table.rows[r].selected)
					myArray[myArray.length] = getInnerText(table.rows[r].cells[column]);
		}
		else
		{
			for(var r=0;r<table.rows.length;r++)
				if(table.rows[r].selected)
					myArray[myArray.length] = r-0;
		};
		return myArray;
	};
	
	function clearSelection()
	{
		for(var r=0;r<table.rows.length;r++)
			table.rows[r].removeAttribute('selected');
	};

	function scrollToFirst()
	{
		for(var r=0;r<table.rows.length;r++)
		{
			if(table.rows[r].selected)
			{
				scrollToRow(r);
				break;
			}
		}
	};
	
	function scrollToRow(row)
	{
		var rowHeight = table.offsetHeight / table.rows.length;
		var topMargin = (divData.offsetHeight - rowHeight) /2;
		var rowPosition = rowHeight * row;
		divData.scrollTop = Math.round(rowPosition - topMargin)+1;
	};

	function eventSelect()
	{
		if(this.selected && !forceSelect)
			this.removeAttribute('selected');
		else
		{
			if(!multiSelect) clearSelection();
			this.selected = true;
		};
		drawTable();
	};	

	function drawTable()
	{
		for(var r=0;r<table.rows.length;r++)
		{
			if(table.rows[r].selected) 
			{
				if(table.rows[r].className == 'hover')
					table.rows[r].oldClass  = 'selected'
				else		
					table.rows[r].className = 'selected';
			}
			else
			{
				if(table.rows[r].className == 'hover')
					table.rows[r].oldClass = rowClass[r]
				else
					table.rows[r].className = rowClass[r];
			}
		}
	}
	
	function eventLoad() 
	{ 
		switch(this.target)
		{
			case '_blank':	window.open(this.value);
							break;
			case '_top':	top.location.assign(this.value)
							break;
			default:	location.assign(this.value); 
		}
	}
	function eventReplace() { location.replace(this.value); }

	//-----------------
	// Sorting Function
	//-----------------
	this.enableSort = function()
	{
		for(var c=0;c<header.rows[0].cells.length;c++)
		{
			header.rows[0].cells[c].onclick = eventSort;
			try      { header.rows[0].cells[c].style.cursor = 'pointer' }
			catch(e) { header.rows[0].cells[c].style.cursor = 'hand' }
		}
	};
	
	this.disableSort = function()
	{
		for(var c=0;c<header.rows[0].cells.length;c++)
		{
			header.rows[0].cells[c].onclick = '';
			header.rows[0].cells[c].style.cursor = '';
		}
	};
	
	this.Sort = function(column) { Sort(column); };
	function eventSort() { Sort(this.column); }

	function Sort(column)
	{	
		var data = new Array();
		var style = new Array();
		for(var c=0;c<table.rows[0].cells.length;c++)
		{
			style[c] = table.rows[0].cells[c].style.cssText;
			table.rows[0].cells[c].style.cssText = '';	
		}
		for(var r=0;r<table.rows.length;r++)
			data[data.length] = new objData(table.rows[r],column);
		data.sort(header.rows[0].cells[column].sortType);
		if(header.rows[0].cells[column].sortAsc)
			data.reverse();
		header.rows[0].cells[column].sortAsc = !header.rows[0].cells[column].sortAsc;
		for(var r=0;r<table.rows.length;r++)
		{
			var parent = table.rows[r].parentNode;
			parent.replaceChild(data[r].node,table.rows[r]);
			table.rows[r].onmouseover = data[r].onmouseover;			
			table.rows[r].onmouseout = data[r].onmouseout;
			table.rows[r].onclick = data[r].onclick;
			table.rows[r].value = data[r].value;
			table.rows[r].selected = data[r].selected;
		};
		for(var c=0;c<table.rows[0].cells.length;c++)
			table.rows[0].cells[c].style.cssText = style[c];		
		drawTable();
	}

	function objData(row,column)
	{
		this.data = getInnerText(row.cells[column]);
		this.node = row.cloneNode(true);
		this.onmouseover = row.onmouseover;
		this.onmouseout = row.onmouseout;
		this.onclick = row.onclick;
		this.value = row.value;
		this.selected = row.selected;
		return this;
	}
	
	function sortDefault(a,b) 
	{
	    var x = a.data;
	    var y = b.data;
	    return ((x > y) ? 1 : ((x < y) ? -1 : 0));
	}

	function sortAsString(a,b)
	{
	    var x = a.data.toLowerCase();
	    var y = b.data.toLowerCase();
	    return ((x > y) ? 1 : ((x < y) ? -1 : 0));
	}

	function sortAsDate(a,b)
	{
	    var x = new Date(a.data);
	    var y = new Date(b.data);
	    return (isNaN(x) && isNaN(y) ? 0 : isNaN(x) ? 1 : isNaN(y) ? -1 : x-y);
	}

	function sortAsCurrency(a,b)
	{ 
    	x = parseFloat(a.data.replace(/[^0-9.]/g,''));
    	y = parseFloat(b.data.replace(/[^0-9.]/g,''));
	    return (isNaN(x) && isNaN(y) ? 0 : isNaN(x) ? 1 : isNaN(y) ? -1 : x-y);
	}

	function sortAsNumber(a,b)
	{ 
    	x = parseFloat(a.data);
    	y = parseFloat(b.data); 
	    return (isNaN(x) && isNaN(y) ? 0 : isNaN(x) ? 1 : isNaN(y) ? -1 : x-y);
	}

	//---------------
	// Table Analysis
	//---------------
	function getColumnType(column)
	{
		if(isColumnEmpty(column)) return sortDefault;
		if(isColumnDate(column)) return sortAsDate;
		if(isColumnCurrency(column)) return sortAsCurrency;
		if(isColumnNumber(column)) return sortAsNumber;
		return sortAsString;
	}
	
	function isColumnEmpty(column)
	{
		for(var r=0;r<table.rows.length;r++)
		{
			var cell = getInnerText(table.rows[r].cells[column]);
			if(!isWhitespace(cell))
				return false;
		};
		return true;
	}
	
	function isColumnDate(column)
	{
		for(var r=0;r<table.rows.length;r++)
		{
			var cell = getInnerText(table.rows[r].cells[column]);
			if(!isWhitespace(cell))
			{
				var d = new Date(cell);
				if(isNaN(d))
					return false;
			};
		};
		return true;
	}

	function isColumnCurrency(column)
	{
		for(var r=0;r<table.rows.length;r++)
		{
			var cell = getInnerText(table.rows[r].cells[column]);
			if(!isWhitespace(cell))
				if(!cell.match(/^[£$]/))
					return false;
		};
		return true;
	}
	
	function isColumnNumber(column)
	{
		for(var r=0;r<table.rows.length;r++)
		{
			var cell = getInnerText(table.rows[r].cells[column]);
			if(!isWhitespace(cell))
			    if(isNaN(cell - cell))
			    	return false;
		};
		return true;
	}
}

//----------------
// Basic Functions
//----------------
function isNumber(n) { return !isNaN(t-t); }
function isWhitespace(n) { return n.match(/^[\s\xA0]*$/g) != null; }

function getInnerText(node)
{
	if(node.nodeType == 3)
		return node.nodeValue
	else
	{
		var str = new String('');
		for(var i=0;i<node.childNodes.length;i++)
			str += getInnerText(node.childNodes[i]);
		return str;
	}
}

function getOuterHTML(node)
{
	var d = document.createElement('div');
	d.appendChild(node.cloneNode(true));
	return d.innerHTML;
}

function getWindowHeight()
{
	if(self.innerHeight)
		return self.innerHeight
	else if(document.documentElement && document.documentElement.clientHeight)
		return document.documentElement.clientHeight
	else if(document.body)
		return document.body.clientHeight;
}
