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));
};

stripWhitespace = String.prototype.stripWhitespace = function()
{
  return ((arguments.length>0)?((typeof(arguments[0])=='string')?arguments[0]:arguments[0].toString()):this).replace(/[\s\t\r\n]/g,'');
};

escapeHTML = String.prototype.escapeHTML = function()
{
  return ((arguments.length>0)?((typeof(arguments[0])=='string')?arguments[0]:arguments[0].toString()):this).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;');
};

unescapeHTML = String.prototype.unescapeHTML = function()
{
  return ((arguments.length>0)?((typeof(arguments[0])=='string')?arguments[0]:arguments[0].toString()):this).replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&quot;/g,'"').replace(/&amp;/g,'&');
};

stripQuotes = String.prototype.stripQuotes = function()
{
  return ((arguments.length>0)?((typeof(arguments[0])=='string')?arguments[0]:arguments[0].toString()):this).replace(/['"]/g,'');
};

escapeQuotes = String.prototype.escapeQuotes = function()
{
  var newString = ((arguments.length>0)?((typeof(arguments[0])=='string')?arguments[0]:arguments[0].toString()):this);
  newString = newString.replace(/\\/g,'\\\\');
  newString = String.replaceStr(newString,'\'','\\\'',false);
  newString = String.replaceStr(newString,'"','&quot;',false);
  return newString;
};

unescapeQuotes = String.prototype.unescapeQuotes = function()
{
  var newString = ((arguments.length>0)?((typeof(arguments[0])=='string')?arguments[0]:arguments[0].toString()):this);
  newString = newString.replace(/\\\\/g,'\\');
  newString = String.replaceStr(newString,'\\\'','\'',false);
  newString = String.replaceStr(newString,'&quot;','"',false);
  return newString;
};

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 depth = ((arguments.length >= 4)?(arguments[3]):(-1));
  var objectType = typeof(object);
  if (objectType.toLowerCase() == "object")
    for (var i in object)
    {
      var currentPrefix = stringPrefix+'['+i+']';
      if (depth>0)
        totalString = totalString + describeObject(currentPrefix,object[i],lineTerminator,depth-1);
      else
        if (depth==-1)
          totalString = totalString + describeObject(currentPrefix,object[i],lineTerminator,-1);
    }
  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);
  newstyle.disabled = false;  //IE fix
};

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('<span class="logWarning">warning:</span>  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);
};


Freeance_Communication=function(){};
Freeance_Communication.javascript_load = function(scriptURL /*,callbackFunction*/)
{
  /* TODO:  Test compatibility in Konqueror, Opera */
  dprintf('<span class="logNotice">loadJavaScript('+scriptURL+')</span>',true);
  if (document.jsload_setwait)      //load script notification function
    document.jsload_setwait(true);
  var callbackFunction = null;
  var ie_attempt_counter=5;
  var returnValue = false;
  if (arguments.length>1)
    callbackFunction = arguments[1];
  if(arguments.length>2)
    ie_attempt_counter=arguments[2];
  var ele = document.createElement('SCRIPT');
  ele["$_JAVASCRIPT_DYNAMIC_LOAD_COMPLETE_$"]=false;  //load complete indicator
  if (ele.readyState==null){  //Firefox and Safari support an onload event; IE supports readystate
    ele.setAttribute('language','JavaScript');
    ele.setAttribute('src',scriptURL);
    ele.addEventListener("load",function(e){
      ele["$_JAVASCRIPT_DYNAMIC_LOAD_COMPLETE_$"]=true;
      if (document.jsload_setwait)
        document.jsload_setwait(false);
      if (callbackFunction)
        callbackFunction();
    },false);
    document.body.appendChild(ele);
  }
  else
  {
    /*readystate method was not reliable due to caching issues
      discard script element and do it the old fashioned way - 
      this loses line numbers in error messages.*/
    XmlHttp.loadTextASync(scriptURL,function(scriptcode){
      dprintf('<span class="logNotice">loadJavaScript('+scriptURL+') - executing script</span>',true);
      eval(scriptcode);
      if (document.jsload_setwait)
        document.jsload_setwait(false);
      if (callbackFunction)
        callbackFunction();
    });
  };
  returnValue = true;
  return true;
};
loadJavaScript = Freeance_Communication.javascript_load;

Freeance_Communication.xmlrpc_request = function(/*Callback,function_name,param[1],...param[n]*/)
{
  var Callback = arguments[0];
  var functionName = arguments[1];
  var returnValue = null;
  var thisRequest = new XMLRPCMessage(functionName);
  for (lcv = 2; lcv < arguments.length; lcv++)
    thisRequest.addParameter(arguments[lcv]);
  var thisRequestDoc = XmlDocument.create();
  thisRequestDoc.loadXML(thisRequest.xml());
  if (Callback)
    returnValue = XmlHttp.postAsync_(FREEANCE_XMLRPC_URL,thisRequestDoc,function(xmlrpc_response){Callback(getXMLRPCResponseObject(xmlrpc_response));});
  else
    returnValue = getXMLRPCResponseObject(XmlHttp.postSync(FREEANCE_XMLRPC_URL,thisRequestDoc));
  return returnValue;
};
freeance_request = Freeance_Communication.xmlrpc_request;

Freeance_Error = function(){};
Freeance_Error.is_error = function(data){
  if (data===null) return true;
  if (data===undefined) return true;
  if (data['XMLRPC_FAULT']) return true;
  if (data['FREEANCE_FAULT'])return true;
  if (data['GUILIB_FAULT'])return true;
  return false;
};
Freeance_Error.get_message=function(data){
  if (data===null) return 'Value is null';
  if (data===undefined) return 'Value is undefined';
  if (data['XMLRPC_FAULT']) return data['XMLRPC_FAULT_MESSAGE'];
  if (data['FREEANCE_FAULT']) return data['FREEANCE_FAULT_MESSAGE'];
  if (data['GUILIB_FAULT']) return data['GUILIB_FAULT_MESSAGE'];
  return null;
};
Freeance_Error.get_code=function(data){
  if (data===null) return -1001;
  if (data===undefined) return -1002;
  if (data['XMLRPC_FAULT']) return data['XMLRPC_FAULT_CODE'];
  if (data['FREEANCE_FAULT']) return data['FREEANCE_FAULT_CODE'];
  if (data['GUILIB_FAULT']) return data['GUILIB_FAULT_CODE'];
  return null;
};
Freeance_Error.xmldoc_is_valid=function(xmlDoc)
{ 
  try
  {
    if(xmlDoc == null) 
      return false;
    var xmlstr = (typeof(xmlDoc.xml)=='function')?xmlDoc.xml():xmlDoc.xml;
    if(xmlstr == '')
      return false;
    if(xmlDoc.documentElement.nodeName == 'parsererror')
      return false;
    return true;
  }
  catch(e)
  {
    return false;
  }
};



Freeance_Event = function(){};
Freeance_Event.add = function(ele,type,fcn)
{
  type=type.toLowerCase();
  var cap = (arguments.length>3)?arguments[3]:false;
  if (!ele.FREEANCE_EVENTS)
    ele.FREEANCE_EVENTS = [];
  ele.FREEANCE_EVENTS.push({evt:type,fcn:fcn});
  if(ele.addEventListener) 
    ele.addEventListener(type,fcn,cap);
  else 
    if(ele.attachEvent)
      ele.attachEvent('on'+type,fcn);
    else
      return {FREEANCE_FAULT:true,FREEANCE_FAULT_CODE:-1003,FREEANCE_FAULT_MESSAGE:'Browser does not support dynamic addition of events to elements'};
  return true;
};
Freeance_Event.remove = function(ele,type,fcn)
{
  type=type.toLowerCase();
  var cap = (arguments.length>3)?arguments[3]:false;
  if (ele.FREEANCE_EVENTS)
  {
    for (var i=0;i<ele.FREEANCE_EVENTS.length;i++)
      if (ele.FREEANCE_EVENTS[i])
        if((ele.FREEANCE_EVENTS[i]['evt']==type)&&(ele.FREEANCE_EVENTS[i]['fcn']==fcn))
          ele.FREEANCE_EVENTS[i] = null;
  }
  if(ele.removeEventListener) 
    ele.removeEventListener(type,fcn,cap);
  else 
    if(ele.detachEvent)
      ele.detachEvent('on'+type,fcn);
    else
      return {FREEANCE_FAULT:true,FREEANCE_FAULT_CODE:-1003,FREEANCE_FAULT_MESSAGE:'Browser does not support dynamic addition of events to elements'};
  return true;
};
Freeance_Event.remove_all = function(ele)
{
  if (ele.FREEANCE_EVENTS!=null)
  {
    for (var i=0;i<ele.FREEANCE_EVENTS.length;i++){
      if(ele.removeEventListener) 
        ele.removeEventListener(ele.FREEANCE_EVENTS[i]['evt'],ele.FREEANCE_EVENTS[i]['fcn'],ele.FREEANCE_EVENTS[i]['cap']);
      else 
        if(ele.detachEvent)
          ele.detachEvent('on'+ele.FREEANCE_EVENTS[i]['evt'],ele.FREEANCE_EVENTS[i]['fcn']);
        else
          return {FREEANCE_FAULT:true,FREEANCE_FAULT_CODE:-1003,FREEANCE_FAULT_MESSAGE:'Browser does not support dynamic addition of events to elements'};
    }
    ele.FREEANCE_EVENTS=null;
  }
  return true;
};

