//------------------------------------
//
// DESCRIPTION
//   Standard Javascript libraries.
//
// VERSION INFORMATION
//   $Header: stdLibs_client.js, 1, 9/27/2005 10:32:36 AM, axacore$
//   $NoKeywords$   
//
//------------------------------------


//------------------------------------
// Color functions.
//------------------------------------



function fnColorUtilCalcComponent(pnColor1Val,pnColor2Val,pnPercent) {
    var nDif = pnColor2Val - pnColor1Val;
    return Math.round(pnColor1Val - (-(pnPercent*nDif/100)));
}

function fnColorUtilGetHexColorNumber(pnColor) {
    return fnStrUtilLPad(new Number(pnColor).toString(16),2,'0')
}

function fnColorUtilGetInterpolatedColor(psColor1,psColor2,pnPercent1To2) {
    var nColor1R = fnNumUtilHexToDec(psColor1.substring(1,3));
    var nColor1G = fnNumUtilHexToDec(psColor1.substring(3,5));
    var nColor1B = fnNumUtilHexToDec(psColor1.substring(5,7));
    var nColor2R = fnNumUtilHexToDec(psColor2.substring(1,3));
    var nColor2G = fnNumUtilHexToDec(psColor2.substring(3,5));
    var nColor2B = fnNumUtilHexToDec(psColor2.substring(5,7));

    return "#" +
           fnColorUtilGetHexColorNumber(fnColorUtilCalcComponent(nColor1R,nColor2R,pnPercent1To2)) + 
           fnColorUtilGetHexColorNumber(fnColorUtilCalcComponent(nColor1G,nColor2G,pnPercent1To2)) + 
           fnColorUtilGetHexColorNumber(fnColorUtilCalcComponent(nColor1B,nColor2B,pnPercent1To2));        

}

//------------------------------------
// Cookie functions.
//------------------------------------

function fnCookieSet(sName, sValue) {
  // Create a cookie with the specified name and value.
  // The cookie expires at the end of the 20th century
  date = new Date(new Date().getTime() + 60*60*1000);
  document.cookie = sName + "=" + escape(sValue) + "; path=/; expires=" + date.toGMTString();
}

function fnCookieGet(sName) {
  // cookies are separated by semicolons
  var aCookie = document.cookie.split("; ");
  for (var i=0; i < aCookie.length; i++) {
    // a name/value pair (a crumb) is separated by an equal sign
    var aCrumb = aCookie[i].split("=");
    if (sName == aCrumb[0]) 
      return unescape(aCrumb[1]);
  }

  // a cookie with the requested name does not exist
  return null;
}


//------------------------------------
// Date Utility functions.
//------------------------------------

/**
 * The mask may contain the following symbols:
 *   M     - month as a number 1 to 12
 *   MM    - month as a number 01 to 12
 *   d     - day of month as a number 1 to 31
 *   dd    - day of month as a number 01 to 31
 *   yy    - last two digits of year
 *   yyyy  - full year
 *   h     - hour as a number 1 to 12
 *   hh    - hour as a number 01 to 12
 *   H     - hour as a number 0 to 23
 *   HH    - hour as a number 01 to 23
 *   m     - minute as a number 0 to 59
 *   mm    - minute as a number 00 to 59
 *   s     - seconds as a number 0 to 59
 *   ss    - seconds as a number 00 to 59
 *   a     - AM or PM
 */
function fnDateUtilToString(poDate, psMask) {
  var sDate;
  var sTemp1;
  var sTemp2;
  if (fnObjUtilIsNull(poDate)) {
    return "";
  }

  sDate = psMask;

  sTemp1  = poDate.getMonth() - (- 1);
  sTemp2  = fnDateUtilTwoPlaces(sTemp1);
  sDate   = fnStrUtilReplace(sDate,"MM",sTemp2);
  sDate   = fnStrUtilReplace(sDate,"M",sTemp1);

  sTemp1  = poDate.getDate();
  sTemp2  = fnDateUtilTwoPlaces(sTemp1);
  sDate   = fnStrUtilReplace(sDate,"dd",sTemp2);
  sDate   = fnStrUtilReplace(sDate,"d",sTemp1);
  
  sTemp1 = poDate.getFullYear();
  sDate  = fnStrUtilReplace(sDate,"yyyy",sTemp1);
  sTemp1 = (sTemp1 + "").substring(2,4);
  sDate  = fnStrUtilReplace(sDate,"yy",sTemp1);

  sTemp1  = poDate.getHours();
  sTemp2  = fnDateUtilTwoPlaces(sTemp1);
  sDate   = fnStrUtilReplace(sDate,"HH",sTemp2);
  sDate   = fnStrUtilReplace(sDate,"H",sTemp1);

  sTemp1  = poDate.getHours();
  sTemp1  = (sTemp1 <= 12 && sTemp1 > 0) ? sTemp1 : sTemp1 - 12;
  sTemp1  = sTemp1 == -12 ? 12 : sTemp1;
  sTemp2  = fnDateUtilTwoPlaces(sTemp1);
  sDate   = fnStrUtilReplace(sDate,"hh",sTemp2);
  sDate   = fnStrUtilReplace(sDate,"h",sTemp1);

  sTemp1  = poDate.getMinutes();
  sTemp2  = fnDateUtilTwoPlaces(sTemp1);
  sDate   = fnStrUtilReplace(sDate,"mm",sTemp2);
  sDate   = fnStrUtilReplace(sDate,"m",sTemp1);

  sTemp1  = poDate.getSeconds();
  sTemp2  = fnDateUtilTwoPlaces(sTemp1);
  sDate   = fnStrUtilReplace(sDate,"ss",sTemp2);
  sDate   = fnStrUtilReplace(sDate,"s",sTemp1);

  sTemp1  = poDate.getHours() < 12 ? "AM" : "PM";
  sDate   = fnStrUtilReplace(sDate,"a",sTemp1);

  return sDate;
  
}


function fnDateUtilIsAxFormat(pnDate) {
  return (new String(parseInt(pnDate))).length == 8;
}


function fnDateUtilParseFromAx(pnDate) {
  var nDate;
  var nDatePart;
  var sDatePart;

  nDate = parseFloat(pnDate);
  if (isNaN(nDate)) {
    return NaN;
  }

  nDatePart = parseInt(nDate);
  sDatePart = new String(nDatePart);
  if (sDatePart.length < 8) {
    return NaN;
  }

  // get the date parts

  var sYear = sDatePart.substring(0, 4);
  var sMonth = (new Number(sDatePart.substring(4, 6)) - 1);
  var sDate = sDatePart.substring(6, 8);

  // get the time parts
  var nTimePart;
  var sTimePart;
  var sHour;
  var sMinute;
  var sSecond;

  nTimePart  =  (nDate - nDatePart) * 1000000;
  if (isNaN(nTimePart) || nTimePart == 0) {
    sHour   = 0;
    sMinute = 0;
    sSecond = 0;
  }else {
    sTimePart = new String(nTimePart);
    sHour     = sTimePart.substring(0,2);
    sMinute   = sTimePart.substring(2,4);
    sSecond   = sTimePart.substring(4,6); 
  }
 
  return new Date(sYear, sMonth, sDate, sHour, sMinute, sSecond);

}

function fnDateUtilConvertToAx(psDateValue) {
   try {
      if ( fnStrUtilIsEmpty(fnStrUtilTrim(psDateValue)) ) {
         return "";
      }

      var oDate;
      var nDateNbr;
      
      
      // Try using the normal Javascript Date object
       nDateNbr = Date.parse(fnStrUtilTrim(psDateValue));

       if (!(isNaN(nDateNbr))) {

          oDate = new Date(nDateNbr);

          return parseFloat(  ""
                        + oDate.getFullYear() 
                        + fnDateUtilTwoPlaces(oDate.getMonth() + 1)
                        +  fnDateUtilTwoPlaces(oDate.getDate())
                        + "."
                        +  fnDateUtilTwoPlaces(oDate.getHours())
                        +  fnDateUtilTwoPlaces(oDate.getMinutes())
                        +  fnDateUtilTwoPlaces(oDate.getSeconds())
                       );
       }else {

          // try the axacore date format
          try {
             if ( fnDateUtilIsAxFormat(psDateValue)) {
                return fnStrUtilTrim(psDateValue);
             }
          }catch(e) {
          }
          return NaN;
       }

   }catch(e) {
     return NaN;
   }

}


function fnDateUtilTwoPlaces(pnNum) {
  return pnNum < 10 ? "0" + pnNum : pnNum + "";
}

function fnDateUtilIsDate(psDate) {
  var d;
  try {
      // try the javascript date
      d = new Date(psDate);
      if (!isNaN(d)) {
         return true;
      }
      // try the axacore format
      return fnDateUtilIsAxFormat(psDateValue);
  } catch (e) { 
    return false;
  }
}

//------------------------------------
// Error Utility functions.
//------------------------------------

function fnErrUtilGetErrMsg(poError) {
  return "Error " + poError.number + ": " + poError.description;
}

function fnErrUtilAlertError(poError) {
  if (!fnObjUtilIsNull(poError)) {
    alert(fnErrUtilGetErrMsg(poError));
  }
}
//------------------------------------
// Generic utility objects.
//------------------------------------

  // object to access window frames
  function fnGOMakeArrayObject() {
    this.length = 6;
    this.nNumItems = 0;
    this.aoItems = new Array();
    this.fnAddItem = new Function("poNewItem","this.aoItems[this.nNumItems++] = poNewItem;");
    this.fnGetItem = new Function("nIndex","return this.aoItems[nIndex]");
    this.fnGetNumItems = new Function("return this.nNumItems");
    this.fnReset = new Function("this.nNumItems = 0; this.aoItems = new Array();");
  }

  function fnGOMakeSingleStateMachine() {
    var sTemp;

    this.length = 5;
    this.nState = "positive";
    this.nStateOld = "positive";
    this.fnGetState = new Function("return this.nState");
    this.fnReset = new Function("this.State=this.StateOld='positive'");

    sTemp = "this.nStateOld = this.nState;" +
            "if (this.nState == 'positive') {" +
            "     this.nState = 'negative'; " +
            "} else { " +
            "  this.nState = 'positive';" +
            "}";
    this.fnToggleState = new Function(sTemp);
  }

  function fnGOMakeDualStateMachine() {
    var sTemp;

    this.length = 9;
    this.nStateX = "positive";
    this.nStateXOld = "positive";
    this.nStateY = "positive";
    this.nStateYOld = "positive";
    this.fnGetStateX = new Function("return this.nStateX");
    this.fnGetStateY = new Function("return this.nStateY");
    this.fnReset = new Function("this.StateX=this.StateY=this.StateXOld=this.StateYOld='positive'");

    sTemp = "this.nStateXOld = this.nStateX;" +
            "if (this.nStateX == 'positive') {" +
            "     this.nStateX = 'negative'; " +
            "} else { " +
            "  this.nStateX = 'positive';" +
            "}";
    this.fnToggleStateX = new Function(sTemp);

    sTemp = "this.nStateYOld = this.nStateY;" +
            "if (this.nStateY == 'positive') {" +
            "     this.nStateY = 'negative';" +
            "} else { " +
            "  this.nStateY = 'positive';" +
            "}";
    this.fnToggleStateY = new Function(sTemp);
  }

//------------------------------------
// HTML hilighting functions.
//------------------------------------

  function fnHilightInitVars() {
  }

  function fnHLHilightButtonBorder(poButton,psColor,pnPixelWidth) {
    try {
      poButton.hlOldBorder = poButton.style.border;
      poButton.style.borderColor = psColor;
      poButton.style.borderWidth = pnPixelWidth;
      poButton.style.borderStyle = "solid";
    } catch (e) {
      throw e;
    }
  }
  function fnHLUnHilightButtonBorder(poButton) {
    try {
      poButton.style.border = poButton.hlOldBorder;
    } catch (e) {
      throw e;
    }
  }

  function fnHLHilightElement(poElement,psBorderColor,psBackgroundColor) {
    try {
      poElement.hlOldBorderColor = poElement.style.borderColor;
      poElement.hlOldBackgroundColor = poElement.style.backgroundColor;
      poElement.style.borderColor = psBorderColor;
      poElement.style.backgroundColor = psBackgroundColor;
    } catch (e) {
      throw e;
    }
  }

  function fnHLUnHilightElement(poElement) {
    try {
      poElement.style.borderColor = poElement.hlOldBorderColor;
      poElement.style.backgroundColor = poElement.hlOldBackgroundColor;
    } catch (e) {
      throw e;
    }
  }


//------------------------------------
// Http Utility functions.
//------------------------------------

/**
 *  This is a server-side function that returns the absolute url up to the directory name passed in
 *  -> fnHtmlUtilGetUrlPrefix("trxAssembler") on the processing website
 *     will return http://processing.xxx.potami.com/tools/trxAssembler
 */
function fnHtmlUtilGetUrlPrefix(psDirName) {
  var sUrl;
  var oRegExp;
   
  sUrl    = "http://" + Request.ServerVariables("SERVER_NAME") + ":" + Request.ServerVariables("SERVER_PORT") + 
            Request.ServerVariables("PATH_INFO");
  oRegExp = new RegExp(psDirName + ".*$","gi");
  sUrl    = sUrl.replace(oRegExp,psDirName);
    
  return sUrl;
}
  
/**
 *  This is a server-side function that returns the absolute path up to the directory name passed in
 *  -> fnHtmlUtilGetPathPrefix("trxAssembler") on the processing website
 *     will return c:\potami\internet\data\com.potami.xxx.processing.www\tools\trxAssembler
 */     
function fnHtmlUtilGetPathPrefix(psDirName) {
  var sPath;
  var oRegExp;
   
  sPath   = Server.MapPath(Request.ServerVariables("PATH_INFO"));
  oRegExp = new RegExp(psDirName + ".*$","gi");
  sPath   = sPath.replace(oRegExp,psDirName);
    
  return sPath;
}

function fnValidateHttpPostRequest(pXmlHttp){
	if (pXmlHttp.status != 200 )
	{
		throw new Error(pXmlHttp.status, pXmlHttp.responseText);
	} else { 
		return pXmlHttp.responseText;
	}
}

function fnHtmlUtilHttpPostRequestAsync(psUrl,psPostData,pbServerSide) {
  var oXMLHTTP;

  if (pbServerSide == true) {
    oXMLHTTP = fnObjUtilCreateObject("MSXML2.ServerXMLHttp");
  } else {
    oXMLHTTP = fnObjUtilCreateObject("Microsoft.XMLHTTP");
  }

  oXMLHTTP.open("POST", psUrl , true);
  oXMLHTTP.send(psPostData);

  return oXMLHTTP;
}

/**
 * @return the XMLHTTP object used to do the request
 */
function fnHtmlUtilHttpPostRequest(psUrl,psPostData,pbServerSide) {
  var oXMLHTTP;
  var asRet = new Array();

  if (pbServerSide == true) {
    oXMLHTTP = fnObjUtilCreateObject("MSXML2.ServerXMLHttp");
  } else {
    oXMLHTTP = fnObjUtilCreateObject("Microsoft.XMLHTTP");
  }

  //alert();
  oXMLHTTP.open("POST", psUrl , false);
  //alert();
  oXMLHTTP.send(psPostData);
  //alert();

  return oXMLHTTP;
}

function fnHtmlUtilAppendQueryStringData(psUrl,psName,psValue,pbIsFirstPair) {
   var sUrl = psUrl;
   if (pbIsFirstPair) {
     sUrl += "?";
   }
   sUrl += psName + "=" + escape(psValue) + "&";
   return sUrl;
}

/**
 * Synchronously navigates poDocument to psNewUrl
 * @throws Error when poDocument is null
 */
function fnHtmlUtilSyncNavigateFromString(psHtml,poDocument) {
   if (fnObjUtilIsNull(poDocument)) {
      throw new Error("poDocument is null; cannot navigate");
   }
   poDocument.open("text/html");
   poDocument.write(psHtml);
   poDocument.close();
}


/**
 * Synchronously navigates poDocument to psNewUrl
 */
function fnHtmlUtilSyncNavigate(psNewUrl,poDocument) {
   var oXMLHTTP;

   // TODO make sure all objects have loaded

   oXMLHTTP = fnObjUtilCreateObject("Microsoft.XMLHTTP");
   oXMLHTTP.open("GET",psNewUrl,false);
   oXMLHTTP.send();
   fnHtmlUtilSyncNavigateFromString(oXMLHTTP.responseText,poDocument);
}

/**
 * This function creates an html option list from
 * an xml structure like:
 * <#some node#>
 *   <#psNodeName# #psDisplayAtt#="" #psIdAtt#=""/>
 *   ........
 * </#some node#>
 * @param poXmlDoc      the xml doc
 * @param psNodeName     the nodename to iterate through
 * @param psaDisplayAtts an array of attributes to be hyphenated for display
 * @param psDisplayAtt2 the attribute name for the second half of the display
 * @param psValueAtt    the attribute name for the value of the droplist node
 */
function fnHtmlUtilGetOptionListFromXml(poXmlDoc,psNodeName,psaDisplayAtts,psValueAtt) {
  var sOptionList;
  var oOptionEls;
  var oOptionEl;
  var sDisplay;
  var i,j;

  if (fnObjUtilIsNull(poXmlDoc) ||
      fnStrUtilIsEmpty(psNodeName) ||
      fnObjUtilIsNull(psaDisplayAtts) ||
      fnStrUtilIsEmpty(psValueAtt)) {
    return "";
  }

  sOptionList = "";
  oOptionEls = poXmlDoc.selectNodes(".//" + psNodeName);

  if (fnObjUtilIsNull(oOptionEls) || oOptionEls.length <= 0) {
    return "";
  }
  for (i=0; i < oOptionEls.length; i++) {
    oOptionEl = oOptionEls.item(i);
    sDisplay = "";
    for (j = 0; j < psaDisplayAtts.length; j++) {
      if (j != 0) {
        sDisplay += " - ";
      }
      sDisplay += oOptionEl.getAttribute(psaDisplayAtts[j]);
    }
    sOptionList += "<option value=\"" + oOptionEl.getAttribute(psValueAtt) + "\">" +
                     sDisplay +
                   "</option>";
  }
  return sOptionList;
}

/**
 * This function appends options to a droplist
 * @param poSelect  the select object
 * @param psValue   the value of the option
 * @param psDisplay how the option should be displayed
 */
function fnHtmlUtilAddOption(poSelect,psValue,psDisplay) {
  var oOption;
  if (fnObjUtilIsNull(poSelect)) {
    return;
  }
  oOption = document.createElement("option");
  oOption.value = psValue;
  oOption.innerText = psDisplay;

  poSelect.appendChild(oOption);
}

/**
 * Clears all the options from a droplist.
 * @param poSelect the droplist to clear.
 */
function fnHtmlUtilClearOptions(poSelect) {
  if (!fnObjUtilIsNull(poSelect)) {
    poSelect.innerHTML = "";
  }
}

function fnHtmlUtilGetCharFromEvent(poEvent) {
    var nCode;
    var sChar;
    var bShift;

    nCode  = poEvent.keyCode;
    bShift = poEvent.shiftKey;

    // handle number pad
    if (nCode >= 96 && nCode <= 105) {
        nCode -= 48;
    } 

    // handle ctrl codes
    if (poEvent.ctrlKey) {
        if (nCode >= 65 && nCode <= 90) {
            return String.fromCharCode(nCode - 64);
        }

        switch (nCode) {
        case 219:
            return String.fromCharCode(27);
        case 220:
            return String.fromCharCode(28);
        case 221:
            return String.fromCharCode(29);
        case 54:
            return String.fromCharCode(30);
        case 189:
            return String.fromCharCode(31);
        default: 
            return "";
        }

    }

    // handle alpha numerics
    if ((nCode >= 65 && nCode <= 90) ||
        (nCode >= 48 && nCode <= 57 && !bShift)) {

        sChar = unescape("%" + nCode.toString(16))
        if (bShift) {
           sChar = sChar.toUpperCase();
        } else {
           sChar = sChar.toLowerCase();
        } 
        return sChar;
    }

    // handle others
    switch (nCode) {
    case 9:                // tab key
        return String.fromCharCode(9);
    case 13:               // carriage Return
        return String.fromCharCode(13);
    case 32:
        return " ";

    case 46:                // delete key
        return String.fromCharCode(127);

    case 48:
        return ")";
    case 49:
        return "!";
    case 50:
        return "@";
    case 51:
        return "#";  
    case 52:
        return "$";
    case 53:
        return "%";
    case 54:
        return "^";
    case 55:
        return "&";
    case 56:
        return "*";
    case 57:
        return "(";

    case 106: 
        return "*";
    case 107:
        return "+";

    case 109:
        return "-";
    case 110:
        return ".";
    case 111:
        return "/";

    case 186:
        return !bShift ? ";" : ":";
    case 187:
        return !bShift ? "=" : "+";
    case 188:
        return !bShift ? "," : "<";
    case 189:
        return !bShift ? "-" : "_";
    case 190:
        return !bShift ? "." : ">";
    case 191:
        return !bShift ? "/" : "?";
    case 192:
        return !bShift ? "`" : "~";

    case 219:
        return !bShift ? "[" : "{";
    case 220:
        return !bShift ? "\\" : "|";
    case 221:
        return !bShift ? "]" : "}";
    case 222:
        return !bShift ? "'" : '"';

    default:
        return "";
    }
}

function fnHtmlUtilGetSelectionLength(poWin) {
   var oTextRange;

   oTextRange = poWin.document.selection.createRange();
   return oTextRange.text.length;
}

function fnHtmlUtilHideCaret(poWin) {
   poWin.document.selection.empty();
}

function fnHtmlUtilGetCaret(poWin, poEl) {
   var oTextRange;
   var nPos;

   oTextRange = poWin.document.selection.createRange();
   oTextRange.text = "*^*^*^*" + oTextRange.text;
   nPos = poEl.value.indexOf("*^*^*^*");   
   oTextRange.moveStart("character",-7);
   oTextRange.text = oTextRange.text.substr(7, oTextRange.text.length - 7);

   return nPos;
}

function fnHtmlUtilPlaceCaret(poEl, pnPos, pnLength) {
    var oTextRange;

    poEl.focus();
    oTextRange = poEl.createTextRange();
    oTextRange.moveStart("character", pnPos);
    oTextRange.setEndPoint("EndToStart", oTextRange);
    oTextRange.moveEnd("character", pnLength);
    oTextRange.select();
}


//------------------------------------
// Logging functionality
//------------------------------------

//---------------------------
// Debugging and Logging Functions
//---------------------------
/*
var gnGlobalLoggingLevel      = 15;
//var gnGlobalLoggingLevel      = 0;
var gnLocalLoggingLevel       = 0;

var gsLogFilePath = "E:\\temp\\log.txt";

var LOG_UTIL_LOG_ALL    = 15;
var LOG_UTIL_LOG_DEBUG  = 1;
var LOG_UTIL_LOG_INFO   = 2;
var LOG_UTIL_LOG_WARN   = 4;
var LOG_UTIL_LOG_ERROR  = 8;

function fnLogUtilSetLocalLoggingLevel(pnLoggingLevel) {
   gnLocalLoggingLevel = pnLoggingLevel;
 }

function fnLogUtilIsLoggingOn(pnLoggingLevel) {
  if (((gnGlobalLoggingLevel & pnLoggingLevel) != 0) ||
      ((gnLocalLoggingLevel & pnLoggingLevel) != 0)) {
    return true;
  }
  return false;
}

function fnLogUtilShowMsg(psPrefix,psText,poCaller)
{
  var sFuncName;
  var sMsg;
  var sText;
  var sPrefix;
  var nTemp;
  var oCaller;
  var oFso;
  var oFile;

  if (!fnObjUtilIsNull(poCaller)) {
    sFuncName = poCaller.toString();
    nTemp = sFuncName.indexOf("(");
    sFuncName = sFuncName.substring(0,nTemp);
    nTemp = sFuncName.indexOf(" ");
    sFuncName = sFuncName.substring(nTemp,sFuncName.length);
  } else {
    sFuncName = "undefined or at top level";
  }
  sPrefix = fnStrUtilEvl(psPrefix,"Message");

  sText = fnStrUtilEvl(psText,"");

  sMsg = "LOGGING EVENT\n" +
         "  Type: " + sPrefix + "\n" +
         "  Source: " + sFuncName + "\n" +
         "  Message: " + sText + "\n";
  try {
    //Response.Write(sMsg + "<br>");
    //oFso = fnObjUtilCreateObject("Scripting.FileSystemObject");
    // open log file for appending (create new file if one doesn't exist
    //oFile = oFso.OpenTextFile(gsLogFilePath,8,true);
    //oFile.Write(sMsg);
    //oFile.Close();
  } catch (e) {
    alert(e.description);
    alert(sMsg);
  }
}


function fnLogUtilDebug(psText) {
  if (fnLogUtilIsLoggingOn(LOG_UTIL_LOG_DEBUG)) {
    fnLogUtilShowMsg("debug",psText,fnLogUtilDebug.caller);
  }
}
function fnLogUtilInfo(psText) {
  if (fnLogUtilIsLoggingOn(LOG_UTIL_LOG_INFO)) {
    fnLogUtilShowMsg("info",psText,fnLogUtilInfo.caller);
  }
}

function fnLogUtilWarn(psText) {
  if (fnLogUtilIsLoggingOn(LOG_UTIL_LOG_WARN)) {
    fnLogUtilShowMsg("warn",psText,fnLogUtilWarn.caller);
  }
}

function fnLogUtilError(psText) {
  if (fnLogUtilIsLoggingOn(LOG_UTIL_LOG_ERROR)) {
    fnLogUtilShowMsg("error",psText,fnLogUtilError.caller);
  }
}

function fnLogNow(psLogText)
{
  var d = new Date();
  var s ="";
  s += d.getSeconds() + "." + d.getMilliseconds() + " " + psLogText;
  log(s);
}

function fnLogUtilLog(sLogText_)
{
      if (window.top.fnLogUtilLog)
         window.top.fnLogUtilLog(sLogText_);
}

function fnLogUtilShow()
{
  if (window.top.fnLogUtilShow)
    window.top.fnLogUtilShow();
}

function fnLogUtilClear()
{
  if (window.top.fnLogUtilClear)
    window.top.fnLogUtilClear();
}
*/

//------------------------------------
// Number Utility functions.
//------------------------------------

function fnNumUtilToNumber(poObj) {
   return poObj - 0;
}

function fnNumUtilPlus(nNum1,nNum2) {
   return nNum1 - (- nNum2);
}

function fnNumUtilIsNumber(poObj) {
  var nNumber;

  if (fnObjUtilIsNull(poObj) || fnStrUtilIsEmpty(poObj)) {
    return false;
  }
  nNumber = new Number(poObj);
  if (nNumber.toString() == Number.NaN.toString()) {
    return false;
  }
  return true;
}

function fnNumUtilAbsValue(pnNumber) {
  if (!fnNumUtilIsNumber(pnNumber)) {
    return Number.NaN;
  }
  if (pnNumber < 0) {
    return pnNumber * -1;
  }
  return pnNumber;
}

/**
 *  @return the number (floating point or otherwise) as a truncated integer
 *   or Number.NaN if pNumber is not a number
 */
function fnNumUtilToInt(pnNumber) {
  return Math.floor(pnNumber); // new Number(pnNumber).toFixed(0); -- this rounds instead of truncates
}

function fnNumUtilIsInRange(pnNumber,pnStart,pnEnd) {
  if ( (!fnNumUtilIsNumber(pnNumber)) || 
       (!fnNumUtilIsNumber(pnStart))  ||
       (!fnNumUtilIsNumber(pnEnd)) ) {
    return false;
  }
  if ( (pnNumber -0) < (pnStart-0) ) {
      return false;
  }
  if ( (pnNumber -0) > (pnEnd-0) ) {
      return false;
  }
  return true;
}

function fnNumUtilHexCharToDecVal(psChar) {
   switch(psChar.toString().toUpperCase().toString()) {
       case "0":
           return 0;
       case "1":
           return 1;
       case "2":
           return 2;
       case "3":
           return 3;
       case "4":
           return 4;
       case "5":
           return 5;
       case "6":
           return 6;
       case "7":
           return 7;
       case "8":
           return 8;
       case "9":
           return 9;
       case "A":
           return 10;
       case "B":
           return 11;
       case "C":
           return 12;
       case "D":
           return 13;
       case "E":
           return 14;
       case "F":
           return 15;
    }
}

function fnNumUtilHexToDec(psValue) {
    var nVal = 0;
    var nMult;
    for (var i=0; i < psValue.length-1; i++) {
        nMult = 16;
        for (j=2; j < psValue.length - i; j++) {
            nMult = nMult*16;
        }
        nVal += nMult*fnNumUtilHexCharToDecVal(psValue.substr(i,1));
    }
    nVal = nVal - - fnNumUtilHexCharToDecVal(psValue.substr(psValue.length-1,1));
    return nVal;
}

//------------------------------------
// Object Utility functions.
//------------------------------------

/**
 * Returns an automation object created with new ActiveXObject or Server.CreateObject
 * based on where this script is run from (server or client).
 * @param psProgId the identification of the automation object to create
 * @return a reference to the automation object identified by the psProgId parameter
 */
function fnObjUtilCreateObject(psProgId) {
  try {
    // try to use the Server object (i.e. assume running at the server)
    return Server.CreateObject(psProgId);
  } catch (e) {
    // if can't use the Server object must be running on the client
    return new ActiveXObject(psProgId);
  }
}

function fnObjUtilIsNull(poObj) {
  if (!poObj || poObj == null) {
    return true;
  }
  return false;
}

/**
 * @return: true if the object is empty, false if not
 */
function fnObjUtilIsObjectEmpty(oObject_)
{
  return (!oObject_) || (oObject_ == "");
}

/**
 * @return: the oNullValue_  if the object is null, the object if not
 */
function fnObjUtilNvl(oObject_, oNullValue_)
{
  return (!oObject_)?  oNullValue_: oObject_;
}

/**
 * @return: oEmptyValue_  if the object is empty, the object if not
 */
function fnObjUtilEvl(oObject_, oEmptyValue_)
{
  return (fnObjUtilIsObjectEmpty(oObject_))? oEmptyValue_: oObject_;
}

function fnObjUtilCalcAbsoluteLeft(oObj_) {
    // Find the element's offsetLeft relative to the BODY tag.
    var pos = oObj_.offsetLeft;
    var objParent = oObj_.offsetParent;
    while (objParent.tagName.toUpperCase() != "BODY") {
      pos   += objParent.offsetLeft;
      objParent = objParent.offsetParent;
    }
    return pos;
}

function fnObjUtilCalcAbsoluteTop(oObj_) {
    // Find the element's offsetTop relative to the BODY tag.
    var pos = oObj_.offsetTop;
    var objParent = oObj_.offsetParent;
    while (objParent.tagName.toUpperCase() != "BODY") {
      pos   += objParent.offsetTop;
      objParent = objParent.offsetParent;
    }
    return pos;
}

//------------------------------------
// Simple Queue object.
//------------------------------------

    function Queue(pnMaxElements) {

        this.nMaxElements = pnMaxElements;
        this.oElements    = new Array(this.nMaxElements);
        this.nNumElements = 0;
        this.nFirstIndex  = 0;
        this.nLastIndex   = 0;

        this.fnEnqueue = function(poElement) {
            if (this.fnIsFull()) {
                throw new Error(0, "Cannot enqueue to a full queue");
            }
            this.nNumElements++;
            this.oElements[this.nLastIndex] = poElement;
            this.nLastIndex = (this.nLastIndex - (-1)) % this.nMaxElements;   
        }

        this.fnDequeue = function() {
            var oEl;

            if (this.fnIsEmpty()) {
                return null;
            }
            this.nNumElements--;
            oEl = this.oElements[this.nFirstIndex];
            this.oElements[this.nFirstIndex] = null;
            this.nFirstIndex = (this.nFirstIndex - (-1)) % this.nMaxElements;   
            return oEl;
        }

        this.fnGetNumElements = function() {
            return this.nNumElements;
        }

        this.fnIsFull = function() {
            return this.nNumElements == this.nMaxElements;
        }

        this.fnIsEmpty = function() {
            return this.nNumElements == 0;
        }

    }
//------------------------------------
//  Provides a window with a selector box (dragger).
//  Assumes that the container has the position style attribute set (to relative or absolute)
//------------------------------------

function SelectorBox(
             poContainer,
             psBorder,
             pnZIndex,
             pfnBoxRedrawCallback,
             pfnBoxCompleteCallback) {
   
    this.getLeft = function() {
        return this.x1;
    }

    this.getTop = function() {
        return this.y1;
    }

    this.getWidth = function() {
        return this.x2 - this.x1;
    }

    this.getHeight = function() {
        return this.y2 - this.y1;
    }

    this.getX1 = function() {
        return this.x1;
    }

    this.getY1 = function() {
        return this.y1;
    }

    this.getX2 = function() {
        return this.x2;
    }

    this.getY2 = function() {
        return this.y2;
    }

    this.getRelativeEventX = function(poThis,poEvent) {

        if (poThis.oContainer.style.position.toUpperCase() == "ABSOLUTE") {
            return poEvent.x - poThis.oContainer.style.pixelLeft -(-poThis.oContainer.scrollLeft);
        } else {
            return poEvent.x -(-poThis.oContainer.scrollLeft);
        }   

    }

    this.getRelativeEventY = function(poThis,poEvent) {
        if (poThis.oContainer.style.position.toUpperCase() == "ABSOLUTE") {
            return poEvent.y - poThis.oContainer.style.pixelTop -(-poThis.oContainer.scrollTop);
        } else {
            return poEvent.y -(-poThis.oContainer.scrollTop);
        }   
    }

    this.redrawBox = function(poThis) {
        var oThis = poThis;
        if (oThis.bBoxShowing == false) {
            oThis.xBox.style.display = "none";
            return;
        } 
        oThis.xBox.style.pixelLeft     = oThis.getX1();
        oThis.xBox.style.pixelTop      = oThis.getY1();
        oThis.xBox.style.pixelWidth    = oThis.getX2() - oThis.getX1();
        oThis.xBox.style.pixelHeight   = oThis.getY2() - oThis.getY1();;
        oThis.xBox.style.display       = "";

        if (oThis.fnBoxRedrawCallback != null) {
            oThis.fnBoxRedrawCallback(oThis);
        }
    }

    this.onMouseMove = function() {
        var nX;
        var nY;
        var oThis;

        try {
            oThis = window.event.srcElement;

            while (fnObjUtilIsNull(oThis.xSelectorBox)) {
                     oThis = oThis.parentElement;                            
            }

            oThis = oThis.xSelectorBox;

            if (fnObjUtilIsNull(oThis)) {
                return;
            }
       
            nX = oThis.getRelativeEventX(oThis,window.event);
            nY = oThis.getRelativeEventY(oThis,window.event);

            if (nX >= oThis.pinX) {
                oThis.x1 = oThis.pinX;
                oThis.x2 = nX;
            } else {
                oThis.x1 = nX;
                oThis.x2 = oThis.pinX;
            }
 
            if (nY >= oThis.pinY) {
                oThis.y1 = oThis.pinY;
                oThis.y2 = nY;
            } else {
                oThis.y1 = nY;
                oThis.y2 = oThis.pinY;
            }
         
            oThis.redrawBox(oThis);
        
            if (oThis.fnOriginalMouseMove != null) {
                oThis.fnOriginalMouseMove();
            }

        } catch (e) {
//             throw new Error(e.number,"selector box onMouseMove error: " + e.description);
        } 
    }

    this.onMouseDown = function() {
        if (window.event.button != 1) {
            return;
        }

        var oThis = window.event.srcElement;  
        while (oThis.xSelectorBox == null) {
             oThis = oThis.parentElement;            
        }
        oThis = oThis.xSelectorBox;
        oThis.pinX = oThis.getRelativeEventX(oThis,window.event);
        oThis.x1   = oThis.pinX;
        oThis.x2   = oThis.pinX - (-1);
        oThis.pinY = oThis.getRelativeEventY(oThis,window.event);
        oThis.y1   = oThis.pinY;
        oThis.y2   = oThis.pinY - (-1);

        // make sure not on scrollbar
//window.status = oThis.oContainer.scrollHeight + "|" + oThis.oContainer.style.pixelHeight + "&" + 
//                oThis.oContainer.scrollWidth + "|" + oThis.oContainer.style.pixelWidth;
//window.status = document.body.scrollTop + "|" + oThis.oContainer.scrollTop;
        if ( ( ((oThis.oContainer.style.pixelHeight -(-oThis.oContainer.scrollTop) - oThis.pinY) < 20) ) ||
             ( ((oThis.oContainer.style.pixelWidth -(-oThis.oContainer.scrollLeft) - oThis.pinX) < 20) ) ) {
            return;
        }

        oThis.bBoxShowing = true;

        if (oThis.fnOriginalMouseDown != null) {
          oThis.fnOriginalMouseDown();
        }
    }
   
    this.onMouseUp = function() {
            if (window.event.button != 1) {
                return;
            }

        var oThis = window.event.srcElement;  
        while (oThis.xSelectorBox == null) {
             oThis = oThis.parentElement;            
        }
        oThis = oThis.xSelectorBox;

        if (oThis.bBoxShowing == false) {
            return;
        }

        oThis.bBoxShowing = false;
        oThis.redrawBox(oThis);

        if (oThis.fnBoxCompleteCallback != null) {
            oThis.fnBoxCompleteCallback(oThis);
        }
 
        if (oThis.fnOriginalMouseUp != null) {
          oThis.fnOriginalMouseUp();
        }
    }


    this.setHandlers = function(pfnBoxRedrawCallback,pfnBoxCompleteCallback) {
        this.fnBoxCompleteCallback    = pfnBoxCompleteCallback;
        this.fnBoxRedrawCallback      = pfnBoxRedrawCallback;
    }

    this.returnFalse = function() {
        window.event.cancelBubble = true;
        return false;
    }

    var oBox;

    this.oContainer               = poContainer;

    this.pinX                     = 0;
    this.pinY                     = 0;
    this.x1                       = 0;
    this.y1                       = 0;
    this.x2                       = 0;
    this.y2                       = 0;

    this.oContainer.onselectstart = this.returnFalse;

    oBox                          = document.createElement("div");
    oBox.style.fontSize           = 0;
    oBox.style.innerText          = "";
    oBox.style.border             = psBorder;
    oBox.style.zIndex             = pnZIndex;
    oBox.style.display            = "none";
    oBox.style.position           = "absolute";
    this.xBox                     = oBox;
    this.bBoxShowing              = false;
    this.oContainer.appendChild(oBox);   
       
    this.setHandlers(pfnBoxRedrawCallback,pfnBoxCompleteCallback);
    this.oContainer.xSelectorBox  = this;    

    this.fnOriginalMouseMove      = this.oContainer.onmousemove;
    this.fnOriginalMouseDown      = this.oContainer.onmousedown;
    this.fnOriginalMouseUp        = this.oContainer.onmouseup;

    this.oContainer.onmousemove   = this.onMouseMove;
    this.oContainer.onmousedown   = this.onMouseDown;
    this.oContainer.onmouseup     = this.onMouseUp;   
}
  

//------------------------------------
// String Utility functions.
//------------------------------------

var QQ = String.fromCharCode(34); // double quote char
var LF = String.fromCharCode(10);
var CRLF = String.fromCharCode(13) + LF;

function fnStrUtilToArray(psList, psSplitChar, pbCutOffEnd) {
  var sList;

  if (fnStrUtilIsEmpty(psList)) {
    return new Array();
  }
 
  sList = psList;
  
  if (fnStrUtilIsTrue(pbCutOffEnd)) {
    if (sList.substr(sList.length - psSplitChar.length, psSplitChar.length) == psSplitChar) {
      sList = sList.substr(0, sList.length - psSplitChar.length);
    }
  }

  return sList.split(psSplitChar);

}


function fnStrUtilCompare(psObj1, psObj2) {
  var sObj1 = new String(psObj1);
  var sObj2 = new String(psObj2);
  if (sObj1.toString() == sObj2.toString()) {
    return true;
  } else {
    return false;
  }
}

function fnStrUtilGetResultSetParam(poResultSet,psPropertyName) {
  var sRet;
  sRet = new String(poResultSet(psPropertyName)) + "";
  return sRet;
}

function fnStrUtilIsTrue(psValue) {
   var c;

   if (fnStrUtilIsEmpty(psValue)) {
      return false;
   }

   c = psValue.toString().substring(0,1);

   return (c == 'Y') || (c == 'y') || (c == 'T') || (c == 't') || (c == '1');
}

function fnStrUtilQQ(psStr) {
  return QQ + psStr + QQ;
}

function fnStrUtilGetRequestParam(psParamName) {
  return fnStrUtilParseRequest(Request(psParamName));
}

function fnStrUtilParseRequest(psData) {
  var sData = new String(psData);
  if (fnObjUtilIsNull(psData)) {
    return "";
  }
  return sData;
}

function fnStrUtilIsEmpty(psStr) {
  if (fnObjUtilIsNull(psStr) || psStr == "" ||
      new String(psStr) == "undefined") {
    return true;
  }
  return false;
}

function fnStrUtilEvl(psStrIn, psEmptyReturn) {
  if (fnStrUtilIsEmpty(psStrIn)) {
    return psEmptyReturn;
  }else {
    return psStrIn;
  }
}

function fnStrUtilReplace(psString, psFind, psReplace) {
  var sStr;
  var oRegExp;

  sStr = psString;
  if (fnStrUtilIsEmpty(sStr)) {
    return sStr;
  }
   oRegExp = new RegExp(psFind,"g");

   sStr = sStr.replace(oRegExp,psReplace);
   return sStr;
}


/**
 * Right pads the string with psPadStr
 */
function fnStrUtilRPad(psString, pnLen, psPadString) {
  var sStr = psString;
  var nCnt;

  if (fnStrUtilIsEmpty(sStr)) {
    return sStr;
  }

  nCnt = pnLen - sStr.length;
  for(i=0; i < nCnt; i++) {
    sStr = sStr + psPadString;
  }
  return sStr;
}

/**
 * Left pads the string with psPadStr
 */
function fnStrUtilLPad(psString, pnLen, psPadString) {
  var sStr = psString;
  var nCnt;

  if (fnStrUtilIsEmpty(sStr)) {
    return sStr;
  }

  nCnt = pnLen - sStr.length;
  for(i=0; i < nCnt; i++)
  {
    sStr = psPadString + sStr;
  }
  return sStr;
}

/**
 * Changes text like fontFamily to FONT-FAMILY
 */
function fnStrUtilMixedCaseToDashedUpperCase(psIn)
{
  var sOut;
  var oRegExp;

  oRegExp = new RegExp("([A-Z])","g");
  sOut = psIn.replace(oRegExp,"-$1");

  return sOut.toUpperCase();
}

/**
 * Changes text like FONT-FAMILY to fontFamily
 */
function fnStrUtilDashedUpperCaseToMixedCase(psIn)
{
  var sOut = psIn.toLowerCase();
  var oRegExp;
  var nDashPos;

  oRegExp = new RegExp("(-)","g");

  while ((nDashPos = sOut.search(oRegExp)) > 0) {
    sOut = sOut.substring(0,nDashPos) +
           sOut.charAt(nDashPos - (- 1)).toUpperCase() +
           sOut.substring(nDashPos - (- 2),sOut.length);

  }

  return sOut;
}


/**
 * calculates the max string length of an array of strings.
 */
function fnStrUtilCalcMaxLen(psArray)
{
  var maxLen = 0;
  if (psArray)
  {
    var i=0;
    var currLen = 0;
    for (i=0; i< psArray.length; i++)
    {
      currLen = psArray[i].length;
      if (currLen > maxLen)
      {
        maxLen = currLen;
      }
    }
  }
  return maxLen;
}

/**
 * Trims all leading and trailing spaces from the string
 */
function fnStrUtilTrim(psStr)
{
  return fnStrUtilLtrim(fnStrUtilRtrim(psStr));
}

/**
 * Trims all leading spaces from the string
 */
function fnStrUtilLtrim(psStr)
{
  var sStr = psStr;
  if (sStr)
  {
    while (sStr.length > 0 && sStr.charAt(0) == ' ')
    {
       sStr = sStr.substring(1);
    }
  }
  return sStr;
}

/**
 * Trims all trailing spaces from the string
 */
function fnStrUtilRtrim(psStr)
{
  var sStr = psStr;
  if (sStr)
  {
    while (sStr.length > 0 && sStr.charAt(sStr.length-1) == ' ')
    {
       sStr = sStr.substring(0,sStr.length-1);
    }
  }
  return sStr;
}

function fnStrUtilSplitNameValue(psNameValue,psSplitChar) {
  var ret = new Array(2);
  if (psNameValue) {
    var pos = psNameValue.indexOf(psSplitChar);
    if (pos > 0) {
      ret[0] = psNameValue.substring(0,pos);
      if ( (psNameValue.length-1) > pos) {
        ret[1] = psNameValue.substring(pos-(-1),psNameValue.length);
      } else {
        ret[1] = "";
      }
    } else {
      ret[0] = psNameValue;
      ret[1] = "";
    }
  } else {
    ret[0] = "";
    ret[1] = "";   
  }
  return ret;
}

//------------------------------------
// XML Utility functions.
//------------------------------------

var PROGID_XMLDOM_CLIENT    = "Microsoft.XMLDOM";
var PROGID_XMLDOM_SERVER    = "MSXML2.DOMDocument";
var PROGID_XMLHTTP_CLIENT   = "Microsoft.XMLHTTP";
var PROGID_XMLHTTP_SERVER   = "MSXML2.ServerXMLHTTP";

function fnXmlUtilGetErrMsg(poParseErr) {
   var sErrMsg;

   sErrMsg = 
      "Error " + poParseErr.errorCode + ": " + poParseErr.reason +
      "\n src text is " + poParseErr.srcText + 
      "\n on line " + poParseErr.line + 
      "\n on character " + poParseErr.linepos;

   return sErrMsg;
}

function fnXmlUtilEscape(psInput) {
   var sResult = new String(psInput);
        
    sResult = fnStrUtilReplace(sResult, "&", "&amp;");
    sResult = fnStrUtilReplace(sResult, "\"", "&quot;");
    //sResult = fnStrUtilReplace(sResult, "\'", "&apos;");
    sResult = fnStrUtilReplace(sResult, "<", "&lt;");
    sResult = fnStrUtilReplace(sResult, ">", "&gt;");
    sResult = fnStrUtilReplace(sResult, String.fromCharCode(13),"&#13;");
    sResult = fnStrUtilReplace(sResult, String.fromCharCode(10),"&#10;");
        
    return sResult;
}
    
function fnXmlUtilUnescape(psInput) {
    var sResult = psInput;
       
    sResult = fnStrUtilReplace(sResult, "&quot;", "\"");
    //sResult = fnStrUtilReplace(sResult, "&apos;", "\'");
    sResult = fnStrUtilReplace(sResult, "&lt;", "<");
    sResult = fnStrUtilReplace(sResult, "&gt;", ">");
    sResult = fnStrUtilReplace(sResult,"&#13;", String.fromCharCode(13));
    sResult = fnStrUtilReplace(sResult,"&xd;", String.fromCharCode(13));
    sResult = fnStrUtilReplace(sResult,"&#10;", String.fromCharCode(10));
    sResult = fnStrUtilReplace(sResult,"&xa;", String.fromCharCode(10));
    sResult = fnStrUtilReplace(sResult, "&amp;", "&");
        
    return sResult;
}

function fnXmlUtilLoadXmlFromUrl(psUrl,pbIsServer) {
  var oXmlDoc;
  var oXmlHttp;
  var sXml;

  try {

   if (pbIsServer) {
     oXmlHttp = fnObjUtilCreateObject(PROGID_XMLHTTP_SERVER);
   } else {
     oXmlHttp = fnObjUtilCreateObject(PROGID_XMLHTTP_CLIENT);
   }

    oXmlHttp.open("GET",psUrl,false);
    oXmlHttp.send();
    sXml = oXmlHttp.responseText;
    oXmlDoc = fnXmlUtilLoadFromXmlString(sXml);
  } catch (e) {
     if (pbIsServer) {
       oXmlDoc = fnObjUtilCreateObject(PROGID_XMLDOM_SERVER);
     } else {
       oXmlDoc = fnObjUtilCreateObject(PROGID_XMLDOM_CLIENT);
     }
     oXmlDoc.async = false;
     oXmlDoc.validateOnParse = false;
     oXmlDoc.load(psUrl);
     fnXmlUtilValidateLoad(oXmlDoc);
  }

  return oXmlDoc;
}

function fnXmlUtilLoadFromXmlString(psXml) {
   var oXmlDoc;

   oXmlDoc = fnObjUtilCreateObject(PROGID_XMLDOM_CLIENT);
   oXmlDoc.async = false;
   oXmlDoc.validateOnParse = false;
   oXmlDoc.loadXML(psXml);

   fnXmlUtilValidateLoad(oXmlDoc);

   return oXmlDoc;
}

function fnXmlUtilValidateLoad(poXmlDoc) {
   if (poXmlDoc.parseError.errorCode != 0) {
     throw new Error(1,fnXmlUtilGetErrMsg(poXmlDoc.parseError));
   }
}

/**
 * Creates a new attribute and appends it to an xmlElement.
 * @return boolean value on the success of setting the attribute
 */
function fnXmlUtilCreateSetAttribute(poXMLRoot,poXMLElement,psName,psValue)
{
  var pNewAttr;

  pNewAttr = poXMLRoot.createAttribute(psName);
  poXMLElement.setAttributeNode(pNewAttr);
  poXMLElement.setAttribute(psName,psValue);
  return true;
}

/**
 * Creates a new xml element and appends it to poParent
 */
function fnXmlUtilCreateAppendElement(poRoot,poParent,psElementName) {
  var oNewEl;

  if (fnObjUtilIsNull(poRoot) || fnObjUtilIsNull(poParent)) {
    return null;
  }
  oNewEl = poRoot.createElement(psElementName);
  poParent.appendChild(oNewEl);
  return oNewEl;
}

/** Form Validation Routines */
function fnFormValidate(oForm) {
  var oEls;
  var oEl;
  var bHasError = false;
  try {
    oEls = oForm.elements;
    for (i=0; i<oEls.length; i++) {
      oEl = oEls[i];
      if ( (fnStrUtilIsTrue(oEl.axvr)) && (fnStrUtilIsEmpty(oEl.value)) ) {
        alert("one or more required fields are missing");
        bHasError = true;   
        break;
      } 
      if ( !fnFormValidateTypeSilent(oEl)) {
        alert("one or more required fields has invalid data");
        bHasError = true;   
        break;
      }
    }
    if (bHasError) {
      try { oEl.focus(); oEl.select(); } catch (e) {}   
      window.event.cancelBubble = true;
      window.event.returnValue = false;
      return false;  
    }
    return true;
  } catch (e) {
    alert("error validating form: " + e.description);
    window.event.cancelBubble = true;
    window.event.returnValue = false;
    return false; 
  }
}

function fnFormValidateTypeSilent(oEl,sMask) {
  if ((!oEl) || (fnStrUtilIsEmpty(oEl.axvt)) || (fnStrUtilIsEmpty(oEl.value)) ) {
    return true;
  }  
  var ndt = (oEl.axvt-0);  
  // integer type
  if ( ndt >= 30 && ndt <= 39) {
    if (!fnNumUtilIsNumber(oEl.value)) {
        return false;
    }
    if (ndt == 31) {
        oEl.value = fnNumUtilToInt(oEl.value);
    }
  }  
  // date or date time
  if (ndt >= 40 && ndt <= 41) {
      try {
        if (fnStrUtilIsEmpty(sMask)) {
          return fnDateUtilIsDate(oEl.value);
        } else {
          // TODO: implement the mask check
        }
      } catch (e) {
        return false;
      }
  }
  return true;
}

function fnFormValidateType(oEl,sMask) {
  try {
    if (!fnFormValidateTypeSilent(oEl,sMask)) {
        alert("the format of the data you entered is not valid. please re-enter.");
        try { oEl.focus(); oEl.select(); } catch (e) {}          
        window.event.cancelBubble = true;
        window.event.returnValue = false;
        return false;  
    }
  } catch (e) {
    alert("error validating field data: " + e.description);
    window.event.cancelBubble = true;
    window.event.returnValue = false;
    return false; 
  }
}

function fnLocale() {
  var loc;
  var idx;
  if( navigator.language ) {
      loc = navigator.language;
   }  else if( navigator.browserLanguage ) {
      loc = navigator.browserLanguage;
   }
   if (!fnStrUtilIsEmpty(loc)) {
     idx = loc.indexOf("-");
     if (idx > 0) {
       loc = loc.substring(0,idx+1) + loc.substring(idx+1,loc.length).toUpperCase();
     }       
   }
   return loc;
   
}



