TableSorter=function()
{
	function sorter(n){this.n=n; }
	sorter.prototype.init=function(e)
  {
    var element = $(e);
    this.table=element;
		this.tbody=$$('tbody', element)[0];
		this.thead=$$('thead', element)[0];
		this.saved_rows = []
		
		var rows = this.tbody.rows;
		for(var i = 0; i < rows.length; ++i)
		{
			this.saved_rows[i] = {
				index: i,
				row: rows[i]
			};
	  }
    var cols = this.thead.rows[0].cells;
    this.mode = 0;
    this.sort_column = null;
		for(var i = 0;i < cols.length;i++)
    {
			var cell = cols[i];
			if(!Element.hasClassName(cell, 'nosort'))
      {
        cell.onclick=new Function(this.n+'.wk(this.cellIndex)');
			}
		}
		this.updateHeader();
	};
	sorter.prototype.updateHeader=function()
	{
    var hcols = this.thead.rows[0].cells;
		for(var i = 0; i < hcols.length; ++i)
		{
			var className = 'initial';
			if (i == this.sort_column)
			{
				switch(this.mode)
				{
				case 1:
					className = "desc";
					break;
				case 2:
					className = "asc";
					break;
				}
			}
			if (hcols[i] != null && !Element.hasClassName(hcols[i], 'nosort'))
			{
				hcols[i].className = className;
			}
		}
	}
	sorter.prototype.wk=function(column_index)
  {
    if (this.sort_column != column_index)
    {
      this.sort_column = column_index;
      this.mode = 1;
    }
    else
    {
      this.mode = (this.mode + 1) % 3;
    }
		var rows = this.saved_rows;
		for(var i = 0; i < rows.length; ++i)
    {
			rows[i].value = getCellValue(rows[i].row.cells[column_index]);
    }
    switch(this.mode)
    {
    case 0:
			rows.sort(compareByIndex);
      break;
    case 1:
      rows.sort(compareByValue);
      break;
    case 2:
      rows.sort(compareByValue);
      rows.reverse();
      break;
    }
		if (this.changingMode != null)
		{
			this.changingMode(rows);
		}
		this.apply(rows);
		this.updateHeader();
		if (this.changedMode != null)
		{
			this.changedMode();
		}		
	};

  sorter.prototype.apply=function(rows_temp)
  {
    this.tbody.removeChild(this.tbody.firstChild);

	for(var i = 0; i < rows_temp.length; ++i)
    {
	  this.tbody.appendChild(rows_temp[i].row);
	}
  }
	function compareByValue(f,c)
  {
    if (f == null || f.value == null ||  c == null || c.value == null) { return 0; }
		var g,h; f=g=f.value.toLowerCase(), c=h=c.value.toLowerCase();
		var i=parseFloat(f.replace(/(\$|\,)/g,'')), n=parseFloat(c.replace(/(\$|\,)/g,''));
		if(!isNaN(i)&&!isNaN(n)){g=i,h=n}
		i=Date.parse(f); n=Date.parse(c);
		if(!isNaN(i)&&!isNaN(n)){g=i; h=n}
		return g>h?1:(g<h?-1:0)
	};
	function compareByIndex(f,c)
  {
    if (f == null || f.index == null ||  c == null || c.index == null) { return 0; }
		var g = f.index;
		var h = c.index;
		return g>h?1:(g<h?-1:0)
	};
	
  function getTextContent(node)
	{
    return node.innerText || node.textContent;
  };
	
	function getCellValue(cell)
	{
		//var text = cell.textContent;
		//return text.replace(/[ \n\r]+/g, '');
		if (cell)
		{
			var text = cell.innerText || cell.textContent || '';
			return text.replace(/[ \n\r]+/g, '');
		}
		else
		{
			return "";
		}
		for (var value = cell;
				 value != null && value.hasChildNodes();
				 )
		{
			var ci = 0;
			for(ci = 0;
					ci < value.childNodes.length;
					++ci)
			{
				switch(value.childNodes[ci].tagName)
				{
				case 'img':
				case 'br':
					continue;
				default:
					break;
				}
			}
			value = value.childNodes[ci];
		}
		if (value && value.nodeValue)
		{
			return value.nodeValue;
		}
		else
		{
			return '';
		}		
	};
	return{sorter:sorter}
}();