if (document.ELEMENT_NODE == null) {
  document.ELEMENT_NODE = 1;
  document.TEXT_NODE = 3;
}
var whtSpEnds = new RegExp("^\\s*|\\s*$", "g");
var whtSpMult = new RegExp("\\s\\s+", "g");
var colClsNm = "sortedColumn";
var colTest = new RegExp(colClsNm, "");
// tableId == the id of the table element i.e. <table id="myTable">
// columnId == the ordinal of the column.
// note: the first column starts at 0 not 1.
function sortTable(tableId, columnId) {
  var tableBody = document.getElementById(tableId).tBodies[0];
  if (tableBody.reverseSort == null) tableBody.reverseSort = new Array();
  if (columnId == tableBody.lastColumn) tableBody.reverseSort[columnId] = !tableBody.reverseSort[columnId];
  tableBody.lastColumn = columnId;
  // Netscape 6 gets funkalious if we don't hide the table first
  var oldDisplay = tableBody.style.display;
  tableBody.style.display = "none";
  // Sort the rows based on the content of the specified column using a selection sort.
  var tempElement;
  var i, j;
  var minValue, minIndex;
  var testValue;
  var compareResults;
  for (i = 0; i < tableBody.rows.length - 1; i++) {
    minIndex = i;
    minValue = getTextValue(tableBody.rows[i].cells[columnId]);
    // Search rows for a smaller value.
    for (j = i + 1; j < tableBody.rows.length; j++) {
      testValue = getTextValue(tableBody.rows[j].cells[columnId]);
      compareResults = compareValues(minValue, testValue);
      if (tableBody.reverseSort[columnId]) compareResults = -compareResults; // Reverse order?
      // If this row is a smaller value than the current min, update the current minimum value.
      if (compareResults > 0) {
        minIndex = j;
        minValue = testValue;
      }
    }
    if (minIndex > i) {
      tempElement = tableBody.removeChild(tableBody.rows[minIndex]);
      tableBody.insertBefore(tempElement, tableBody.rows[i]);
    }
  }
  // Done! Now show the table
  highlightColumn(tableBody, columnId);
  tableBody.style.display = oldDisplay;
  return false;
}
function getTextValue(Element) {
  var i;
  var Value;
  // Find and concatenate the values of all text nodes contained within the element.
  Value = "";
  for (i = 0; i < Element.childNodes.length; i++)
    if (Element.childNodes[i].nodeType == document.TEXT_NODE)
    Value += Element.childNodes[i].nodeValue;
  else if (Element.childNodes[i].nodeType == document.ELEMENT_NODE && Element.childNodes[i].tagName == "br")
    Value += " "; // we replace this element because it's empty and will break us, precious.
  else
  // recurse to get text within sub-elements.
    Value += getTextValue(Element.childNodes[i]);
  return normalizeString(Value);
}
function compareValues(Value1, Value2) {
  var m_arrDate = Value1.split("/");  // cheesy but it works for what i'm using it for.
  if (m_arrDate.length == 3) {            // i'm cheking if the value can create a three column
    Value1 = new Date(Value1);      // array. if it can then i'm assuming it's a date.
    Value2 = new Date(Value2);      // like i said...cheesy.
  } else {
    var Float1, Float2;
    Float1 = parseFloat(Value1);      // If the values can be cast to a float then
    Float2 = parseFloat(Value2);      // we compare as an integer.
    if (!isNaN(parseFloat(Float1)) && !isNaN(parseFloat(Float2))) {
      Value1 = Float1;
      Value2 = Float2;
    }
  }
  if (Value1 == Value2)
    return 0;
  if (Value1 > Value2)
    return 1
  return -1;
}
function normalizeString(Value) {
  Value = Value.replace(whtSpMult, " ");  // Collapse white spaces.
  Value = Value.replace(whtSpEnds, "");   // Trim white space.
  return Value;
}
function highlightColumn(tableBody, columnId) {
  var i, j;
  var rowElement, cellElement;
  // Set style classes on each row to alternate their appearance.
  for (i = 0; i < tableBody.rows.length; i++) {
    rowElement = tableBody.rows[i];
    for (j = 0; j < tableBody.rows[i].cells.length; j++) {
      cellElement = rowElement.cells[j];
      cellElement.className = cellElement.className.replace(colTest, "");
      if (j == columnId)
        cellElement.className += " " + colClsNm;
      cellElement.className = normalizeString(cellElement.className);
    }
  }
  // Find the table header and highlight the column that was sorted.
  var el = tableBody.parentNode.tHead;
  rowElement = el.rows[el.rows.length - 1];
  // removes the class from the cell.
  for (i = 0; i < rowElement.cells.length; i++) {
    cellElement = rowElement.cells[i];
    if (cellElement.className != "nonSortable" && cellElement.className != "options") cellElement.className = cellElement.className = "";
    // Highlight the header of the sorted column.
    if (i == columnId) {
      cellElement.className += " " + colClsNm;
      if (cellElement.getElementsByTagName("img")[0]) {
        if (tableBody.reverseSort[columnId]) cellElement.getElementsByTagName("img")[0].className = "arrowDn";
        else cellElement.getElementsByTagName("img")[0].className = "arrowUp";
      }
    }
    cellElement.className = normalizeString(cellElement.className);
  }
}
