/* Easy CSS class manipulation functions */
function Highlight(oObj, sClass)
{
	if(typeof oObj=='string') oObj = document.getElementById(oObj);
	if(oObj==null) return;
  if(sClass == null || sClass == '') sClass = 'highlight';
  if(oObj.className.match(RegExp('\\b' + sClass + '\\b')) == null) oObj.className += ' ' + sClass;
}
function Unhighlight(oObj, sClass)
{
	if(typeof oObj=='string') oObj = document.getElementById(oObj);
	if(oObj==null) return;
  if(sClass == null || sClass == '') sClass = 'highlight';
  oObj.className = oObj.className.replace(RegExp('\\b' + sClass + '\\b', 'g'), '');
}
function IsHighlighted(oObj, sClass)
{
	if(typeof oObj=='string') oObj = document.getElementById(oObj);
	if(oObj==null) return;
  if(sClass == null || sClass == '') sClass = 'highlight';
  return(oObj.className.match(RegExp('\\b' + sClass + '\\b')) != null);
}

function Hover(oObj)		{ Highlight(oObj, 'hover'); }
function Unhover(oObj)	{ Unhighlight(oObj, 'hover'); }

/* Client side sortable tables */

/** SortTable() Usage:
<style>
 th.sort_a, th.sort_d
  { background-position: right center; background-repeat: no-repeat; padding-right: 18px; }
 sort_a { background-image: url(img/sort_a.png); }
 sort_d { background-image: url(img/sort_d.png); }
 .sortval	{ display: none; }
 body.debug .sortval	{ color: gray; font-size: x-small; display: inline; }

.bla tbody td a:hover { background-color: red; }
.bla tbody td a:hover img { background-color: white; }

</style>
<table>
 <thead>
  <tr>
   <th onclick="SortTable(this);">bla1</th>
   <th class="sortval">date(SQL)</th>			<!-- Two different ways to sort other values -->
   <th onclick="SortTable(this, -1);">date1</th> <!-- Sort on previous (invisible) column -->
   <th onclick="SortTable(this);">date2</th>     <!-- Sort on firstChild with class="sortval" -->
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>bla</td>
   <td class="sortval">2004-10-10</td>
   <td>10-10-2004</td>
   <td><span class="sortval">2004-10-10</span>10-10-2004</td> <!-- tag with sortval class MUST be first in TD ! -->
  </tr>
  <tr>
   <td>trala</td>
   <td class="sortval">2003-08-05</td>
   <td>5-8-2003</td>
   <td><span class="sortval">2003-08-05</span>5-8-2003</td>
  </tr>
 </tbody>
</table>
 
* Works fine for more than one table per page.
*/
function SortTable(oObj, iColDelta)
{
	bTime=0;
	if(bTime) {
		var dStart=new Array();
		var dEnd=new Array();
		dStart[dStart.length] = new Date();
	}
	
	// Find the cell object (TH or TD)
	var oCell = oObj;
	while(oCell.nodeName!="TH" && oCell.nodeName!="TD") {
		if(oCell.nodeName=="BODY")
			return;
		oCell = oCell.parentNode;
	}
	
	// Find the table object
	var oTable = oCell;
	while(oTable.nodeName!="TABLE") {
		if(oTable.nodeName=="BODY")   
			return;
		oTable = oTable.parentNode;
	}
	
	// Find the column number to sort (0-based) and sort direction
	iCol=-1;
	oRow=oCell.parentNode;
	x2=0;	// Take colspan into account
	for(x = 0; x<oRow.cells.length; x++) {
		if(oRow.cells[x]==oCell) {
			iCol = x2;
		  sDir = (oCell.className.match(RegExp('\\bsort_a\\b'))==null) ? 'a' : 'd';
		}
		Unhighlight(oRow.cells[x], 'sort_a');
		Unhighlight(oRow.cells[x], 'sort_d');
		x2+=oRow.cells[x].colSpan;
	}
	
	if(iCol<0) return;
	
	if(typeof(iColDelta) == 'number')
		iCol += iColDelta;
	
	if(sDir=='a')
		funCompare = function(a,b)	{
																	if(a['cmp']>b['cmp']) return 1;
																	if(a['cmp']<b['cmp']) return -1;
																	return 0;
																};
	else
		funCompare = function(a,b)	{
																	if(a['cmp']>b['cmp']) return -1;
																	if(a['cmp']<b['cmp']) return 1;
																	return 0;
																};
	
	aRows = new Array();
	for(var b=0; b<oTable.tBodies.length; b++) {	// For all tBodies
		oTBody = oTable.tBodies[b];
		if(oTBody.className.match(RegExp('\\bnosort\\b'))==null)
		{
			iRows = oTBody.rows.length;
			if(iRows <= 1) continue;
			
			for(var y=iRows-1; y>=0; y--) {	// for all rows backwards
//				oRow = oTBody.removeChild(oTBody.rows[y]); // Doesn't work in IE! Might speed up a little?
				oRow = oTBody.rows[y];
				
				sSortType = 'string';
				oVal = oRow.cells[iCol];
				if(oVal.className.match(RegExp('\\amount\\b')) != null)
					sSortType = 'amount';
				
				// If the firstChild has className sortval, then use that value to sort with!
				oValChild = oVal.firstChild;
				if(oValChild != null
					&& oValChild.className != null
					&& oValChild.className.match(RegExp('\\bsortval\\b')) != null
					)
					oVal = oValChild;
				if(oVal.className.match(RegExp('\\amount\\b')) != null)
					sSortType = 'amount';
				
	      xCell = oRow.cells[iCol].innerHTML;
	      xCell = xCell.replace(RegExp('\<[^\>]*\>', 'g'), ''); // FILTER HTML Tags !  
				if(sSortType == 'amount')
				{
					xCell = parseFloat(xCell);
					if(isNaN(xCell))
						xCell = 0;
				}
				else
		      xCell = xCell.toLowerCase();  
				
				aRows[y] = new Array();
				aRows[y]['obj']		= oRow;
				aRows[y]['cmp']		= xCell;
			}
			
			aRows.sort(funCompare);
			
			if(bTime) {
				dEnd[dEnd.length] = new Date();
				dStart[dStart.length] = new Date();
			}
			
			for(var y=0; y<iRows; y++) {	// for all rows (fix odd/even classNames)
				oRow = aRows[y]['obj'];
				// Odd/Even is 1-based on screen -- row 0 is odd !!!
		  	if((y%2==1) && oRow.className.match(RegExp('\\bstRowOdd\\b'))!=null) {
					Unhighlight(oRow, 'stRowOdd');
					Highlight(oRow, 'stRowEven');
				} else if((y%2==0) && oRow.className.match(RegExp('\\bstRowEven\\b'))!=null) {
					Unhighlight(oRow, 'stRowEven');
					Highlight(oRow, 'stRowOdd');
				}
				oTBody.appendChild(oRow);
			}
		}
	}
	
	Highlight(oCell, 'sort_' + sDir);

	if(bTime) {
	  dEnd[dEnd.length] = new Date();
		var sDiff='';
		for(i=0; i<dStart.length; i++) {
			sDiff += 'i: ' + DateDiffString(dStart[i], dEnd[i]) + '\n';
		}
		alert(sDiff);
	}
}

/* Client side filter for tables
* Keeps the currently used filter text in a cookie specific for that URL, use 
* sFilter=0 (see below) on page load to recall it.
* oObj object table or something inside the table
* sFilter string Filter text
*                 null and oObj is an <input>, use value of oObj.
*                 -1 (numeric) delete the cookie (no filtering done)
*                  0 (numeric) retrieve last filter from cookie (also sets oObj.value if it's an INPUT tag)
*                  1 (numeric) force repeat of last filter
* @return string Currently active filter text
*/
function SetFilter(oObj, sFilter)
{
  // Find the table object
  var oTable = oObj;
  while(oTable.nodeName!="TABLE") {
    if(oTable.nodeName=="BODY")   
      return null;
    oTable = oTable.parentNode;
  }
  
	sCookieName = 'Filter_' + oTable.id + '_' + escape(document.location);
	
  if(sFilter==null && oObj.nodeName=="INPUT")
    sFilter=oObj.value;
  
  if(typeof(sFilter) == 'string')
  	sFilter=sFilter.toLowerCase()
  
  if(typeof sFilter=='number')
    if(sFilter==-1)
    {
      delCookie(sCookieName);
      return null;
    }
    else if(sFilter==0)
    {
      sFilter=getCookie(sCookieName);
      if(oObj.nodeName=="INPUT")
        oObj.value=sFilter;
    }
    else if(sFilter==1)
      if(typeof oTable.sCurrentFilter == 'undefined')
        sFilter = "";
      else
        sFilter = oTable.sCurrentFilter;
   else if(oTable.sCurrentFilter == sFilter)
     return sFilter;
  
  oTable.sCurrentFilter = sFilter;
  setCookie(sCookieName, sFilter);
  var iFiltered=0;
  
  // Filter all TBodies (without 'nofilter' as className)
  iMatches=0;
  for(var b=0; b<oTable.tBodies.length; b++) {
    oTBody = oTable.tBodies[b];
    if(oTBody.className.match(RegExp('\\bfilter-empty\\b'))!=null)
    {
      if(iMatches>0)
        Unhighlight(oTBody, 'filter-isempty');
      else
        Highlight(oTBody, 'filter-isempty');
    }
    else if(oTBody.className.match(RegExp('\\bnofilter\\b'))==null)
    {
      iRows = oTBody.rows.length;
      if(iRows < 1) continue;
      for(var y=0; y<iRows; y++) {
        oRow = oTBody.rows[y];
        iCols = oRow.cells.length;
        bMatch=0;
        for(var x=0; x<iCols; x++) {
          sCell=oRow.cells[x].innerHTML;
          sCell=sCell.replace(RegExp('\<[^\>]*\>', 'g'), ''); // FILTER HTML Tags !  
          sCell=sCell.toLowerCase();  
          if(sCell.indexOf(sFilter) >= 0) {
            bMatch=1;
            iMatches++;
            break;
          }
        }
        if(bMatch)
          Unhighlight(oRow, 'filter-mismatch');
        else
        {
          Highlight(oRow, 'filter-mismatch');
         	iFiltered++;
        }
      }
    }
  }
  
	if(iFiltered>0)
		Highlight(oTable, 'filter-active');
	else
		Unhighlight(oTable, 'filter-active');
	
  return sFilter;
}

function getCookie(sName)
{
	re = new RegExp("(^| )" + sName + "=([^;\n]*)(;|\n|$)");
	document.cookie.match(re);
	return(unescape(RegExp.$2));
}


function setCookie(sName, sValue, iExpireDays)
{
	var dExpireDate = new Date ();
	dExpireDate.setTime(dExpireDate.getTime() + (iExpireDays * 24 * 3600 * 1000));
	document.cookie = sName + "=" + escape(sValue) +
		((iExpireDays == null) ? "" : "; expires=" + dExpireDate.toGMTString());
}

function delCookie(sName)
{
	if (getCookie(sName)) {
		document.cookie = sName + "=; expires=Thu, 01-Jan-70 00:00:01 GMT";
	}
}

/* Date functions */
function DateDiffString(dStart, dEnd)
{
	var sDiff;
	var dDiff = new Date(dEnd.getTime() - dStart.getTime());
  var sMilliSec = parseInt((((dDiff.getMinutes() * 60) + dDiff.getSeconds()) * 1000) + dDiff.getMilliseconds()) + "";
  while(sMilliSec.length < 4) {
		sMilliSec = '0' + sMilliSec;
	}
  iLen = sMilliSec.length;
  
	sDiff = "" + sMilliSec.substring(0, iLen-3) + '.' + sMilliSec.substring(iLen-3) + ' sec.';
	return sDiff;
}