// JavaScript Document
/* This script is property of Tanner Naeher, coyote6.com.  It may only be used as a template for others.  Any use of its images or content is strictly forbidden without written consent.*/
/* Based on table sorting script by Joost de Valk, at http://www.joostdevalk.nl/code/sortable-table/. */
/* The purpose of this script is to sort colomns inside of a table. */

/*************************************************************************************************************
These values can be changed.
*************************************************************************************************************/

var european_date = false;
var alternate_row_colors = true;
// Set the default arrow side to left or right, give the sortable table a class of left or right to switch between options on the same page.
var arrow_side = "left";
var image_path = "../Images/Common/";
var image_up = "up_arrow.jpg";
var image_down = "down_arrow.jpg";
var image_none = "no_arrow.jpg";


/*************************************************************************************************************
DO NOT MAKE CHANGES BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING!!!!!!
*************************************************************************************************************/

// Set some global variables.
var column_index;
var headers = false;

// Add this function to the onload list
add_event (window, "load", get_sortable_tables);

// Adds and removes events for the onload.  (Cross-browser event handling for IE5+, NS6 and Mozilla - by Scott Andrew)
function add_event (element, event_type, function_name, useCapture) {
	// If the browser has the 'addEventListener' function use it.
	if (element.addEventListener) {
		element.addEventListener(event_type, function_name, useCapture);
		return true;
	}
	// Else if the browser has the 'attachEvent' function use it.
	else if (element.attachEvent){
		var new_event = element.attachEvent("on"+event_type, function_name);
		return new_event;
	}
	else {
		alert("Handler could not be removed");
	}
}

// Finds all tables with 'sortable' in the class and makes them sortable (through the 'make_table_sortable' function).
function get_sortable_tables() {
	// If document cannot get elements by tag name stop the function.
	if (!document.getElementsByTagName) {
	 return;
	}
	// Get all the tables.
	var tables = document.getElementsByTagName("table");
	// Check each table for the 'sortable' tag name and if it matches and has an id, add it to the 'make_table_sortable' function.
	for (ti=0;ti<tables.length;ti++) {
		var this_table = tables[ti];
		if (((' '+this_table.className+' ').indexOf("sortable") != -1) && (this_table.id)) {
			if ((' '+this_table.className+' ').indexOf("right") != -1) {
				this_table_arrow_side = "right";
			}
			else if ((' '+this_table.className+' ').indexOf("left") != -1) {
				this_table_arrow_side = "left";
			}
			else {
				this_table_arrow_side = arrow_side;
			}
			make_table_sortable(this_table, this_table_arrow_side);
		}
	}
}

// Makes the tables sortable.
function make_table_sortable(t, this_table_arrow_side) {
	// Make sure the table has rows in it.
	if (t.rows && t.rows.length > 0) {
		// Check to see if the table has a header and if so set it to the variable 'first_row'
		if (t.tHead && t.tHead.rows.length > 0) {
			var first_row = t.tHead.rows[t.tHead.rows.length-1];
			// If the header does exist set the global variable to true.
			headers = true;
		}
		// If no header is present then make the first row the header.
		else {
			var first_row = t.rows[0];
		}
	}
	// End the function if no first_row was set.
	if (!first_row) return;
	// Make the header and its contents clickable links.
	for (var i=0;i<first_row.cells.length;i++) {
		// Set a cell variable with the cells info and a text variable with the text from the cell.
		var cell = first_row.cells[i];
		var txt = get_innerText(cell);
		// Make sure the cell does not have an unsortable class name.
		if (cell.className != "unsortable" && cell.className.indexOf("unsortable") == -1) {
			// Write the arrow on the correct side of the text.
			if (this_table_arrow_side == 'left') {
				// Add the link, image, and a span to the header.
				cell.innerHTML = '<a class="sort_header" onclick="resort_table(this, '+i+');return false;"><span class="sort_arrow"><img src="'+ image_path + image_none + '" alt="No Arrow"/></span>'+txt+'</a>';
			}
			else {
				// Add the link, image, and a span to the header.
				cell.innerHTML = '<a class="sort_header" onclick="resort_table(this, '+i+');return false;">'+txt+'<span class="sort_arrow"><img src="'+ image_path + image_none + '" alt="No Arrow"/></span></a>';
			}
		}
	}
	// If the alternate rows is turned on call the alternate function.
	if (alternate_row_colors) {
		alternate(t);
	}
}

// Gets the inner text from an element.
function get_innerText(element) {
	if (typeof element == "string") {
		return element;
	}
	if (typeof element == "undefined") {
		return element;
	}
	// This statement is not needed but makes it faster.
	if (element.innerText) {
		return element.innerText;
	}
	// Create a blank variable to place the new string.
	var str = "";
	var cs = element.childNodes;
	var l = cs.length;
	// Cycle through all the child nodes of the element.
	for (var i = 0; i < l; i++) {
		// Recreate the element into a string depending on what type the node is.
		switch (cs[i].nodeType) {
			// Loop through this function again if this is an element node
			case 1:
				str += get_innerText(cs[i]);
				break;
			// Add the value to the string if it is a text node
			case 3:	
				str += cs[i].nodeValue;
				break;
		}
	}
	// Once finished return the string.
	return str;
}

// Resorts the table when the header is clicked.
function resort_table(link, link_id) {
	// Create a blank variable 'span'.
	var span;
	// Loop for all of the child nodes of the link.
	for (var ci=0; ci<link.childNodes.length; ci++) {
		// Get the span element and set it to the variable if it exists.
		if (link.childNodes[ci].tagName && link.childNodes[ci].tagName.toLowerCase() == 'span') {
			span = link.childNodes[ci];
		}
	}
	// Get the inner text from the variable.
	var span_text = get_innerText(span);
	// Get the table data element.
	var td = link.parentNode;
	// Set a column variable with either the link id or the cell index.
	var column = link_id || td.cellIndex;
	// Get the table.
	var t = get_parent(td,'TABLE');
	// Stop the function if the table has 1 or less rows.
	if (t.rows.length <= 1) {
		return;
	}
	// Get blank variables.
	var item = "";
	var i = 0;
	// Loop while the item string is blank and the counter is less than the number of rows in the table body.
	while (item == "" && i < t.tBodies[0].rows.length) {
		// For every element get the inner text.
		var item = get_innerText(t.tBodies[0].rows[i].cells[column]);
		// Trim the white spaces of the item.
		item = trim(item);
		// Make sure the item is not an html comment and has been set.
		if (item.substr(0,4) == "<!--" || item.length == 0) {
			// If it is a comment or has been set set the item to nothing.
			item = "";
		}
		// Add on to the counter.
		i++;
	}
	// If the item is blank stop the function.
	if (item == "") {
		return;
	} 
	// Make the text insensitive for sorting.
	sort_method = case_insensitive_sort;
	// If the text pattern matches a certain patttern send it to the right sorting function.
	if (item.match(/^\d\d[\/\.-][a-zA-z][a-zA-Z][a-zA-Z][\/\.-]\d\d\d\d$/)) {
		sort_method = sort_date;
	}
	if (item.match(/^\d\d[\/\.-]\d\d[\/\.-]\d\d\d{2}?$/)) {
		sort_method = sort_date;
	}
	if (item.match(/^-?[£$?Û¢´]\d/)) {
		sort_method = sort_numeric;
	}
	if (item.match(/^-?(\d+[,\.]?)+(E[-+][\d]+)?%?$/)) {
		sort_method = sort_numeric;
	}
	// Set the global variable 'column_index' to this columns index.
	column_index = column;
	// Start new arrays to place the rows in.
	var first_row = new Array();
	var new_rows = new Array();
	// Loop for every table body in the table.
	for (k=0;k<t.tBodies.length;k++) {
		// Loop for every row in each of the table bodies.
		for (i=0;i<t.tBodies[k].rows[0].length;i++) { 
			// Set the first row to the table bodys first row.
			first_row[i] = t.tBodies[k].rows[0][i]; 
		}
	}
	// Loop for every table body in the table.
	for (k=0;k<t.tBodies.length;k++) {
		// If no headers are present.
		if (!headers) {
			// Skip the first row.
			for (j=1;j<t.tBodies[k].rows.length;j++) { 
				new_rows[j-1] = t.tBodies[k].rows[j];
			}
		}
		else {
			// Do not skip the first row.
			for (j=0;j<t.tBodies[k].rows.length;j++) { 
				new_rows[j] = t.tBodies[k].rows[j];
			}
		}
	}
	// Sort the new rows by the appropriate sorting method.
	new_rows.sort(sort_method);
	// If the 'sort_dir' attribute is set to down then switch the arrow image and reset the direction attribute.
	if (span.getAttribute("sort_dir") == 'down') {
			arrow = '<img src="'+ image_path + image_down + '" alt="Down Arrow;"/>';
			new_rows.reverse();
			span.setAttribute('sort_dir','up');
	}
	// If the 'sort_dir' attribute is not set to down then switch the arrow image and reset the direction attribute.
	else {
			arrow = '<img src="'+ image_path + image_up + '" alt="Up Arrow"/>';
			span.setAttribute('sort_dir','down');
	} 
	// Append child rows that already exist to the tbody, so it moves them rather than creating new ones.
  for (i=0; i<new_rows.length; i++) { 
		// Don't do 'footer' rows.
		if (!new_rows[i].className || (new_rows[i].className && (new_rows[i].className.indexOf('footer') == -1))) {
			t.tBodies[0].appendChild(new_rows[i]);
		}
	}
  // Do 'footer' rows only.
  for (i=0; i<new_rows.length; i++) {
		if (new_rows[i].className && (new_rows[i].className.indexOf('footer') != -1)) 
			t.tBodies[0].appendChild(new_rows[i]);
	}
	// Delete any other arrows that may be showing from the header row.
	var all_spans = document.getElementsByTagName("span");
	for (var ci=0; ci<all_spans.length; ci++) {
		if (all_spans[ci].className == 'sort_arrow') {
			// Make sure that it is in the same table as the one being sorted.
			if (get_parent(all_spans[ci],"table") == get_parent(link,"table")) {
				all_spans[ci].innerHTML = '<img src="'+ image_path + image_none + '" alt="No Arrow"/>';
			}
		}
	}		
	// Add the new arrow direction.
	span.innerHTML = arrow;
	// Call the alternate rows function.
	alternate(t);
}

// Get the parent element of the current one by tag name.
function get_parent (current_element, parent_tag_name) {
	// If there is no current element return it null.
	if (current_element == null) {
		return null;
	}
	// If the current element has an element node type and its tag name is the same as the lowercase verson of the parent_tag_name return the element.
	else if (current_element.nodeType == 1 && current_element.tagName.toLowerCase() == parent_tag_name.toLowerCase()) {
		return current_element;
	}
	// Loop the parent of the current element back into this function until the one being searched for is found.
	else {
		return get_parent (current_element.parentNode, parent_tag_name);
	}
}

// Arrange the date string
function arrange_date_string (date) {	
	// Two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX due to y2k.
	dt = "00000000";
	// If the length of the date string is 11 (Meaning it is the date expressed as 10 Mar 2008).
	if (date.length == 11) {
		// Get the 4-6 letters and change them to lowercase.
		month_string = date.substr(3,3);
		month_string = month_string.toLowerCase();
		// Check the month string against each case.
		switch(month_string) {
			// The default is mt = "00";
			case "jan": var mt = "01"; break;
			case "feb": var mt = "02"; break;
			case "mar": var mt = "03"; break;
			case "apr": var mt = "04"; break;
			case "may": var mt = "05"; break;
			case "jun": var mt = "06"; break;
			case "jul": var mt = "07"; break;
			case "aug": var mt = "08"; break;
			case "sep": var mt = "09"; break;
			case "oct": var mt = "10"; break;
			case "nov": var mt = "11"; break;
			case "dec": var mt = "12"; break;
		}
		// Add the 8-11 letters(year) to the months and to the 1-2 letters (day) of the date string.
		dt = date.substr(7,4)+mt+date.substr(0,2);
		return dt;
	}
	// If the length of the date string is 10 (Meaning it is the date expressed as 03/10/2008).
	else if (date.length == 10) {
		// If the European date is not turned on.
		if (european_date == false) {
			// Add the 7-10 letters (year) to the 1-2 letters (month) to the 4-5 letters (day) of the date string.
			dt = date.substr(6,4)+date.substr(0,2)+date.substr(3,2);
			return dt;
		}
		// If the European date is turned on.
		else {
			// Add the 7-10 letters (year) to the 4-5 letters (month) to the 1-2 letters (day) of the date string.
			dt = date.substr(6,4)+date.substr(3,2)+date.substr(0,2);
			return dt;
		}
	}
	// If the length of the date string is 8 (Meaning it is the date expressed as 03/10/08).
	else if (date.length == 8) {
		// Get the 7-8 letters (year) from the date str.
		yr = date.substr(6,2);
		// If the year is less than 50 make it '20XX'.
		if (parseInt(yr) < 50) { 
			yr = '20'+yr; 
		}
		// If not make the year '19XX'.
		else { 
			yr = '19'+yr; 
		}
		// If the European date is turned on.
		if (european_date == true) {
			// Add the year to the 4-5 letters (month) to the 1-2 letters (day) of the date string.
			dt = yr+date.substr(3,2)+date.substr(0,2);
			return dt;
		}
		// If the European date is not turned on.
		else {
			// Add the year to the 1-2 letters (month) to the 4-5 letters (day) of the date string.
			dt = yr+date.substr(0,2)+date.substr(3,2);
			return dt;
		}
	}
	return dt;
}

// Sort the dates.
function sort_date(a,b) {
	// Get the text value for a.
	dt1 = arrange_date_string(get_innerText(a.cells[column_index]));
	// Get the text value for b.
	dt2 = arrange_date_string(get_innerText(b.cells[column_index]));
	// If the values are equal return them the same.	
	if (dt1==dt2) {
		return 0;
	}
	// If the first is smaller then return -1.
	if (dt1<dt2) { 
		return -1;
	}
	// Else return it as 1.
	return 1;
}

// Sort the numbers.
function sort_numeric (a,b) {
	// Get the text value for a.
	var aa = get_innerText(a.cells[column_index]);
	aa = clean_num (aa);
	// Get the text value for b.
	var bb = get_innerText(b.cells[column_index]);
	bb = clean_num (bb);
	// Return the results from the 'compare_numeric' function for the new values.
	return compare_numeric (aa,bb);
}

// Compare the numbers against each other.
function compare_numeric (a,b) {
	var a = parseFloat(a);
	a = (isNaN(a) ? 0 : a);
	var b = parseFloat(b);
	b = (isNaN(b) ? 0 : b);
	return a - b;
}

// Return whether the case of the text makes a difference.
function case_insensitive_sort(a,b) {
	// Get the text value for a.
	aa = get_innerText(a.cells[column_index]).toLowerCase();
	// Get the text value for b.
	bb = get_innerText(b.cells[column_index]).toLowerCase();
	// If the values are equal return them the same.
	if (aa==bb) {
		return 0;
	}
	// If the first is smaller then return -1.
	if (aa<bb) {
		return -1;
	}
	// Else return it as 1.
	return 1;
}

function sort_default (a,b) {
	// Get the text value for a.
	aa = get_innerText(a.cells[column_index]);
	// Get the text value for b.
	bb = get_innerText(b.cells[column_index]);
	// If the values are equal return them the same.
	if (aa==bb) {
		return 0;
	}
	// If the first is smaller then return -1.
	if (aa<bb) {
		return -1;
	}
	// Else return it as 1.
	return 1;
}

// Cleans the number of ????
function clean_num(str) {
	str = str.replace(new RegExp(/[^-?0-9.]/g),"");
	return str;
}

// Removes all unwanted white space and other characters.
function trim(s) {
	return s.replace(/^\s+|\s+$/g, "");
}

// Alternates the colors once the value is returned.
function alternate(table) {
	// Take object table and get all it's tbodies.
	var table_bodies = table.getElementsByTagName("tbody");
	// Loop through these tbodies
	for (var i = 0; i < table_bodies.length; i++) {
		// Take the tbody, and get all it's rows
		var table_rows = table_bodies[i].getElementsByTagName("tr");
		// Loop through these rows, but start at 1 because we want to leave the heading row untouched.
		for (var j = 0; j < table_rows.length; j++) {
			// Check if it is even, and apply classes for both possible results.
			if ((j % 2) == 0) {
				// If the class has an odd row class replace it with even.
				if ( !(table_rows[j].className.indexOf('odd') == -1) ) {
					table_rows[j].className = table_rows[j].className.replace('odd', 'even');
				}
				// If the class has an even row class keep it
				else {
					if ( table_rows[j].className.indexOf('even') == -1 ) {
						table_rows[j].className += " even";
					}
				}
			}
			// If it is an odd row.
			else {
				// If class name equals an even row replace it with odd.
				if (!(table_rows[j].className.indexOf('even') == -1)) {
					table_rows[j].className = table_rows[j].className.replace('even', 'odd');
				}
				// If the class has an odd row keep it.
				else {
					if (table_rows[j].className.indexOf('odd') == -1 ) {
						table_rows[j].className += " odd";
					}
				}
			} 
		}
	}
}