String.replaceStr = function(orig,lookfor,replacewith,ignorecase)  // JPW::Jan 6, 2003
{
  //alert('String.replaceStr');
  var str = new String();
  str += orig;
  var type = 'g';
  if (ignorecase)
    type += 'i';
  var re = new RegExp (lookfor, type);
  return(str.replace(re,replacewith));
};

String.stripWhitespace = function(newString)
{
  newString = String.replaceStr(newString,' ','',false);
  newString = String.replaceStr(newString,'\n','',false);
  newString = String.replaceStr(newString,'\r','',false);
  newString = String.replaceStr(newString,'\t','',false);
  return newString;
};
stripWhitespace = String.stripWhitespace;

String.escapeHTML = function(newString)
{
  newString = String.replaceStr(newString,'&','&amp;',false);
  newString = String.replaceStr(newString,'<','&lt;',false);
  newString = String.replaceStr(newString,'>','&gt;',false);
  newString = String.replaceStr(newString,'"','&quot;',false);
  return newString;
};
escapeHTML = String.escapeHTML;

String.unescapeHTML = function(newString)
{
  newString = String.replaceStr(newString,'&lt;','<',false);
  newString = String.replaceStr(newString,'&gt;','>',false);
  newString = String.replaceStr(newString,'&quot;','"',false);
  newString = String.replaceStr(newString,'&amp;','&',false);
  return newString;
};
unescapeHTML = String.unescapeHTML;

String.stripQuotes = function(newString)
{
  newString = String.replaceStr(newString,'\'','',false);
  newString = String.replaceStr(newString,"\"","",false);
  return newString;
};
stripQuotes = String.stripQuotes;

String.escapeQuotes = function(newString)
{
  newString = newString.replace(/\\/g,'\\\\');
  newString = String.replaceStr(newString,'\'','\\\'',false);
  newString = String.replaceStr(newString,'"','&quot;',false);
  return newString;
};
escapeQuotes = String.escapeQuotes;


String.unescapeQuotes = function(newString)
{
  newString = newString.replace(/\\\\/g,'\\');
  newString = String.replaceStr(newString,'\\\'','\'',false);
  newString = String.replaceStr(newString,'&quot;','"',false);
  return newString;
};
unescapeQuotes = String.unescapeQuotes;

String.prototype.ltrim = function()
{
  return this.replace(/^\s+/,'');
};

String.prototype.rtrim = function()
{
  return this.replace(/\s+$/,'');
};

String.prototype.strtrim = function()
{
  return this.replace(/^\s+/,'').replace(/\s+$/,'');
};

function getArrayLength (arr)
{
  /* since in some instances involving delete, JS seems to get it wrong */
  var count = 0;
  for(var idx in arr)
    if ((typeof(arr[idx]) != 'undefined') && (arr[idx]!=null))
      count++;
  return(count);
};

function describeObject(stringPrefix, object)
{
  var totalString = '';
  var lineTerminator = ((arguments.length >= 3)?(arguments[2]):("<br>"));
  var objectType = typeof(object);
  if (objectType.toLowerCase() == "object")
    for (var i in object)
    {
      var currentPrefix = stringPrefix+'['+i+']';
      totalString = totalString + describeObject(currentPrefix,object[i],lineTerminator);
    }
  else
    totalString = totalString + stringPrefix+' = ' + object + lineTerminator;
  return totalString;  
};

function DataTypeOf(o){
  // identifies the data type
  var type = typeof(o);
  type = type.toLowerCase();
  switch(type){
    case "number":
      if (Math.round(o) == o) type = "i4";
      else type = "double";
      break;
    case "object":
      var con = o.constructor;
      if (con == Date) type = "date";
      else if (con == Array) type = "array";
      else type = "struct";
      break;
  }
  return type;
};

function duplicateNodeTreeEmbeddingStyles(theNode)
{
  var newNode = theNode.cloneNode(false);
  if(theNode.nodeType == 1)  // copy the "calculated" style
  {
    if(theNode.getAttribute('action_button'))
      return(null);
    if(theNode.currentStyle)
    {
      for(var attribName in theNode.currentStyle)
      {
        var attribValue = theNode.currentStyle[attribName];
        if ((attribValue != '') && (attribValue != 'undefined') && (attribValue != 'none') && (attribValue != 'normal') && (attribValue != 'auto'))
          newNode.style[attribName] = attribValue;
      }
    }
    else if (window.getComputedStyle)
    {
      var newStyles = window.getComputedStyle(theNode,null);
      for (var lcv=0;lcv < newStyles.length;lcv++)
      {
        var attribName = newStyles.item(lcv);
        var attribValue = newStyles.getPropertyValue(attribName);
        if (attribValue.indexOf('-moz') >= 0) {} else
        if ((attribValue != '') && (attribValue != 'undefined') && (attribValue != 'none') && (attribValue != 'normal') && (attribValue != 'auto'))
          newNode.style.setProperty(attribName,attribValue,null);
      }
    }
  }
  for(var lcv=0;lcv < theNode.childNodes.length;lcv++)
  {
    var cNode = duplicateNodeTreeEmbeddingStyles(theNode.childNodes[lcv]);
    if(cNode != null)
      newNode.appendChild(cNode);
  }
  return(newNode);
};

function duplicateNodeTreeEmbeddingStylesSubset(theNode)
{
  var newNode = theNode.cloneNode(false);
  if(theNode.nodeType == 1)  // copy the "calculated" style
  {
    if(theNode.getAttribute('action_button'))
      return(null);
    try { newNode.removeAttribute('class'); newNode.removeAttribute('className'); } catch (e) { }
    if(theNode.currentStyle)
    {
      var copyAttribs = Array('margin','borderColor','borderStyle','borderWidth','backgroundColor','color','fontStyle','fontFamily','fontSize','fontWeight','padding','width','height','textAlign','textDecoration','cursor','visibility');
      for(var lcv=0;lcv < copyAttribs.length;lcv++)
      {
        var attribName = copyAttribs[lcv];
        var attribValue = theNode.currentStyle.getAttribute(attribName);
        if ((attribValue != null) && (attribValue != '') && (attribValue != 'undefined') && (attribValue != 'none') && (attribValue != 'normal') && (attribValue != 'auto') && (attribValue != 'transparent') && (attribValue != 'visible') && (attribValue != 'inherit'))
        try{ newNode.style[attribName] = attribValue; } catch(e){}
      }
    }
    else if (window.getComputedStyle)
    {
      var copyAttribs = Array('margin','border-bottom-color','border-bottom-width','border-bottom-style','border-top-color','border-top-width','border-top-style','border-left-color','border-left-width','border-left-style','border-right-color','border-right-width','border-right-style','background-color','color','font-family','font-size','font-weight','padding','width','height','text-align','text-decoration','cursor','visibility');
      var newStyles = window.getComputedStyle(theNode,null);
      for (var lcv=0;lcv < copyAttribs.length;lcv++)
      {
        var attribName = copyAttribs[lcv];
        var attribValue = newStyles.getPropertyValue(attribName);
        if ((attribValue != null) && (attribValue != '') && (attribValue != 'undefined') && (attribValue != 'none') && (attribValue != 'normal') && (attribValue != 'auto') && (attribValue != 'transparent') && (attribValue != 'visible') && (attribValue != 'inherit'))
          newNode.style.setProperty(attribName,attribValue,null);
      }
    }
  }
  for(var lcv=0;lcv < theNode.childNodes.length;lcv++)
  {
    var cNode = duplicateNodeTreeEmbeddingStylesSubset(theNode.childNodes[lcv]);
    if(cNode != null)
      newNode.appendChild(cNode);
  }
  return(newNode);
};

document.addStylesheet = function (url)
{
  var newstyle = document.createElement('LINK');
  newstyle.setAttribute('type','text/css');
  newstyle.setAttribute('href',url);
  newstyle.setAttribute('rel','stylesheet');
  newstyle.setAttribute('disabled','false');
  var headElem = document.getElementsByTagName('head')[0];
  headElem.appendChild(newstyle);
  //testing.... this at least fixes things in explorer!
  newstyle.disabled = false;
};

function cloneObject(originalObject)
{
  /** TODO:  VERIFY TYPE CASTING IN THIS FUNCTION **/
  if (originalObject == null)
    newObject = null;
  else
  {
    var newObject = null;
    var objectType = typeof(originalObject);
    objectType = objectType.toLowerCase();
    if (objectType == "object")
    {
      var con = originalObject.constructor;
      if (con == Date)
        objectType = "date";
      else 
        if (con == Array)
          objectType = "array";
        else
          type="object";
    }
    switch (objectType)
    {
      case "object":
        newObject = new Object;
        for (var i in originalObject){
          try{
            newObject[i] = cloneObject(originalObject[i]);
          }
          catch(e){
            //probably tried to descend to a system object
            dprintf('warning:  attribute "'+i+'" could not be duplicated by cloneNode.');
            newObject[i]=null;
          }
        }
        break;
      case "array":
        newObject = new Array;
        for (var i=0; i<originalObject.length; i++)
          newObject[i] = cloneObject(originalObject[i]);
        break;
      default:
        newObject = originalObject;
    }
  }
  return newObject;
};

function setClass(elementId,newClass)
{
  var elementReference = ((typeof(elementId)=='object')?(elementId):(document.getElementById(elementId)));
  while((elementReference != null) && (elementReference.nodeName == '#text'))
     elementReference = elementReference.parentNode;
  if (elementReference != null)
    elementReference.className = newClass;
};


function convertDistance(dist,srcUnit,destUnit)
{
  if (srcUnit == destUnit)
    return(dist);
  var newdist = dist;
  /* convert to meters */
  switch (srcUnit.toLowerCase())
  {
    case 'mm':
      newdist = dist/1000.0;
      break;
    case 'cm':
      newdist = dist/100.0;
      break;
    case 'm':
      newdist = dist;
      break;
    case 'km':
      newdist = dist * 1000;
      break;
    case 'in':
      newdist = dist*0.0254;
      break;
    case 'ft':
      newdist = dist*0.3048;
      break;
    case 'yd':
      newdist = dist*0.9144;
      break;
    case 'mi':
      newdist = dist * 1609.344;
      break;
  }
  /* convert to requested units */
  switch (destUnit.toLowerCase())
  {
    case 'mm':
      newdist = newdist * 1000;
      break;
    case 'cm':
      newdist = newdist * 100;
      break;
    case 'in':
      newdist = newdist * 39.37007874;
      break;
    case 'ft':
      newdist = newdist * 3.2808399;
      break;
    case 'yd':
      newdist = newdist * 1.0936133;
      break;
    case 'mi':
      newdist = newdist * 0.00062137;
      break;
    case 'm':
      break;
    case 'km':
      newdist = newdist * .001;
      break;
  }
  return(newdist);
};
