//cipertool.js
//
// Copyright 2008, by Ralph Ciper, All Rights Reserved.
// This software cannot be used without express written permission.

// Generic Tools


function CopyToClipboardByID(ID)
{
  var target;
  if (document.getElementById)
      target = document.getElementById(ID);
  else if (document.all)
      target = document.all[ID];
  else if (document.layers)
      target = document.layers[ID];
  CopyToClipboard(target);
}

function CopyToClipboard(target)
{
  ctrlRange = document.body.createControlRange();
  ctrlRange.add(target);
  ctrlRange.select();
  ctrlRange.execCommand("Copy");
  Alert("Copy Complete: " + ctrlRange.length + " Items")
}

function CopyTableToClipboard(cell)
{
	alert("Copying Table to Clipboard");
	var table = GetOwnerTable(cell);
	CopyToClipboard(table);
}

function GetCellText(cell)
{
   return cell.innerHTML;
}


function FixText(text)  // make text displayable in HTML
{
   return text.replace(/\&/,'&amp;').replace(/</,'&lt;').replace(/>/,'&gt;').replace(/\r\n/,'<BR />');
}

function GetOwnerCell(obj)   // Get the row obj is within
{ try { 
  while (obj.cellIndex == undefined) { obj = obj.parentNode; }
  return obj;
} catch (err) { Alert ("GetOwnerCell: " + err.description + "\n\n"); } }

function GetOwnerRow(obj)    // Get the row obj is within
{ try { 
  while (obj.tagName != "TR") { obj = obj.parentNode; }
  return obj;
} catch (err) { Alert ("GetOwnerCell: " + err.description + "\n\n"); } }

function GetOwnerTable(obj)  // Get the table obj is within
{ try { 
  while (obj.tagName != "TABLE") { obj = obj.parentNode; }
  return obj;
} catch (err) { Alert ("GetOwnerCell: " + err.description + "\n\n"); } }

// Debuging Functions
function Dump(item)
{
   for(var itemIndex in item)
   {
      Debug("["+itemIndex+"] "+"\r\n",true); ; // + item[itemIndex]+"\r\n",true);  
   }
}
 
var ShowAlerts = false;  // When set to false, alerts no longer show 
function Alert(text)   // Display Dialog Box with message
{
   if (ShowAlerts) ShowAlerts = window.confirm(text + "\r\n\r\n Continue Showing Message?");
}

function Debug(text,retain) // Displays Debuging Text in an element with ID: debugtext <hr /><p id="debugtext"></p>
{
   if (retain == true) document.getElementById('debugtext').innerHTML += FixText(text);
   else                document.getElementById('debugtext').innerHTML  = FixText(text);    
} 

// State Control
function StartEdit(button)
{ try {
  Debug(button.outerHTML,false);
  button.value = "Lock";
  //Debug(button.onclick,true);
  button.onclick = new Function("FinishEdit(this);")
  row = button.parentNode;
  while (row.tagName != "TR") {row = row.parentNode; }
  EditRow(row);
} catch (err) { Alert ("StartEdit: " + err.description + "\n\n"); }  }

function FinishEdit(button)
{ try  {
  Debug(button.outerHTML,false);
     button.value = "Edit";
      //Debug(button.onclick,true);
      button.onclick = new Function("StartEdit(this);");
      row = button.parentNode;
      while (row.tagName != "TR") {row = row.parentNode; }
      LockRow(row);
   }  catch (err) { Alert ("FinishEdit: " + err.description + "\n\n"); }  }

   function EditRow(row)
   {  try {
      var name = row.cells[1].innerText;
      row.cells[1].innerHTML = "<input type='text' maxlength='20' width='20'></input>";
      row.cells[1].childNodes[0].value = name;
      var level = row.cells[2].innerText;      
      row.cells[2].innerHTML = "<input type='text' maxlength='2' size='3'></input>";
      row.cells[2].childNodes[0].value = level;   
   }  catch (err) { Alert ("EditRow: " + err.description + "\n\n"); } }

   function LockRow(row)
   {  try {
      row.cells[1].innerHTML = row.cells[1].childNodes[0].value;
      row.cells[2].innerHTML = row.cells[2].childNodes[0].value;
   }  catch (err) { Alert ("LockRow: " + err.description + "\n\n"); } }

   function GetSortData(cell)
   {  try { 
      var attr = cell.getAttribute("sortvalue");    // Get attribute if one
      var val = ((attr == undefined) ? GetCellText(cell) : attr).toLowerCase();

      sortdata = val.split(/\s+/);

      //Debug("["+ val + "=",true);
      for (var i in sortdata)
      {
         if (isFinite(sortdata[i]))
         { 
            sortdata[i] = Number(sortdata[i]);
         //   Debug(sortdata[i] + ",",true);
         }
         //else Debug("\"" +sortdata[i] + "\",",true);
      }
      //Debug("]\r\n",true);
      return sortdata;
   }  catch (err) { Alert ("GetSortData: " + err.description + "\n\n"); } }


   function GetSortValues(rows, cellIndex, fn_GetData)
   {  try {     
      //Alert("Doing GetSortValues()");
      for(var rowIndex=0; rowIndex < rows.length; rowIndex++)
      {
        sortvalues[rowIndex] = fn_GetData(rows[rowIndex].cells[cellIndex]);
      }
      return sortvalues;
   }  catch (err) { Alert ("GetSortValues: " + err.description + "\n\n"); } }

   function SimpleCompare(p,q)
   {
      if (p < q) return +1;
      if (p > q) return -1;
      return 0;
   }

   function MixedCompare(p,q)
   {
      var pType = typeof p;
      var qType = typeof q;
      if (pType < qType) return +1;
      if (pType > qType) return -1;
      return SimpleCompare(p,q);
   }

   function CompareArray(p,q,extra)
   {
     if (arguments.length > 2)
     {
        for(var i = 0; i< extra.length; i++)
        {
           var comp = MixedCompare(p[extra[i]],q[extra[i]]);
           if (comp != 0) return comp;
        }
     }
     for (var i in p)
     {
        var comp = MixedCompare(p[i],q[i]);
        if (comp != 0) return comp;
     }
   }
   
   function CompareArrayDesc(p,q,extra)
   {
	   if (arguments.length > 2)
	   {
	       return -CompareArray(p,q,extra);
	   }
	   else
	   {
	       return -CompareArray(p,q);
	   }
   }

   function SortRows(tbody, sortvalues, fn_Compare, extra)        // Sort Rows tBody has rows
   {  try { 
      //Alert("starting SortRows() ");
      var pMax = tbody.rows.length-1;                             // no chance to swap last row
      var qMax = tbody.rows.length;                               // go to end while comparing

      for(var pIndex=0; pIndex < pMax; pIndex++)                   // walk there reference positions
      {
         //Alert("Row " + pIndex);
         var pValue = sortvalues[pIndex];                          // Load value of reference position
         for(var qIndex=pIndex+1; qIndex < qMax; qIndex++)         // search above reference position for anything lower values
         {
            var qValue = sortvalues[qIndex];                       // Load value of search position
            if (fn_Compare(pValue, qValue, extra) < 0)                 // <0 means q is lower than p move to place
            {
                //Alert("Inserting [" + qValue[0] + "] Before [" + pValue[0] +"]");
                var row = tbody.rows[qIndex].cloneNode(true);      // Get Complete Clone of Row searched
                tbody.deleteRow(qIndex);                           // Terminate the Searched Row
                tbody.insertBefore(row,tbody.rows[pIndex]);        // Insert to reference position
                sortvalues.splice(qIndex,1);                       // Remove the value from value array
                sortvalues.splice(pIndex,0,qValue);                // Insert the search value to reference position
                pValue = qValue;                                       // search value is new reference postion
                //Alert("Insert Complete");
            } 
         }
      }
      //Alert("Completed SortRows() ");
  }  catch (err) { Alert ("SortBy: " + err + "\n\n"); } }

   OldSortedProfile = "";
   function SortByDesc(button)
   {
	   try { 
		      //Alert("Starting SortBy()");

		      sortvalues = new Array();

		      var cell = GetOwnerCell(button);
		      var table = GetOwnerTable(cell);
		      
		      SortedProfile = [cell.cellIndex];     
		      var elementOrder = new Array;
		      var peek = arguments.length > 1 ? arguments[1] : 0;
		      for(var i=1; i < arguments.length; i++)
		      {
		         elementOrder[i-1] = arguments[i];
		         SortedProfile[i] = arguments[i];
		      }

		      SortedProfile = SortedProfile.toString();
		      //Alert(SortedProfile);
		      
		      if (SortedProfile == OldSortedProfile)
		      {
		         ReverseRows(table);
		         return;
		      }

		      var tbody = table.tBodies[0];
		      var tBodyCount = table.tBodies.length;
		      for(var tBodyIndex = 0; tBodyIndex < tBodyCount; tBodyIndex++)
		      {
		         //Alert("table.tBodies["+tBodyIndex + "] - Getting Values");
		         var rows = table.tBodies[tBodyIndex].rows;
		         var SortValues = GetSortValues(rows, cell.cellIndex, GetSortData);
		         SortRows(table.tBodies[tBodyIndex], SortValues, CompareArrayDesc, elementOrder);
		         ResetRowBands(table.tBodies[tBodyIndex].rows);
		         //Alert("Sort Complete");
		         /*
		         Debug("peek =" + peek + "\r\n");
		         for(var rowIndex=0; rowIndex < rows.length; rowIndex++)
		         {
		            Debug("rowIndex: "+ rowIndex + " ");
		            var row = rows[rowIndex];
		            var val = SortValues[rowIndex][peek];
		            Debug("value = "+ val + "\r\n");
		            row.cells[0].innerText = val;
		         }
		         */
		         //Alert("Index Complete");
		      }
		      OldSortedProfile = SortedProfile;
		   }  catch (err) { Alert ("SortBy: " + err + "\n\n"); } }
   function SortBy(button)
   {  try { 
      //Alert("Starting SortBy()");

      sortvalues = new Array();

      var cell = GetOwnerCell(button);
      var table = GetOwnerTable(cell);
      
      SortedProfile = [cell.cellIndex];     
      var elementOrder = new Array;
      var peek = arguments.length > 1 ? arguments[1] : 0;
      for(var i=1; i < arguments.length; i++)
      {
         elementOrder[i-1] = arguments[i];
         SortedProfile[i] = arguments[i];
      }

      SortedProfile = SortedProfile.toString();
      //Alert(SortedProfile);
      
      if (SortedProfile == OldSortedProfile)
      {
         ReverseRows(table);
         return;
      }

      var tbody = table.tBodies[0];
      var tBodyCount = table.tBodies.length;
      for(var tBodyIndex = 0; tBodyIndex < tBodyCount; tBodyIndex++)
      {
         //Alert("table.tBodies["+tBodyIndex + "] - Getting Values");
         var rows = table.tBodies[tBodyIndex].rows;
         var SortValues = GetSortValues(rows, cell.cellIndex, GetSortData);
         SortRows(table.tBodies[tBodyIndex], SortValues, CompareArray, elementOrder);
         ResetRowBands(table.tBodies[tBodyIndex].rows);
         //Alert("Sort Complete");
         /*
         Debug("peek =" + peek + "\r\n");
         for(var rowIndex=0; rowIndex < rows.length; rowIndex++)
         {
            Debug("rowIndex: "+ rowIndex + " ");
            var row = rows[rowIndex];
            var val = SortValues[rowIndex][peek];
            Debug("value = "+ val + "\r\n");
            row.cells[0].innerText = val;
         }
         */
         //Alert("Index Complete");
      }
      OldSortedProfile = SortedProfile;
   }  catch (err) { Alert ("SortBy: " + err + "\n\n"); } }

   function ReverseRows(table)
   {  try {
      //Alert("Starting ReverseRows()");
       var tBodyCount = table.tBodies.length;
       for(var tBodyIndex = 0; tBodyIndex < tBodyCount; tBodyIndex++)
       {
          var tbody = table.tBodies[tBodyIndex];
          var rowCount = tbody.rows.length;              
          for(var rowIndex=1; rowIndex < rowCount; rowIndex++)  // walk there reference positions
          { 
             var row = tbody.rows[rowIndex].cloneNode(true);    // Get Complete Clone of Row searched
             tbody.deleteRow(rowIndex);                         // Terminate the Searched Row
             tbody.insertBefore(row,tbody.rows[0]);             // Insert in front
          }
          ResetRowBands(table.tBodies[tBodyIndex].rows);
       }
      //Alert("ReverseRows() Complete");
   }  catch (err) { Alert ("ReverseRows: " + err + "\n\n"); } }

   function FindText(input, test)
   {  //Alert ("Starting FindText");
      onReset(input,'value','');
      if (test == "")
      {
         ResetRows(input);
      }
      else
      {   
         MatchRowText(GetOwnerTable(input)
                     ,GetOwnerCell(input).cellIndex
                     ,SafeRegex(test)); 
      }
   }
   
   function DoNothing(){return true; }
   function SafeRegex(text)
   {
      holderr = window.onerror;
      regex = /^$/;
      window.onerror = DoNothing;
      regex = new RegExp(text,"i");
      window.onerror = holderr;
      return regex;
   }
   
   var LastFilter = {input: undefined } 
   
   function HideRow(row,i)    {row.className = 'hiderow row' + ((i%6)+1); } 
   function ShowRow(row,i,ii) {row.className = 'showrow'+ ((ii%6)+1) + ' row' + ((i%6)+1);  Alert(row.className);}
   function IsHidden(row)     {return /\bhiderow\b/.test(row.className); }
    
   function ResetRowBands(rows)
   {
      var iMatch = 0;
      for(var iRow=0; iRow < rows.length; iRow++)
      {
         row = rows[iRow];
         if (IsHidden(row))
         {
            HideRow(row,iRow);
         }
         else
         {
            ShowRow(row,iRow,iMatch++);
         }
      }
   } 
     
   function onReset(input,prop,value)
   {
      if (LastFilter.input == input) return;
      if (LastFilter.input != undefined)
      {
         LastFilter.input[LastFilter.prop] = LastFilter.value;
      }
      LastFilter.input = input;
      LastFilter.prop  = prop;
      LastFilter.value = value;
   }
   
   function FindRangeInt(input, test) 
   {
      onReset(input,'value','');
      test = test.replace(/[^\d\-\+\<\>]/g,"");
      table     = GetOwnerTable(input);
      cellIndex = GetOwnerCell(input).cellIndex;
      values    = test.split(/[^\d]+/);
      
      switch (values.length)
      {
      case 1:
         if ( /^\d+?$/.test(test) ) // Absolute nn 
         {  
             //Alert("Do Absolute: " + test + "\r\n Values[" + values[0] + "," + values[1] + "]");
             FindUsingRange(table, cellIndex, Number(values[0]), Number(values[0]));
         }
         else 
         {
            ResetRows(input);
         }
         break;
      case 2:
         if ( /^\d+?\-\d+$/.test(test) ) // Range nn-nn
         {  
            //Alert("Do Range: " + test + "\r\n Values[" + values[0] + "," + values[1] + "]"); 
            FindUsingRange(table, cellIndex, Number(values[0]), Number(values[1]));
         }
         else if ( /^[\-<]\d+?$/.test(test) ) // Max Value  -nn or <nn
         {  
            Alert("Do Max: " + test + "\r\n Values[" + values[0] + "," + values[1] + "]"); 
            FindUsingRange(table, cellIndex, 0, Number(values[1]));
         }
         else if ( /^\d+(\-|\+)$/.test(test) ) // Min Value nn+ or nn-
         {  
            Alert("Do Min: " + test + "\r\n Values[" + values[0] + "," + values[1] + "]"); 
            FindUsingRange(table, cellIndex, Number(values[0]), Number.POSITIVE_INFINITY);
         }
         else if ( /^[\-<]\d+?$/.test(test) ) // Min Value  >nn
         {  
            Alert("Do Min: " + test + "\r\n Values[" + values[0] + "," + values[1] + "]"); 
            FindUsingRange(table, cellIndex, Number(values[1]), Number.POSITIVE_INFINITY);
         }        
         else 
         {
            ResetRows(input);
         }
         break;
      default:
         //Alert("Range Error: " + test + "\r\n "+values.length +" Parts --Values[" + values[0] + "," + values[1] + "]"); 
         ResetRows(input);
         break;
      }
   }
   

   
   function FindUsingRange(table, cellIndex, low, high)
   {
      if (high < low) { var val = high; high = low + val; low = low - val; } // if high is less than low its a variance
      var tBodyCount = table.tBodies.length;
      for (var tBodyIndex=0; tBodyIndex < tBodyCount; tBodyIndex++)
      {
        tBody = table.tBodies[tBodyIndex];
        var iMatch = 0;
        for(var rowIndex=0; rowIndex < tBody.rows.length; rowIndex++)
        {
           row = tBody.rows[rowIndex];
           value = GetCellText(row.cells[cellIndex]);
           value = (isFinite(value)) ? Number(value) : 0; 
           if (value >= low && value <= high)
           {
              ShowRow(row,rowIndex,iMatch++);
           }
           else
           {
              HideRow(row,rowIndex);
           }
        }
      }
   }
     
   function FindBy(select, test, attribute)
   {  //try { //Alert ("Starting FindBy");
      if (select.selectedIndex == 0)
      {
         ResetRows(select);
      }
      else
      {
         MatchRowText(GetOwnerTable(select), GetOwnerCell(select).cellIndex, SafeRegex(test), attribute);
      }
   }  //catch (err) { Alert ("FindBy: " + err + "\r\n"); } }
   
   function MatchRowText(table, cellIndex, regex, attribute)
   { //try {   //Alert ("Starting MatchRowText"); 
      var tBodyCount = table.tBodies.length;
      for (var tBodyIndex=0; tBodyIndex < tBodyCount; tBodyIndex++)
      {
        //Alert ("Starting Body: " + tBodyIndex + "\r\n")
        tBody = table.tBodies[tBodyIndex];
        var iMatch = 0;
        for(var rowIndex=0; rowIndex < tBody.rows.length; rowIndex++)
        {
           row = tBody.rows[rowIndex];
           text = (attribute == undefined)? GetCellText(row.cells[cellIndex]) :  row.cells[cellIndex].getAttribute(attribute);
           if (regex.test(text))
           {
             //Alert("Showing Row: " + rowIndex + " = \"" + row.cells[cellIndex].innerText + "\"");
             ShowRow(row,rowIndex,iMatch++);
           }
           else
           {
             //Alert("Hiding Row: " + rowIndex + " = \"" + row.cells[cellIndex].innerText + "\"");
             HideRow(row,rowIndex);
           }
        }
      }
   } //catch (err) { Alert ("MatchRowText: " + err + "\r\n"); } }

   function ResetRows(obj)
   {  try {   //Alert ("Starting ResetRows");
      var table  = GetOwnerTable(obj);
      var tBodyCount = table.tBodies.length;
      for (var tBodyIndex=0; tBodyIndex < tBodyCount; tBodyIndex++)
      {
        tBody = table.tBodies[tBodyIndex];
        for(var rowIndex=0; rowIndex < tBody.rows.length; rowIndex++)
        {
          row = tBody.rows[rowIndex];
          ShowRow(row,rowIndex,rowIndex);
        }
      } 
   }  catch (err) { Alert ("ResetRows: " + err + "\r\n"); } }

   function AddStart(button)
   {
      var table = button.parentNode;
      while(table.tagName != 'TABLE') {table = table.parentNode;}
      document.all.datatext.innerText = table.tBodies[0].rows[0].outerHTML;
   }
   function CloneRow(tbody,rowIndex,rowSource)
   {
      var newRow = tbody.rows[rowSource].cloneNode(true);
      tbody.appendChild(newRow);
   }
   function MoveRowTo(tbody,rowIndex,rowSource)
   {  try { teststate = "Row Move";
      if (rowIndex == rowSource) return;                              // No reason to move it if already there
      var newRow = tbody.rows[rowSource].cloneNode(true);             // Get Complete Clone of Source Row
      tbody.deleteRow(rowSource);                                     // Terminate Original
      tbody.insertBefore(newRow,tbody.rows[rowIndex]);                // Insert Clone in position
      teststate = "Value Move";
      var newVal = sortvalues[rowSource];
      sortvalues.splice(rowSource,1);                                  // Terminate Original
      sortvalues.splice(rowIndex,0,newVal);                            // Insert Clone in position
   }  catch (err) { Alert ("MoveTo[" + teststate + "]-- " + err + "\n\n"); } }
   function MoveRowToEnd(tbody,rowSource)
   {
      var newRow = tbody.rows[rowSource].cloneNode(true);
      tbody.appendChild(newRow);
      tbody.deleteRow(rowSource);
   }

   function ksort(array, sort_flags) {
	    // http://kevin.vanzonneveld.net
	    // +   original by: GeekFG (http://geekfg.blogspot.com)
	    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   improved by: Brett Zamir (http://brettz9.blogspot.com)
	    // %          note: The examples are correct, this is a new way
	    // *     example 1: data = {2: 'van', 3: 'Zonneveld', 1: 'Kevin'};
	    // *     example 1: ksort(data);
	    // *     results 1: data == {1: 'Kevin', 2: 'van', 3: 'Zonneveld'}
	    // *     returns 1: true
	 
	    var tmp_arr={}, keys=[], sorter, i, key, that=this;
	 
	    switch (sort_flags) {
	        case 'SORT_STRING': // compare items as strings
	            sorter = function (a, b) {
	                return that.strnatcmp(a, b);
	            };
	            break;
	        case 'SORT_LOCALE_STRING': // compare items as strings, based on the current locale (set with  i18n_loc_set_default() as of PHP6)
	            sorter = function (a, b) {
	                return(a.localeCompare(b));
	            };
	            break;
	        case 'SORT_NUMERIC': // compare items numerically
	            sorter = function (a, b) {
	                return(a - b);
	            };
	            break;
	        case 'SORT_REGULAR': // compare items normally (don't change types)
	        default:
	            sorter = function (a, b) {
	                if (a > b) {
	                    return 1;
	                }
	                if (a < b) {
	                    return -1;
	                }
	                return 0;
	            };
	            break;
	    }
	 
	    // Make a list of key names
	    for (key in array) {
	        keys.push(key);
	    }
	 
	    keys.sort(sorter);
	 
	    // Rebuild array with sorted key names
	    for (i = 0; i < keys.length; i++) {
	        key = keys[i];
	        tmp_arr[key] = array[key];
	        delete array[key];
	    }
	    for (i in tmp_arr) {
	        array[i] = tmp_arr[i]
	    }
	 
	    return true;
	}

	function ChartThis(obj)
	{
	   var cell = GetOwnerCell(obj);
	   var cellIndex = cell.cellIndex;
	   //alert("ChartThis");
	   var url = "http://chart.apis.google.com/chart?cht=p3&chs=700x300&chf=bg,s,00000000&chxs=0,FFFFFF,13,-1,t,FF0000"
	             + "&chco=FF0000,FF8800,FFFF00,00FF00,0000DD,DD00DD"
	   var table = GetOwnerTable(cell);  
	   var chart = new Array();
	   var rows = table.tBodies[0].rows;
	   var rowCount = rows.length;
	   for (var rowIndex=0; rowIndex < rowCount; rowIndex++)
	   {
	      if (!IsHidden(rows[rowIndex]))
	      { 
	        var attr = rows[rowIndex].cells[cellIndex].getAttribute("chartas");
	        var value = attr == undefined ? rows[rowIndex].cells[cellIndex].innerHTML : attr;
	      
	        value = value.replace(/\s/g,"+").replace("ó","o");
	        if (chart[value] == undefined)
	        {
	           //alert(value);
	           chart[value] = 1;
	        }
	        else
	        {
	           chart[value]++;
	        }
	      }  
	   }
	   ksort(chart);
	   var weights = "&chd=t:"; 
	   var tags    = "&chl=";
	   var labels  = "&chdl=";
	   var valSep = "";
	   var txtSep = "";
	   for (chartLabel in chart)
	   {
	      //alert(chartLabel + ":"  + chart[chartLabel]);
	      weights += valSep + chart[chartLabel];
	      tags    += txtSep + chart[chartLabel];
	      labels  += txtSep + chartLabel + "(" + chart[chartLabel] +")"
	      valSep = ",";
	      txtSep = "|";
	   }
	   url += weights + tags + labels;
	   //alert(url);
	   element = document.getElementById("chart");
	   element.src = url;
	}

