// Utils functions
function sbm__dp(number, decimals) {
  var rs;
  var loc;
  var y;
  rs=new String(number);
  loc=rs.indexOf(".");
  if (loc<0) {
    rs=rs+".";
    loc=(rs.length-1);
  }
  for (y=0; y<decimals; y++) {
    rs=rs+"0";
  }
  rs=rs.substring(0,(loc+1+decimals));
  return rs;
}

function sbm__numeric(num) {
  var s = num.toString();
  var bracket = s.indexOf("(");
  var minus = s.indexOf("-");
  var filteredValues = "-1234567890.";     // Characters kept
  var i;
  var intString = "";
  for (i = 0; i < s.length; i++) {
    var c = s.charAt(i);
    if (filteredValues.indexOf(c) != -1) {
      intString += c;
    }
  }

  if (minus<0) {
    if (bracket<0) {
      return intString;
    } else {
      return "-".concat(intString);
    }
  }
  return intString;
}

function sbm__sortNumeric(x,y) {
  return x-y;
}

// An object to represent a row of data in a table. We use an array to allow
// for any size.
function sbm__tableRow(columnArray){
  this.columnArray = columnArray;
            
  //default sort setting
  this.sortby = columnArray[0];
  this.sorttype = "text";

  /*
  this setsortby method sets the value of the sort by property of this object (in our case this row)
  there are some things to be aware of: note case matters when sorting so set all
  strings to lower case. Also there are special rules with the array.sort() method which
  will actually do the sorting work. For example numerical sorting will take an extra step.
  See the JavaScript documentation for more on sorting caveats.
  */

  this.setsortby = function (colNo){
    if (this.sorttype == "int" ||
        this.sorttype == "currency" ||
        this.sorttype == "double" ||
        this.sorttype == "float" ||
        this.sorttype == "comma") {
      // We need to convert to a numeric, removing any formatting
      this.sortby = sbm__numeric(this.columnArray[colNo]);
    } else if (this.sorttype == "date" ||
               this.sorttype == "datetime") {
      // We need to convert the date to padded unix time before sorting
      this.sortby = sbm__numeric(Date.parse(this.columnArray[colNo]));
    } else if (this.sorttype == "checkbox") {
      // Checkboxes need to be sorted on value. Tricky to extract but not impossible.
      this.sortby = this.columnArray[colNo-1].indexOf('CHECKED');
      if (this.sortby == -1) {
        this.sortby = 1;
      } else {
        this.sortby = 0;
      }
    } else {
      // Text and other behaviour
      this.sortby = this.columnArray[colNo];
    }
  };

  this.fixsortby = function (colNo){
    this.sortby = this.columnArray[colNo];
  };

  // We need a function to allow the sort type to be set as this affects how we present our sortby field
  this.setsorttype = function (sortType){ this.sorttype = sortType; };

  /*
  this toString method overrides the default to string method and instead returns the value
  stored in the sortby property
  */
  this.toString = function (){return String(this.sortby).toUpperCase()};
}

/*
I need to store an object defines which column and which direction 
is currently being sorted  
*/
var sbm__activeSort = null;

/*
this is an object that stores the column name that is currently being sorted on
and which direction
*/
function sbm__sortReference(column, direction){
  this.column = column;
  this.direction = direction;
}


// The sortby() method is a workflow method that defines the order
// of work that needs to be done.        
// The parameter columnid needs to match a property defined in our tableRow object
function sbm__sortby(tableid,columnid,columntype){
  var rowArray = sbm__createTableRowArray(tableid);

  //loop through the array and set the sortby property
  for (var x=0;x<rowArray.length;x++) {
    rowArray[x].setsorttype(columntype);
    rowArray[x].setsortby(columnid*2+1);
  }

  //get the sort direction, and store for future reference
  var direction = sbm__getSortDirection(columnid);

  //sort the array
  if (columntype == "currency" ||
      columntype == "double" ||
      columntype == "int" ||
      columntype == "float" ||
      columntype == "comma" ||
      columntype == "date" ||
      columntype == "datetime") {
    rowArray.sort(sbm__sortNumeric);
  } else {
    rowArray.sort();
  }
  //if descending reverse the array
  if (direction == "dsc") rowArray.reverse();

  // Now convert any converted date formats back to their pretty look before
  // creating the new table
  for (var x=0;x<rowArray.length;x++) {
    rowArray[x].fixsortby(columnid*2+1);
  }

  //rebuild the table from the array of tableRow objects
  sbm__alterTable(tableid,rowArray);
}

// The function that creates the data array from the contents of the table
function sbm__createTableRowArray(tableid){
  var data = new Array();
  var table = document.getElementById(tableid);
  var tbody = table.tBodies[0];
  var rows = tbody.rows;
  for (var x=0;x<rows.length;x++) {
    var cells = rows[x].cells;
    var rowdata = new Array();
    for (var y=0;y<cells.length;y++) {
      // Here we push both the contents of the cell (for rebuilding later)
      // and the text value visible (for sorting on)
      rowdata.push(cells[y].innerHTML);

      if (cells[y].firstChild.innerText &&
          cells[y].firstChild.innerText.length > 0) {
        // We grab the text from the text element
        rowdata.push(cells[y].firstChild.innerText);
      } else {
        // We grab the value from the input element
        rowdata.push(cells[y].firstChild.value);
      }
    }
    var aTableRow = new sbm__tableRow(rowdata);
    data.push(aTableRow);
  }
  return data;
}

function sbm__getSortDirection(columnid){
  if (sbm__activeSort == null || sbm__activeSort.column != columnid) {
    sbm__activeSort = new sbm__sortReference(columnid, "asc");
  }else{
    if (sbm__activeSort.direction == "asc") {
      sbm__activeSort.direction = "dsc";
    }else{
      sbm__activeSort.direction = "asc";
    }
  }
  return sbm__activeSort.direction;
}

function sbm__alterTable(tableid,rowArray){
  var table = document.getElementById(tableid);
  var tbody = table.tBodies[0];

  for (var x=0;x<rowArray.length;x++) {
    var tr = tbody.rows[x];
    for (var y=0;y<tr.cells.length;y++) {
      var td = tr.cells[y];
      td.innerHTML = rowArray[x].columnArray[y*2];
    }
  }
}

function sbm__addrow(tableid) {
  var table = document.getElementById(tableid);
  var tbody = table.tBodies[0];

  var lasttr = tbody.rows[tbody.rows.length-1];

  // Now insert a duplicate of the last tr
  tbody.rows.push(lasttr);
}

function sbm__calcTotals(tableid,tablecolumn,columntype) {
  // We calculate all the required totals for this table
  // This method is always attached to inputs within TDs
  var table = document.getElementById(tableid);
  var tbody = table.tBodies[0];

  var total = 0.0;
  // Now we sum the values for the given column, implicitly assuming to column
  // contains only our relevant input
  var rows = tbody.rows;
  for (var x=0;x<rows.length;x++) {
    var cells = rows[x].cells;
    var td = cells[tablecolumn];
    total = total + eval(sbm__numeric(td.firstChild.value));
  }
  var myTotal = document.getElementById(tableid+"_total_"+tablecolumn);

  // Now check if we are formatting a currency
  if (columntype == "currency") {
    // In this instance, we also reformat the current cell
    myTotal.value = "$"+sbm__dp(total, 2);
  } else {
    myTotal.value = total;
  }
  return;
}

