/*
getObjDebugStr(obj)
externalLinks()
getBaseOfLocation()
clear_table(table, head, foot)
fill_table_from_array(table, array, descriptor)
foreach(array, func)
objHideByObj( oObj )
objHideById( id )
blockShowByObj( oObj )
blockShowById( id )
rowShowByObj( oRow )
rowShowById( id )
rowToggleByObj( oRow )
rowToggleById( id )
blockToggleByObj( oObj )
blockToggleById( id )
inlineShowByObj( oObj )
inlineShowById( id )
rowGetByIndex( oTable, index )
tableShowByObj( oTable )
tableShowById( id )
validateTextboxInt( oTextbox )
validateTextboxFloat( oTextbox )
floatToDecimalPlaces( f, n )
getXMLHttpRequestObject()
sendXMLHttpRequestWithFormData( xml_obj, state_change, stem_location, form_data )
quicksortTableByColumn( oTable, leftRow, rightRow, column )
paginated_table( name )
paginated_table_set_min_row( name, minRow )
paginated_table_set_page_num_display( name, id )
paginated_table_set_num_results_display( name, id )
paginated_table_set_filter( name, column, filter_value )
paginated_table_set_per_page( name, per_page )
paginated_table_goto_first( name )
paginated_table_goto_previous( name )
paginated_table_goto_next( name )
paginated_table_goto_final( name )
paginated_table_refresh( table )
*/

//add Array.indexOf to browsers missing it (IE)
if(!Array.indexOf){
  Array.prototype.indexOf = function(obj, start){
    start = start || 0;
    for (var i=start; i<this.length; ++i)
      if (this[i]===obj)
        return i;
    return -1;
  }
}

function getObjDebugStr(obj){
  var str = "{";
  for (var x in obj) {
    str = str + x + ": " + obj[x] + ", ";
  }
  str = str + "}";
  return str;
}

function externalLinks(){
  var anchors = document.getElementsByTagName("a");
  for( var i = 0; i < anchors.length; i++ ){
    if( anchors[i].href && anchors[i].rel == "external" ){
      anchors[i].target = "_blank";
    }
  }
}

function getBaseOfLocation()
{
  var l = window.location.href;
  return l.slice(0, l.lastIndexOf('/'));
}

function clear_table(table, head, foot){
  if(head)
    table.deleteTHead();
  if(foot)
    table.deleteTFoot();
  while(table.rows.length)
    table.deleteRow(0);
}

function fill_table_from_array(table, array, descriptor){
  /*
  descriptor {
    columns: [{
      name: string,
      key: object,
      post_cell: function(cell, element),
      post_header: function(cell)
    }],
    post_row: function(row, element)
  }
  */
  
  if (!descriptor){
    var cols = [];
    
    if(array.length){
      var obj = array[0];
      for(var j in obj)
        cols.push({name:j,key:j});
    }
    else{ //struct
      for(var i in array){
        var obj = array[i];
        for(var j in obj)
          cols.push({name:j,key:j});
        break;
      }
    }
    
    descriptor = {
      columns: cols
    }
  }
  
  {
    var thead = table.createTHead();
    var row = thead.insertRow(0);
    var cell_index = 0;
    for (var j = 0; j < descriptor.columns.length; ++j){
      var column = descriptor.columns[j];
      if (!column) continue; //IE
      var cell = row.insertCell(cell_index);
      cell_index++;
      cell.innerHTML = column.name;
      if (column.post_header)
        column.post_header(cell);
    }
  }
  
  for (var i in array){
    //rough fix to avoid functions prototyped onto Array for IE
    if("function" === typeof(array[i]))
      continue;
    
    var element = array[i];
    var row = table.insertRow(table.rows.length);
    var cell_index = 0;
    
    for (var j = 0; j < descriptor.columns.length; ++j){
      var column = descriptor.columns[j];
      if (!column) continue; //IE
      var cell = row.insertCell(cell_index);
      cell_index++;
      
      if (column.key)
        cell.innerHTML = element[column.key];
      
      if (column.post_cell)
        column.post_cell(cell, element);
    }
    
    if (descriptor.post_row)
      descriptor.post_row(row, element);
  }
}

//foreach for arrays or structures. call is func(element, index, array)
function foreach(array, func){
  for(var i in array){
    //rough fix to avoid functions prototyped onto Array for IE
    if("function" === typeof(array[i]))
      continue;
    
    func(array[i], i, array);
  }
}

function objHideByObj(oObj){
  if( oObj.style.display != "none" ){
    oObj.style.display = "none";
  }
}

function objHideById(id){
  return objHideByObj(document.getElementById(id));
}

function blockShowByObj(oObj){
  oObj.style.display = "block";
}

function blockShowById(id){
  return blockShowByObj(document.getElementById(id));
}

function inlineShowByObj(oObj){
  oObj.style.display = "inline";
}

function inlineShowById(id){
  return inlineShowByObj(document.getElementById(id));
}

function rowShowByObj(oRow){
  if( oRow.style.display == "none" ){
    try{
      oRow.style.display = "table-row";
    }
    catch(e){
      oRow.style.display = "block";
    }
  }
}

function rowShowById(id){
  return rowShowByObj(document.getElementById(id));
}

function blockToggleByObj(oObj){
  if( oObj.style.display == "none" ){
    blockShowByObj(oObj);
  }
  else{
    objHideByObj(oObj);
  }
}

function blockToggleById(id){
  return blockToggleByObj(document.getElementById(id));
}

function rowToggleByObj(oRow){
  if( oRow.style.display == "none" ){
    rowShowByObj(oRow);
  }
  else{
    objHideByObj(oRow);
  }
}

function rowToggleById(id){
  return rowToggleByObj(document.getElementById(id));
}

function rowGetByIndex(oTable, index){
  try{
    var oRow = oTable.rows[index];
    return oRow;
  }
  catch(e){
    try{
      var oRow = document.getElementById(oTable).rows[index];
      return oRow;
    }
    catch(ee){
      return 0;
    }
  }
}

function rowGetIndex(oTable, oRow){
  for(var i=0; i<oTable.rows.length; ++i)
    if(oRow===oTable.rows[i])
      return i;
  return -1;
}

function tableShowByObj(oTable){
  if( oTable.style.display == "none" ){
    try{
      oTable.style.display = "table";
    }
    catch(e)
    {
      oTable.style.display = "block";
    }
  }
}

function tableShowById(id){
  return tableShowByObj(document.getElementById(id));
}

function validateTextboxInt( oTextbox ){
  var value = parseInt(oTextbox.value);
  if( isNaN(value) ){
    value = 0;
  }
  
  oTextbox.value = value;
  return value;
}

function validateTextboxFloat( oTextbox ){
  var value = parseFloat(oTextbox.value);
  if( isNaN(value) ){
    value = 0;
  }
  
  oTextbox.value = value.toFixed(2);
  return floatToDecimalPlaces(value, 2);
}

function floatToDecimalPlaces( f, n ){
  var m = Math.pow(10, n);
  return Math.round(f * m) / m;
}

function getXMLHttpRequestObject(){
  var XMLHttpRequestObj;
  
  try{
    XMLHttpRequestObj = new XMLHttpRequest();
  }
  catch(e){
    try{
      XMLHttpRequestObj = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch(e){
      try{
        XMLHttpRequestObj = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch(e){
        XMLHttpRequestObj = null;
      }
    }
  }
  
  return XMLHttpRequestObj;
}

function sendXMLHttpRequest( xml_obj, state_change, stem_location ){
  if( null != xml_obj ){
    if( 0 != xml_obj.readyState && 4 != xml_obj.readyState ){
      xml_obj.abort();
    }
  }
  
  xml_obj = getXMLHttpRequestObject();
  if( null == xml_obj ){
    return null;
  }
  
  xml_obj.onreadystatechange = state_change;
  xml_obj.open("GET", getBaseOfLocation() + stem_location, true);
  xml_obj.send(null);
  
  return xml_obj;
}

function sendXMLHttpRequestWithFormData( xml_obj, state_change, stem_location, form_data ){
  if( null != xml_obj ){
    if( 0 != xml_obj.readyState && 4 != xml_obj.readyState ){
      xml_obj.abort();
    }
  }
  
  xml_obj = getXMLHttpRequestObject();
  if( null == xml_obj ){
    return null;
  }
  
  xml_obj.onreadystatechange = state_change;
  xml_obj.open("POST", getBaseOfLocation() + stem_location, true);
  xml_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xml_obj.send(form_data);
  
  return xml_obj;
}

/*
quicksort functions
*/
function stripHTML( str )
{
  var start = str.indexOf("<",0);
  if( -1 == start ){
    return str;
  }
  
  var depth = 1, position = start;
  
  while( 0 < depth ){
    position++;
    if( position >= str.length ){
      return str;
    }
  
    if( "<" == str.charAt(position) ){
      depth++;
    }
    else if( ">" == str.charAt(position) ){
      depth--;
    }
  }
  
  return stripHTML(str.replace(str.substring(start,position + 1),""));
}

function orderAlphabetical( strA, strB )
{
  strA = stripHTML(strA).toLowerCase();
  strB = stripHTML(strB).toLowerCase();
  var i = 0;
  
  while( i < strA.length && i < strB.length ){
    if( strA.charCodeAt(i) != strB.charCodeAt(i) ){
      return strB.charCodeAt(i) - strA.charCodeAt(i); //>0 if b > a, <0 if a < b
    }
    
    i++;
  }
  
  return strB.length - strA.length;
}

function orderInteger( a, b )
{
  return b - a; //0 if equal, >0 if b > a, <0 if a < b
}

function valueLessThanOrEqual( valA, valB )
{
  var aInt = parseInt(valA);
  var bInt = parseInt(valB);
  if( (aInt || valA == "0") && (bInt || valB == "0") ){
    return orderInteger(aInt, bInt) > 0;
  }
  
  return orderAlphabetical(valA, valB) > 0;
}

function tableSwapRows( oTable, rowAIndex, rowBIndex )
{
  var rowA = oTable.rows[rowAIndex];
  var rowB = oTable.rows[rowBIndex];
  var temp;
  
  /*
  temp = rowA.align;
  rowA.align = rowB.align;
  rowB.align = temp;
  
  temp = rowA.id;
  rowA.id = rowB.id;
  rowB.id = temp;
  
  temp = rowA.vAlign;
  rowA.vAlign = rowB.vAlign;
  rowB.vAlign = temp;
  
  temp = rowA.className;
  rowA.className = rowB.className;
  rowB.className = temp;
  */
  
  for( var i = 0; i < rowA.cells.length; i++ ){
    temp = rowA.cells[i].innerHTML;
    rowA.cells[i].innerHTML = rowB.cells[i].innerHTML;
    rowB.cells[i].innerHTML = temp;
  }
}

function partitionTableByColumn( oTable, leftRow, rightRow, pivotIndex, column )
{
  var pivotValue = oTable.rows[pivotIndex].cells[column].innerHTML;
  tableSwapRows( oTable, pivotIndex, rightRow );
  var storeIndex = leftRow;
  
  for( var i = leftRow; i < rightRow; i++ ){
    if( valueLessThanOrEqual(oTable.rows[i].cells[column].innerHTML, pivotValue) ){
      tableSwapRows( oTable, storeIndex, i );
      storeIndex++;
    }
  }
  
  tableSwapRows( oTable, rightRow, storeIndex );
  return storeIndex;
}

//quicksortTableByColumn( document.getElementById('testTable'), 1, document.getElementById('testTable').rows.length - 1, 0 );
function quicksortTableByColumn( oTable, leftRow, rightRow, column )
{
  if( rightRow > leftRow ){
    var pivotNewIndex = partitionTableByColumn( oTable, leftRow, rightRow, leftRow, column );
    quicksortTableByColumn( oTable, leftRow, pivotNewIndex - 1, column );
    quicksortTableByColumn( oTable, pivotNewIndex + 1, rightRow, column );
  }
}

//local table pagination
var paginated_tables = new Array();

function paginated_table( name )
{
  for( var i = 0; i < paginated_tables.length; i++ ){
    if( paginated_tables[i].name == name ){
      return paginated_tables[i];
    }
  }
  
  var table = new Object();
  table.name = name;
  table.obj = document.getElementById(name);
  table.min_row = 0;
  table.max_row = table.obj.rows.length - 1;
  table.per_page = 25;
  table.page = 0;
  table.final_page = Math.floor((table.max_row - table.min_row) / table.per_page);
  table.page_num_display = null;
  table.num_results_display = null;
  table.filters = new Array(table.obj.rows[0].cells.length);
  for( var i = 0; i < table.filters.length; i++ ){
    table.filters[i] = "";
  }
  table.filter_refresh = 0;
  
  paginated_tables.push(table);
  return table;
}

function paginated_table_set_min_row( name, minRow )
{
  var table = paginated_table(name);
  table.min_row = minRow;
  paginated_table_refresh(table);
}

function paginated_table_set_page_num_display( name, id )
{
  var table = paginated_table(name);
  table.page_num_display = document.getElementById(id);
  paginated_table_refresh(table);
}

function paginated_table_set_num_results_display( name, id )
{
  var table = paginated_table(name);
  table.num_results_display = document.getElementById(id);
  paginated_table_refresh(table);
}

function paginated_table_set_filter( name, column, filter_value )
{
  var table = paginated_table(name);
  clearTimeout(table.filter_refresh);
  table.filters[column] = filter_value.toLowerCase();
  table.filter_refresh = setTimeout("paginated_table_refresh(paginated_table('" + name + "'))",500);
}

function paginated_table_set_per_page( name, per_page )
{
  //blur the select box first
  var sels = document.getElementsByTagName("select");
  for( var i = 0; i < sels.length; i++ ){
    sels[i].blur();
  }

  var table = paginated_table(name);
  table.per_page = per_page;
  paginated_table_refresh(table);
}

function paginated_table_goto_first( name )
{
  var table = paginated_table(name);
  if( table.page != 0 ){
    table.page = 0;
    paginated_table_refresh(table);
  }
}

function paginated_table_goto_previous( name )
{
  var table = paginated_table(name);
  if( table.page > 0 ){
    table.page = table.page - 1;
    paginated_table_refresh(table);
  }
}

function paginated_table_goto_next( name )
{
  var table = paginated_table(name);
  if( table.page < table.final_page ){
    table.page = table.page + 1;
    paginated_table_refresh(table);
  }
}

function paginated_table_goto_final( name )
{
  var table = paginated_table(name);
  if( table.page != table.final_page ){
    table.page = table.final_page;
    paginated_table_refresh(table);
  }
}

function paginated_table_refresh( table )
{
  var displayed = 0;
  var disp;

  for( var i = table.min_row; i <= table.max_row; i++ ){
    disp = 1;
  
    for( var j = 0; j < table.filters.length; j++ ){
      if( table.filters[j] != "" ){
        if( stripHTML(table.obj.rows[i].cells[j].innerHTML).toLowerCase().indexOf(table.filters[j]) == -1 ){
          disp = 0;
          break;
        }
      }
    }
    
    if( disp == 1 ){
      displayed = displayed + 1;
      
      if( displayed % 2 == 0 ){
        table.obj.rows[i].className = "sidebar_tr1"
      }
      else{
        table.obj.rows[i].className = "sidebar_tr0"
      }
    
      if( table.page * table.per_page >= displayed || displayed > (table.page + 1) * table.per_page ){
        disp = 0;
      }
    }
    
    if( disp == 1 ){
      try{
        table.obj.rows[i].style.display = "table-row";
      }
      catch(e){
        table.obj.rows[i].style.display = "block";
      }
    }
    else{
      table.obj.rows[i].style.display = "none";
    }
  }
  
  table.final_page = Math.ceil(displayed / table.per_page) - 1;
  if( table.final_page < table.page ){
    table.page = table.final_page;
    return paginated_table_refresh(table);
  }
  else if( -1 == table.page && 0 <= table.final_page ){
    table.page = 0;
    return paginated_table_refresh(table);
  }
  
  if( table.page_num_display != null ){
    table.page_num_display.innerHTML = (table.page + 1) + " of " + (table.final_page + 1);
  }
  
  if( table.num_results_display != null ){
    table.num_results_display.innerHTML = displayed;
  }
}

//local tabbed frames
var tabbed_frames = new Array();

function tabbed_frame( name )
{
  for( var i = 0; i < tabbed_frames.length; i++ ){
    if( tabbed_frames[i].name == name ){
      return tabbed_frames[i];
    }
  }
  
  var frame = new Object();
  frame.name = name;
  frame.selected_tab_button = null;
  frame.selected_tab_frame = null;
  
  tabbed_frames.push(frame);
  return frame;
}

function tabbed_frame_click_button( name, button, display_frame_name )
{
  var frame = tabbed_frame(name);
  var display_frame = document.getElementById(display_frame_name);
  if( null == display_frame ){
    return;
  }

  if( null != frame.selected_tab_button ){
    frame.selected_tab_button.className = "unselected";
  }
  
  if( null != frame.selected_tab_frame ){
    objHideByObj(frame.selected_tab_frame);
  }
  
  button.className = "selected";
  tableShowByObj(display_frame);
  
  frame.selected_tab_button = button;
  frame.selected_tab_frame = display_frame;
}
