/********
FILENAME: autoSort.js
VERSION:  1.2
AUTHOR:   Kevin Hastie
CREATED:  2004-07-07
MODIFIED: 2004-07-22 by Kevin Hastie
SUMMARY:  Autosorting and autohighlighting script

DESCRIPTION: 
Client-side sorting script to sort tables without making calls to the server. Includes code to automatically alternate row colors/styles and to highlight the column headers.

CHANGELOG:
1.2   - Column header now highlights to indicate which column the data is sorted on
      - Modified to support Mozilla
1.1   - Addressed IE5 multi-threading ug

********/

  if (is_mac_ie5x) { // Hide table header links in Mac IE5.x - this will disable the sorting
    document.writeln("<style type=\"text/css\">.sorterLink {text-decoration: none;}</style>");
  }

	var allowSorting = false;
	var functionString;
	var sortedOn = 0; // Remembers column # you are currently sorted by. Initally 1st column. Zero-indexed.
  var secondarySort = 0; // The column to do a secondary sort on.  Also zero-indexed.
	var numColumns = 4;
	var sortDirection = 'inc';
  var imgArrowInc = '/features/overviews/images/arrow_up.gif';
  var imgArrowDec = '/features/overviews/images/arrow_down.gif';

	// Sort the table with id=tableId by the values in column number sortOn
	function SortTable(tableId, sortOn) {
    if (!is_mac_ie5x) { // disable sorting for Mac IE5.x browsers

  		var table = document.getElementById(tableId);
  		var tbody = table.getElementsByTagName('tbody')[0]; // Only the rows in <TBODY> will be affected
  		var rows = tbody.getElementsByTagName('tr');
  
  		// Make a copy of the array of row elements
  		var rowArray = new Array();
  		for (var i=0, length=rows.length; i<length; i++) {
  			rowArray[i] = rows[i].cloneNode(true);
  		}
  
  		// If already sorted by this column, reverse the order & float TBD values for cols 3 & 2
  		if (sortOn == sortedOn) {

  			rowArray.reverse();

        flipSortArrow(sortedOn);
        
        if (sortedOn == 3 || sortedOn == 2) {
          rowArray.sort(RowCompareTBD);
        }
          
  		// Otherwise sort by this column
  		} else {
  			sortedOn = sortOn;
  			sortDirection = 'inc';
  
  			// Customize this to sort using the appropriate comparison function
  			// In this example, column 0 is a number, column 3 is a dollar amount,
  			// and all other rows are regular strings to be sorted alphanumerically
        // Float TBA/TBD values to the bottom for columns 2 & 3
        if (sortedOn == 3 || sortedOn == 2) {
          rowArray.sort(RowCompareTBD);
        } else if (sortedOn == 0) {
          rowArray.sort(RowCompareLinkIds);
  			} else { // default sort
  				rowArray.sort(RowCompare);
  			}
 
  			// Turn all arrows off, except this column's, which should display increasing
  			toggleSortArrowsOff();
  			toggleSortArrowOn(sortOn);
  		}

  		// Build a new <TBODY> and replace the old one
  		var newTbody = document.createElement('tbody');
  		for (var i=0, length=rowArray.length; i<length; i++) {
  			newTbody.appendChild(rowArray[i]);
  		}
  		table.replaceChild(newTbody, tbody);
    }

 		// Optional: alternate the classes of the rows (in the <TBODY> only)
 		// starting at row 0 (the first non-header row, therefore considered to be odd)
 		alternateRowClasses(tableId, 0, 'oddRow', 'evenRow');

    // Highlight appropriate column header
    highlightColumnHeader(tableId, sortOn);
    				
		// Ensures that the page is not refreshed when onClick="return SortTable(...)" is used
		return false;
	}
  
	// Default compare function
	// So 10 < 2 (compares the string '10' to the string '2')
	function RowCompare(a, b) {
    var aCell = a.getElementsByTagName('td')[sortedOn];
    var bCell = b.getElementsByTagName('td')[sortedOn];    

    var aNodeValue = aCell.firstChild.nodeValue;
    var bNodeValue = bCell.firstChild.nodeValue;

		var aVal = aNodeValue.toLowerCase();
		var bVal = bNodeValue.toLowerCase();

    if (aVal == bVal && (sortedOn != secondarySort)) { // Perform secondary sort
      rememberSortedOn = sortedOn;
      sortedOn = secondarySort; // temporarily pretend you're sorting on column[secondarySort]
      returnVal = RowCompareLinkIds(a, b);
      sortedOn = rememberSortedOn;
      return returnVal;    

    } else return (aVal > bVal ? 1 : -1);
	}

	// Compare function for integers (removes commas & number signs, then parses an int)
	// So 1,000 > 200 (compares the int 1000 to the int 200)
	function RowCompareNumbers(a, b) {

    var aCell = a.getElementsByTagName('td')[sortedOn];
    var bCell = b.getElementsByTagName('td')[sortedOn];
    var aNodeValue = aCell.firstChild.nodeValue;
    var bNodeValue = bCell.firstChild.nodeValue;
    
		var aVal = parseInt(aNodeValue.replace(/,|\#/g,''));
		var bVal = parseInt(bNodeValue.replace(/,|\#/g,''));

    if (isNaN(aVal) || isNaN(bVal)){
  		return (aNodeValue == bNodeValue ? 0 : (aNodeValue > bNodeValue ? 1 : -1));
    } else if (aVal == bVal && (sortedOn != secondarySort)) { // Perform secondary sort
      rememberSortedOn = sortedOn;
      sortedOn = secondarySort; // temporarily pretend you're sorting on column[secondarySort]
      returnVal = RowCompareLinkIds(a, b);
      sortedOn = rememberSortedOn;
      return returnVal;
    } else return (aVal > bVal ? 1 : -1);
	}

	// Compare function for currency (removes dollar signs and commas)
	function RowCompareDollars(a, b) {
  
    var aCell = a.getElementsByTagName('td')[sortedOn];
    var bCell = b.getElementsByTagName('td')[sortedOn];    
    var aNodeValue = aCell.firstChild.nodeValue;
    var bNodeValue = bCell.firstChild.nodeValue;

		// Uses a regexp to strip commas and dollar signs, then parses out the (first) float
		var aVal = parseFloat(aNodeValue.replace(/,|\$/g,''));
		var bVal = parseFloat(bNodeValue.replace(/,|\$/g,''));

    if (isNaN(aVal) || isNaN(bVal)){
  		return (aNodeValue == bNodeValue ? 0 : (aNodeValue > bNodeValue ? 1 : -1));
    } else if (aVal == bVal && (sortedOn != secondarySort)) { // Perform secondary sort
      rememberSortedOn = sortedOn;
      sortedOn = secondarySort; // temporarily pretend you're sorting on column[secondarySort]
      returnVal = RowCompareLinkIds(a, b);
      sortedOn = rememberSortedOn;
      return returnVal;
    } else return (aVal > bVal ? 1 : -1);
	}
  
  function RowCompareLinkIds(a, b) {

    var aCell = a.getElementsByTagName('td')[sortedOn];
    var bCell = b.getElementsByTagName('td')[sortedOn];    

    var aInnerHTML = aCell.innerHTML;
    var bInnerHTML = bCell.innerHTML;
    
    return (aInnerHTML == bInnerHTML ? 0 : (aInnerHTML > bInnerHTML ? 1 : -1));
    
  }

  function RowCompareTBD(a, b) {
    // If TBD (or TBA) is contained in the string anywhere, that string should
    // be considered greater than any other value.

    var aCell = a.getElementsByTagName('td')[sortedOn];
    var bCell = b.getElementsByTagName('td')[sortedOn];    
    var aNodeValue = aCell.firstChild.nodeValue;
    var bNodeValue = bCell.firstChild.nodeValue;
    var aVal;
    var bVal;
    var rememberSortedOn;
    var returnVal;
    
    if (aNodeValue != null) { // Check for null
      aVal = aNodeValue.toLowerCase();
    } else {
      aVal = '';
    }
    
    if (bNodeValue != null) { // Check for null
      bVal = bNodeValue.toLowerCase();
    } else {
      bVal = '';
    }

    if (aVal.indexOf('tbd') != -1 || aVal.indexOf('tba') != -1) {
      if (bVal.indexOf('tbd') != -1 || bVal.indexOf('tba') != -1) {
        // if both contain 'tbd' then sort alphabetically on column[secondarySort]
        rememberSortedOn = sortedOn;
        sortedOn = secondarySort; // temporarily pretend you're sorting on column[secondarySort]
        returnVal = RowCompareLinkIds(a, b);
        sortedOn = rememberSortedOn;
        return returnVal;

      } else { // 'TBD' > anything
        return 1;
      }
    } else if (bVal.indexOf('tbd') != -1 || bVal.indexOf('tba') != -1) { // anything < 'TBD'
      return -1;
    } else { 
  		if (sortedOn == 3) {
        if (sortDirection == 'inc'){
    			return (RowCompareNumbers(a,b));
        } else {
    			return (RowCompareNumbers(b,a));        
        }
  		} else if (sortedOn == 2) {
        if (sortDirection == 'inc') {
    			return (RowCompareDollars(a,b));
        } else {
          return (RowCompareDollars(b,a));
        }
      }
    }
  }

  // You can create a comparison function based on your own sorting rules:
	// This one is the same as the default sort comparison
	//
	// function RowCompareExample(a, b) {
	// 	// determine your return value
	// 	// return a negative value if a < b, zero if a == b, or a positive value if a > b
	// }

	// Alternates the classes of the rows in the table identified by id=tableId
	// PARAMS:
	//	tableId - the id of the table to be sorted (NOTE: there should only be one table
	// 			 on the page with that id)
	// startAt - the row number to begin at (does NOT include header rows not found in <TBODY>
	// firstClassName  - the name of the class to be used for 'odd' rows
	// secondClassName - the name of the class to be used for 'even' rows
	//
	function alternateRowClasses (tableId, startAt, firstClassName, secondClassName) {
    var table = document.getElementById(tableId);
    var tbody = document.getElementById(tableId).getElementsByTagName('tbody')[0];
    var tbodyRows = document.getElementById(tableId).getElementsByTagName('tbody')[0].getElementsByTagName('tr');
    
		for (var i = startAt; i < tbodyRows.length; i++) {
    
			for (var j = 0; j < tbodyRows[i].getElementsByTagName('td').length; j++) {
      
				if (i%2 == 0) { // "odd" rows, starting at row[startAt] (so row[0] is considered odd)
					document.getElementById(tableId).getElementsByTagName('tbody')[0].getElementsByTagName('tr')[i].getElementsByTagName('td')[j].className = firstClassName;
          
				} else { // "even" rows, starting at row[startAt + 1] (so row[1] is considered even)
					document.getElementById(tableId).getElementsByTagName('tbody')[0].getElementsByTagName('tr')[i].getElementsByTagName('td')[j].className = secondClassName;
				}
			}
		}
	}
  
  // Highlights the column header by which the data is sorted
  function highlightColumnHeader(tableId, sortOn) {
    var headerRow = document.getElementById(tableId).getElementsByTagName('thead')[0].getElementsByTagName('tr')[0];
    for (var i = 0; i < 4; i++) {
      if (i == sortOn) {
        headerRow.getElementsByTagName('td')[i].style.backgroundColor = '#636563'; // Highlight sorted column header
      } else {
        headerRow.getElementsByTagName('td')[i].style.backgroundColor = '#9A9C9A'; // Unhighlight other column headers
      }
    }
  }

	function MM_findObj(n, d) { //v4.01
	  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
		d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
	  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
	  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
	  if(!x && d.getElementById) x=d.getElementById(n); return x;
	}

	function MM_swapImage() { //v3.0
	  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
	   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
	}

	// Hides all sort arrows (based on numColumns)
	function toggleSortArrowsOff() {
		for (var i = 0; i < numColumns; i++) {
			MM_swapImage('sortArrow' + i,'','/images/pixel.gif');
		}
	}
  
  // Displays the increasing sort arrow for column n
  function toggleSortArrowOn(n) {
    MM_swapImage('sortArrow' + n,'',imgArrowInc);
  }

	// Flips the sortArrow for column indicated by param:column. Also flips sortDirection.
	function flipSortArrow(column) {
		if (sortDirection == 'inc') { // if currently in increasing order
			MM_swapImage('sortArrow' + column, '',imgArrowDec);
			sortDirection = 'dec';
		} else { // if currently in decreasing order
			MM_swapImage('sortArrow' + column, '',imgArrowInc);
			sortDirection = 'inc';
		}
	}

