call_when_loaded(make_sortable);

function make_sortable(){
  var tables = document.getElementsByTagName('table');
  for(var i=0; i < tables.length; i++){
	if(tables[i].className.search(/\bsortable\b/) != -1){
	  create_thead(tables[i]);
	  add_sort_functions_to_thead(tables[i]);
	}
  }
}

function create_thead(table){
  //make sure there is a thead portion to the table, if not assume the top row is the head row
  if (table.getElementsByTagName('thead').length == 0) {
    var the = document.createElement('thead');
	the.appendChild(table.rows[0]);
	table.insertBefore(the,table.firstChild);
  }	
}

function add_sort_functions_to_thead(table){
  if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
  var headrow_cells = table.tHead.rows[0].cells;
  for (var i=0; i<headrow_cells.length; i++){
	if(headrow_cells[i].className != 'ignore_for_sort'){
      change_class_of_element(headrow_cells[i], 'sort_none');
      add_event_to_element(headrow_cells[i], 'click', function(e){sort_by(this);}, true);
    }
  }
}

function sort_by(cell){
  var table = cell.parentNode.parentNode.parentNode;
  if(cell.className == 'sort_up'){
	change_class_of_element(cell, 'sort_down');
	reverse_order(table);
  }else if(cell.className == 'sort_down'){
	change_class_of_element(cell, 'sort_up');
	reverse_order(table);
  }else{
	clear_previous_sort(table);
	change_class_of_element(cell, 'sort_up');
	var cell_index = find_sorted_cell_index(table);
	var type = get_data_type_of_column(table, cell_index);
	//if(type == 'date') bubble_sort(compare_date, table, cell_index);	
	//else if(type == 'number') bubble_sort(compare_number, table, cell_index);	
	//else bubble_sort(compare_string, table, cell_index);
	if(type == 'date') quick_sort(0, table.tBodies[0].rows.length, compare_date, table, cell_index);	
	else if(type == 'number') quick_sort(0, table.tBodies[0].rows.length, compare_number, table, cell_index);	
	else quick_sort(0, table.tBodies[0].rows.length, compare_string, table, cell_index);	
  }	
}

function clear_previous_sort(table){
  if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
  var headrow_cells = table.tHead.rows[0].cells;
  for (var i=0; i<headrow_cells.length; i++){
    change_class_of_element(headrow_cells[i], 'sort_none');
  }	
}

function reverse_order(table){
  var existing_order = new Array();
  var t_body = table.tBodies[0];
  for (var i=0; i< t_body.rows.length; i++) {
    existing_order[i] = t_body.rows[i];
  }
  for (var i=existing_order.length-1; i>=0; i--) {
    t_body.appendChild(existing_order[i]);
  }
  delete existing_order;
}


function quick_sort(begin, end, compare_function, table, cell_index){
  if(end-1>begin) {
	var pivot=begin+Math.floor(Math.random()*(end-begin));

	pivot=partition(begin, end, pivot, compare_function, table, cell_index);

	quick_sort(begin, pivot, compare_function, table, cell_index);
	quick_sort(pivot+1, end, compare_function, table, cell_index);
  }
}

function partition(begin, end, pivot, compare_function, table, cell_index){
  var t_body = table.tBodies[0];

  var piv = get_data_of_element(t_body.rows[pivot].cells[cell_index]);
  exchange(t_body, pivot, end-1);
  var store = begin;
  var ix;
  for(ix=begin; ix<end-1; ++ix) {
	if(compare_function(get_data_of_element(t_body.rows[ix].cells[cell_index]), piv)) {
	  exchange(t_body, store, ix);
	  ++store;
	}
  }
  exchange(t_body, end-1, store);

  return store;
}


function bubble_sort(compare_function, table, cell_index){
  var t_body = table.tBodies[0];

  for(var i=0; i < t_body.rows.length; i++){
    for(var j=0; j < t_body.rows.length - i - 1; j++){

      if(compare_function(get_data_of_element(t_body.rows[j].cells[cell_index]), get_data_of_element(t_body.rows[j + 1].cells[cell_index])) ){
        t_body.insertBefore(t_body.rows[j + 1], t_body.rows[j]);
  	  }
  	}
  }
}


function exchange(t_body, a, b){
  if(a == b+1) {
	t_body.insertBefore(t_body.rows[a], t_body.rows[b]);
  } else if(b == a+1) {
	t_body.insertBefore(t_body.rows[b], t_body.rows[a]);
  } else {
	var tmpNode = t_body.replaceChild(t_body.rows[a], t_body.rows[b]);
	if(typeof(t_body.rows[a]) != "undefined") {
		t_body.insertBefore(tmpNode, t_body.rows[a]);
	} else {
		t_body.appendChild(tmpNode);
	}
  }
}


function find_sorted_cell_index(table){
  var cell_index = 0;
  if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
  var headrow_cells = table.tHead.rows[0].cells;
  for(var i=0; i < headrow_cells.length; i++){ 
    if(headrow_cells[i].className == 'sort_up'){
      cell_index = i;
	}
  }
  return cell_index;	
}

function get_data_type_of_column(table, cell_index){
  var the_data = get_data_of_element(table.tBodies[0].rows[0].cells[cell_index]);
  the_type = 'string';
  if(the_data != ''){
    if(the_data.match(/^-?[£$¤]?[\d,.]+%?$/)){
      the_type = 'number';	
    }
  }

  return the_type;
}

function get_data_of_element(element){
  var the_data = '';
  if(element != null){
	the_data = element.innerHTML;
    if (element.getAttribute("value_override") != null) {
	  the_data = element.getAttribute("value_override");
    }
  }
  return the_data;	
}

function get_data_for_column(row, column_index){
  var the_data = '';
  if((row != null) && (row != undefined)){
    the_data = row.cells[column_index].innerHTML;
	if (row.cells[column_index].getAttribute("value_override") != null) {
      the_data = row.cells[column_index].getAttribute("value_override");
	}
  }
  return the_data;	
}

function compare_string(a, b){
  return a < b; 
}

function compare_number(a, b){
  var aa = parseFloat(a.replace(/[^0-9.-]/g,''));
  if (isNaN(aa)) aa = 0;
  var bb = parseFloat(b.replace(/[^0-9.-]/g,'')); 
  if (isNaN(bb)) bb = 0;
  
  return aa < bb;
}

function compare_date(a, b){
  var aa = Date.parse(a);
  var bb = Date.parse(b);

  return aa < bb;
}