//
// /js/ws.js.
// Client-Side Java Scripts used for the WarpSpeed front-end.
//

// "Include" other JS libraries
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/svg.js' data-path='/js'></script>");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/app.js'></script>");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/mask.js'></script>");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/layout.js'></script>");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/datetimepicker.js'></script>");

document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/ws_tree.js'></script>");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='"+cThemePath+"js/ws_tree_tv_style.js'></script>");

document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/ws_menu.js'></script>\n");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='"+cThemePath+"js/ws_menu_dd_style.js'></script>");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='"+cThemePath+"js/ws_menu_ddv_style.js'></script>");

// "Include" CSS files
document.writeln("<link href='"+cThemePath+"css/ws.css'      type='text/css' rel='stylesheet' media='screen'/>");
document.writeln("<link href='"+cThemePath+"css/cnt.css'     type='text/css' rel='stylesheet' media='screen'/>");
document.writeln("<link href='"+cThemePath+"css/btn.css'     type='text/css' rel='stylesheet' media='screen'/>");
document.writeln("<link href='"+cThemePath+"css/wsprint.css' type='text/css' rel='stylesheet' media='print'/>");

document.writeln("<script language='JavaScript1.2' type='text/javascript'>var objDialog;</script>\n");    // Write a line to the document to localize this variable to it
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/table.js'></script>\n");
document.writeln("<script language='JavaScript1.2' type='text/javascript' src='/js/wsMSC.js'></script>\n");

// Place any globally used variables here...
// Note that these values are defaults, and they may be subsequently changed in
// the calling HTML created by Webspeed!!!.
var gvDefaultButton="";
var gvFirstButton="";
var giPrevKeyCode;
var gvPrevControl;
var gvAlertActive=false;

var lDebug=true;
var cBrowser=fnSetBrowser();
var cLkpWin="top=20,left=20,width=720,height=520,toolbar=no,menubar=no,status=yes,scrollbars=yes,resizable=yes,location=no,alwaysRaised=yes";
var cMSCWin="top=20,left=20,width=900,height=620,toolbar=no,menubar=no,status=yes,scrollbars=yes,resizable=yes,location=no,alwaysRaised=yes";
var iTimer=0;
var iTimeOut=2000;
var dmOpen=false;
var dmClick=false;
var lastBtnPtr=0;
var lastMenuPtr=0;
var cDateSeq="dmy";
var cDateDel="/";
var cDateDels=".,-";
var cDateMsg="dd/mm/yyyy";
var cDateKey="dd/mm/yyyy";
var cDatePattern=/^\d{2}\/\d{2}\/\d{4}$/;
// End of globally used variables...


// Open the Lookup Window, and fire the Lookup Request.
function fnLookupOpen(lkpSrc, lkpFlds, lkpVals, retForm, retFlds, retList, lkpRunWob) {
  var winPtr=window.open(cThemePath + "/lookup.html","winLookup",cLkpWin);
  var frmlkp=window.document.frmLookup;
  lkpRunWob = (lkpRunWob == undefined || trim(lkpRunWob) == "" ? "lookp" : trim(lkpRunWob));
  frmlkp.run.value=lkpRunWob;
  frmlkp.lkpSrc.value=lkpSrc;
  frmlkp.lkpFlds.value=lkpFlds;
  frmlkp.lkpVals.value=lkpVals;
  frmlkp.retForm.value=retForm;
  frmlkp.retFlds.value=retFlds;
  frmlkp.retList.value=retList;
  frmlkp.submit();
}

// Open the Lookup Window, and fire the Lookup Request.
function fnOpenCntLookup(pInstance, pLkpSrc, pLkpFlds, pLkpCtls, pFltFlds, pFltCtls, pRetFlds, pRetCtls, pCtx, pRunWob) {
  var vLkpVals = "";
  var vParentForm;
  var vControl;
  var vKeyFld  = new Array();
  var vKeyCtl  = new Array();
  var vName;
  var vURL;

  var iVar = 0;
  var iFld = 0;

  if (pInstance == undefined)
  {
    wsAlert("An invalid instance was passed to fnOpenCntLookup.\n\n  Unable to initialize lookup.");

    return false;
  }

  pRunWob = (pRunWob == undefined || trim(pRunWob) == "" ? "lookp" : trim(pRunWob));

  vParentForm = wsGetParent(pInstance, "FORM");

  pLkpSrc  = (pLkpSrc  == undefined ? "" : trim(pLkpSrc));

  pRetFlds = (pRetFlds == undefined || trim(pRetFlds) == "" ? new Array() : pRetFlds.replace(" ", "").split(","));
  pRetCtls = (pRetCtls == undefined || trim(pRetCtls) == "" ? new Array() : pRetCtls.replace(" ", "").split(","));
  pLkpFlds = (pLkpFlds == undefined || trim(pLkpFlds) == "" ? new Array() : pLkpFlds.replace(" ", "").split(","));
  pLkpCtls = (pLkpCtls == undefined || trim(pLkpCtls) == "" ? new Array() : pLkpCtls.replace(" ", "").split(","));
  pFltFlds = (pFltFlds == undefined || trim(pFltFlds) == "" ? new Array() : pFltFlds.replace(" ", "").split(","));
  pFltCtls = (pFltCtls == undefined || trim(pFltCtls) == "" ? new Array() : pFltCtls.replace(" ", "").split(","));
  pCtx     = (pCtx     == undefined                         ? ""          : trim(pCtx));

  vKeyFld[0] = pLkpFlds[0];
  vKeyCtl[0] = pLkpCtls[0];
  pLkpFlds = pLkpFlds.slice(1);
  pLkpCtls = pLkpCtls.slice(1);
  
  pRetFlds = vKeyFld.concat(pRetFlds, pLkpFlds);
  pRetCtls = vKeyCtl.concat(pRetCtls, pLkpCtls);

  pLkpFlds = pLkpFlds.concat(pFltFlds);
  pLkpCtls = pLkpCtls.concat(pFltCtls);

  for (iVar = 0; iVar < pLkpCtls.length; iVar++)
  {
    vControl = fnGetControls(pLkpCtls[iVar])[0];

    vLkpVals = vLkpVals + (iVar == 0 ? "" : "^|^")
             + (vControl == undefined ? pLkpCtls[iVar] : vControl.value);
  }

  // This is specifically for multiselect combos 
  if ( pRunWob == "mscombo" )
  {
    vControl = fnGetControls(vKeyCtl[0])[0];
    pLkpFlds = vKeyFld.concat(pLkpFlds);
    vLkpVals = vControl.value + "^|^" + vLkpVals;
  }
  vURL = "?run="     + pRunWob
       + "&ctx="     + cSpf + ":" + pCtx
       + "&lkpSrc="  + pLkpSrc
       + "&retForm=" + vParentForm.name
       + "&lkpFlds=" + pLkpFlds.join("|")
       + "&lkpVals=" + vLkpVals
       + "&retFlds=" + pRetCtls.join("|")
       + "&retList=" + pRetFlds.join("|");

  var winPtr=window.open(vURL,"winLookup",cLkpWin);
}


function handleKeystroke(poEvent) {
  var vControl;
  var vEvent;
  var vButton = "";
  var vSubmit  = false;

  vEvent   = ((poEvent.which)     ? poEvent           : event);
  vControl = ((vEvent.srcElement) ? vEvent.srcElement : vEvent.target);

  if (gvAlertActive == true)
  {
    gvAlertActive = false;
    vEvent.cancelBubble = true;
    return true;
  }
  
  if (vEvent.keyCode == 13) {
    switch (vControl.type) {
      case ("select-one") :
        vSubmit = !(giPrevKeyCode > 36 && giPrevKeyCode < 41);
        break;
      case ("textarea") :
        vSubmit = false;
        break;
      default:
        vSubmit = true;
        break;
    }
  }

  gvPrevControl = vControl;
  giPrevKeyCode = vEvent.keyCode;

  if (vSubmit == true)
  {
    vButton = eval(gvDefaultButton != undefined && trim(gvDefaultButton) != "" ? gvDefaultButton : gvFirstButton);

    if (vButton != undefined && vButton.tagName == "wsButton")
    {
      vEvent.cancelBubble = true;

      vButton.highlight();
      vButton.click();

      return false;
    }
    else
      return true;
  }
  else
    return true;
}

function wsAlert(ipcMessage) {
  gvAlertActive = true;

  alert(ipcMessage);

  iTimer = setTimeout('gvAlertActive = false;', 250);
}

function wsGetElementTopLeft (pObjectOrIdOrName) {

  var vObject = fnGetControls(pObjectOrIdOrName)[0];
  var vLeft   = 0;
  var vTop    = 0;

  while (vObject != undefined) {
    vLeft   = vLeft + vObject.offsetLeft;
    vTop    = vTop  + vObject.offsetTop;
    vObject = vObject.offsetParent;
  }

  return vTop + "," + vLeft;
}

function wsHasAttribute(pControlOrIdOrName, pAttributeName)
{
  pAttributeName = (pAttributeName == undefined ? "" : trim(pAttributeName));

  if (pAttributeName == "")
    return false;

  var vControl = fnGetControls(pControlOrIdOrName)[0];

  if (vControl == undefined)
    return false;

  if (vControl.hasAttribute != undefined)
    return vControl.hasAttribute(pAttributeName);
  else
    if (vControl.getAttribute != undefined)
      return vControl.getAttribute(pAttributeName);
    else
      return false;
}

// Check the type of browser and return a TLA for it.
// TLA structure:
// char 1-2 : ie = Microsoft Internet Explorer
//          : ns = Netscape
// char 3   : Major Version Number
function fnSetBrowser() {
  var cThisBrowser="";
  var cAppName=navigator.appName;
  var cAppVer=navigator.appVersion;
  switch (cAppName) {
    case ("Microsoft Internet Explorer") :
      cThisBrowser="ie"+cAppVer.substring(0,1);
      break;
    case ("Netscape") :
      cThisBrowser="ns"+cAppVer.substring(0,1);
      break;
    default :
      cThisBrowser="unk";
      break;
  }
  return cThisBrowser;
}

function fnValidDate(ptrDate,lMand,lWarn) {
  var cDate=ptrDate.value;
  var iPosDay=cDateSeq.indexOf("d",0);
  var iPosMth=cDateSeq.indexOf("m",0);
  var iPosYear=cDateSeq.indexOf("y",0);
  var lValidDate=cDatePattern.test(cDate);

  if((lMand == false)&&(cDate == "")) {lValidDate=true;}
  else {
    if(lValidDate) {
      var cParts=cDate.split(cDateDel);
      var cDay=cParts[iPosDay];
      var cMth=cParts[iPosMth];
      var cYear=cParts[iPosYear];
      var lLeapYear=((cYear%4 == 0)&&(cYear%100 != 0)||(cYear%400 == 0));
      var iMaxDay=(((cMth%2) == (cMth<=7?1:0))?31:(cMth == 2?(lLeapYear?29:28):30));

      lValidDate=lValidDate&&(cDay>=1)&&(cDay<=iMaxDay);
      lValidDate=lValidDate&&(cMth>=1)&&(cMth<=12);
      lValidDate=lValidDate&&(cYear.length == 4);
    }
  }

  if(lWarn&&(!lValidDate)) {
    wsAlert("The Date ["+cDate+"] is invalid.  Please enter the date in the format "+cDateMsg);
    // ptrDate.focus();
  }

  return lValidDate;
}

function fnBuildDate(ptrDate) {
  var iLoop;
  var cDate=ptrDate.value;
  var iPosDay=cDateSeq.indexOf("d",0);
  var iPosMth=cDateSeq.indexOf("m",0);
  var iPosYear=cDateSeq.indexOf("y",0);

  while (   (cDate.length > 0)
         && (cDateDels.indexOf(cDate.substr(cDate.length-1,1)) > -1)
        ) {
    cDate=cDate.substr(0,(cDate.length-1))+cDateDel;
  }
  var cParts=cDate.split(cDateDel);
  var cDay =((cParts.length > iPosDay) ?cParts[iPosDay]:"");
  var cMth =((cParts.length > iPosMth) ?cParts[iPosMth]:"");
  var cYear=((cParts.length > iPosYear)?cParts[iPosYear]:"");
  cDate="";
  for (iLoop=0;((iLoop < 3)&&(iLoop < cParts.length));iLoop++) {
    if (iLoop > 0) {cDate+=cDateDel;}
    if (cParts.length > iLoop+1) {
      if (cParts[iLoop].length < 2) {cDate+="0"+ cParts[iLoop];}
      else                          {cDate+=cParts[iLoop];}
    } else {
      cDate+=cParts[iLoop];
    }
    

//    if (iPosDay  == iLoop) {
//      if (cParts.length > iPosDay + 1) {
 //       if (cDay.length < 2) {cDay = "0" + cDay;}
//      }
//      cDate+=cDay;
//    }
//    if (iPosMth  == iLoop) {
//      if (cParts.length > iPosMth + 1) {
//        if (cMth.length < 2) {cMth = "0" + cMth;}
//      }
//      cDate+=cMth;
//    }
//    if (iPosYear  == iLoop) {
//      if (cParts.length > iPosYear + 1) {
//        if (cYear.length < 4) {cYear = "0" + cYear;}
//      }
//      cDate+=cYear;
//    }
  }

  
  while (   (cDate.length > 0)
         && ((cDateDel+"0123456789").indexOf(cDate.substr(cDate.length-1,1)) == -1)
        ) {
    cDate=cDate.substr(0,(cDate.length-1));
  }
  ptrDate.value=cDate;
  return true;
}


function createTable(psTitle,
                     psTableName,
                     psTableTagSnippet,
                     psColumnLabels,
                     psColumnLabelTagSnippet,
                     psRowContents,
                     psRowTagSnippet,
                     psCellTagSnippet,
                     psHeaderRowTagSnippet,
                     psRow1TagSnippet,
                     psRow2TagSnippet) {

  var sColumnLabelTagSnippets = psColumnLabelTagSnippet.split(",");
  var sColumnLabelTagSnippet;
  var sOuterTableTagSnippet;
  var sColumnLabels           = psColumnLabels.split(",");
  var sColumnLabel;
  var sCellTagSnippets        = psCellTagSnippet.split(",");
  var sCellTagSnippet;
  var sCellContents;
  var sRowTagSnippets         = psRowTagSnippet.split(",");
  var sRowTagSnippet;
  var sRowTagSnippet;
  var sRowContents;
  var sReturnValue;
  var sFieldNames = "";
  var iColumn;
  var iRow;

  // Make sure they supply a name - we also need to make sure that it is unique
  if (psTableName == undefined || psTableName == "") {
    wsAlert("Please supply a name when calling the createTable function.");

    return false;
  }

  // Assume some default values for arguments that were not supplied
  if (psHeaderRowTagSnippet == undefined) psHeaderRowTagSnippet = "";              else psHeaderRowTagSnippet = " " + psHeaderRowTagSnippet;
  if (psTableTagSnippet     == undefined) psTableTagSnippet     = "";              else psTableTagSnippet     = " " + psTableTagSnippet;
  if (psRow1TagSnippet      == undefined) psRow1TagSnippet      = "class='clRw1'"; else psRow1TagSnippet      = " " + psRow1TagSnippet;
  if (psRow2TagSnippet      == undefined) psRow2TagSnippet      = "";              else psRow2TagSnippet      = " " + psRow2TagSnippet;
  if (psRowContents         == undefined) psRowContents         = "";

  sOuterTableTagSnippet = psTitle.split("|")[1];

  if (sOuterTableTagSnippet == undefined)
    sOuterTableTagSnippet = "";
  else {
    psTitle = psTitle.split("|")[0];

    sOuterTableTagSnippet = " " + sOuterTableTagSnippet;
  }

  if (psRow2TagSnippet == "")
    psRow2TagSnippet = " " + psRow1TagSnippet;

  sRowContents = psRowContents.split(",");

  document.write("\n");

  document.write("<table id='id" + psTableName + "-Outer' cellspacing='0' cellpadding='0'" + sOuterTableTagSnippet + ">\n");

  if (psTitle != "") {
    document.write(" <tr class='clHdr'>\n");
    document.write("  <td class='clPd0'>" + psTitle + "</td>\n");
    document.write(" <tr>\n");
  }

  document.write(" <tr>\n");
  document.write("  <td class='clPd0'>\n");
  document.write("   <table name='" + psTableName + "'" + psTableTagSnippet + ">\n");

  // Only if we have some valid labels do we actually want to output a header row
  if (sColumnLabels.join("") != "") {
    // Open the header row
    document.write("    <tr" + psTableTagSnippet + ">\n");

    for (iColumn = 0; iColumn < sColumnLabels.length; iColumn++) {
     // Prepare the ColumnLabelTagSnippet that will be used on a per column basis
     if (sColumnLabelTagSnippets[iColumn] == undefined)
       sColumnLabelTagSnippet = " class='clChr'";
     else
       sColumnLabelTagSnippet = " " + sColumnLabelTagSnippets[iColumn];

     document.write("     <th" + sColumnLabelTagSnippet + ">" + sColumnLabels[iColumn] + "</th>\n");
    }

    // Close the header row and underline it
    document.write("    </tr>\n");
    document.write("    <tr class='clTbu' height='1px'><td class='clTbu' colspan='" + sColumnLabels.length + "'></td></tr>\n");
  }

  // Now we start outputting the rows
  if (psRowContents != "" && psRowContents != undefined) {
    for (iRow = 0; iRow < sRowContents.length; iRow++) {
      // If no overriding row tag snippet was specified, then we will default to the Row1-Row2 tag snippets
      if (sRowTagSnippets[iRow] == undefined || sRowTagSnippets[iRow] == "") {
        if (iRow % 2 == 0)
          sRowTagSnippet = psRow1TagSnippet;
        else
          sRowTagSnippet = psRow2TagSnippet;
      }
      else
        sRowTagSnippet = sRowTagSnippets[iRow];

      if (sRowTagSnippet != "")
        sRowTagSnippet = " " + sRowTagSnippet;

      // Open the row
      document.write("    <tr" + sRowTagSnippet + ">\n");

      if (sRowContents[iRow] == undefined)
        sCellContents = "";
      else
        sCellContents = sRowContents[iRow].split("|");

      for (iColumn = 0; iColumn < sColumnLabels.length; iColumn++) {
        if (sCellTagSnippets[iColumn] == undefined || sCellTagSnippets[iColumn] == "")
          sCellTagSnippet = "";
        else
          sCellTagSnippet = " " + sCellTagSnippets[iColumn];

        //Open the cell
        document.write("     <td" + sCellTagSnippet + ">");

        //If we have some control details, then output control details
        if (sCellContents[iColumn] != undefined && sCellContents[iColumn] != "") {
          document.write(sCellContents[iColumn]);

          sReturnValue = getAttributeValueFromControls(sCellContents[iColumn], "name");
          sFieldNames  = sFieldNames + (sFieldNames == "" ? "" : (sReturnValue == "" ? "" : ","))
                       + sReturnValue;
        }
        //Close the cell
        document.write("</td>\n");
      }
      // Close the row
      document.write("    </tr>\n");
    }
  }
  //Close the table
  document.write("   </table>\n");
  document.write("  </td>\n");
  document.write(" </tr>\n");
  document.write("</table>\n");
  document.write("<input type='hidden' id='frmTblFields-" + psTableName + "' value='" + sFieldNames + "'>\n");
}

function getAttributeValueFromControls(psText, psAttribute) {
  var sFieldNames = "";
  var rgxPattern  = new RegExp("\\s*" + psAttribute + "\\s*=\\s*(\"|\')\\w*(\"|\')", "gi");
  var rgxName     = new RegExp("[^\\s*name\\s*=\\s*(\"|\')]\\w*", "i");
  var rgxResult;

  rgxResult = rgxPattern.exec(psText);

  while (rgxResult != undefined) {
    sFieldNames = sFieldNames + (sFieldNames == "" ? "" : ",") + rgxName.exec(rgxResult[0]);

    rgxResult = rgxPattern.exec(psText);
  }

  return sFieldNames;
}

function sensitizeTable(psTableName, pbSensitive) {
  var sControlNames = "";
  var sControls;
  var cControl;
  var cTable;
  var iControl;

  if (psTableName == "")
    return;

  sTable    = window.document.getElementById("id" + psTableName + "-Outer");
  sControls = window.document.getElementById("frmTblFields-" + psTableName);

  if (sTable == undefined) {
    wsAlert("The table '" + (psTableName == undefined ? "<Null>" : psTableName) + "' could not be found to sensitize.");

    return false;
  }

  if (sControls != undefined) {
    sControls = sControls.value.split(",");

    for (iControl = 0; iControl < sControls.length; iControl++) {
      cControl = window.document.getElementsByName(sControls[iControl]);

      if (cControl[0] != undefined) {
        cControl[0].disabled = !(pbSensitive);
      }
    }
  }

  sTable.style.display = (pbSensitive ? "" : "none");
}

function rebuildSelect(psSelectIDName, psNewListItemPairs, psNewValue) {
/* --------------------------------------------------------------------------------
     Purpose: To reconstruct the options for a select

  Parameters: psSelectIDName     - The id or name of the select control. Seeing
                                   that ids are supposed to be unique, we will
                                   first try to find a select using the value
                                   as an id. Failing that, we will try to find
                                   the first select using the value as a name.
              psNewListItemPairs - A ListItem-Value pair that will be used to
                                   construct the new options for the select
              psNewValue         - Optional: Default value the select should be
                                   pointed to after the reconstuct has occured.
                                   If not specified or if blank, the first option
                                   in the select will be chosen.
-------------------------------------------------------------------------------- */
  var sListItemPairs;
  var sOption;
  var sValue;
  var bFoundWithID;
  var cTempOption;
  var cControl;
  var cSelect;
  var iIterations;
  var iOptions;
  var iOption;
  var iSelect;
  var iSelected;
  var sSelected = new Array();
  var lNewValueSelected = false;

  // Default unspecified parameters to blanks/empty strings
  if (psSelectIDName     == undefined) psSelectIDName     = "";
  if (psNewListItemPairs == undefined) psNewListItemPairs = "";
  if (psNewValue         == undefined) psNewValue         = "";
  
  if (psSelectIDName == "") {
    wsAlert("function 'rebuildSelect' was invoked but no value was supplied for the 'psSelectIDName' parameter.\n\n");

    return false;
  }

  sListItemPairs = psNewListItemPairs.split("|");

  // First try and locate the control by using the value as an ID
  cSelect = window.document.getElementById(psSelectIDName);

  // If we found a control (and seeing that the ID should be unique), if it is not a select, we cannot continue
  if (cSelect != undefined && cSelect.options == undefined) {
    wsAlert("function 'rebuildSelect' found a control on the page with an id of '" + psSelectIDName + "' but it was not a select.\n\n");

    return false;
  }

  /* This is a workaround for IE - even though you use getElementById, they find a control using the name
     if they cannot find a unique control using the id!!! You query the id of the returned control and it
     is blank... Go figure */
  if (cSelect != undefined && cSelect.id != psSelectIDName)
    cSelect = null;

  // If we still do not have a control at this stage, see what controls we can find by using the value as a name
  if (cSelect == undefined)
    cSelect = window.document.getElementsByName(psSelectIDName);
  else
    bFoundWithID = true;

  // If we still do not have a control, then nothing on the form exists with the specified id or name
  if (cSelect == undefined) {
    wsAlert("function 'rebuildSelect' found no valid select controls on the page with an id or name of '" + psSelectIDName + "'.\n\n");

    return false;
  }

  /* If we got back something but it does not have options, it might be an array of controls. In
     that case, check each one of them to make sure that they are select controls */
  if (cSelect != undefined && cSelect.options == undefined) {
    for (iSelect = 0; iSelect < cSelect.length; iSelect++) {
      if (cSelect[iSelect].options == undefined) {
        wsAlert("function 'rebuildSelect' found controls on the page named '" + psSelectIDName + "', but not all of them were select controls.\n\n");

        return false;
      }
    }
  }

  // Determine how many iterations of the loop we have to go through depending on whether we got back an array of controls
  iIterations = (cSelect.options == undefined ? cSelect.length : 1);

  for (iSelect = 0; iSelect < iIterations; iSelect++) {
    cControl = (iIterations == 1 ? (bFoundWithID ? cSelect : cSelect[0]) : cSelect[iSelect]);

    /* If it is not a multi select then we know there could only have been a maximum of 1 selected,
     or atleast there should of only been 1 selected */
    if (cControl.selectedIndex >= 0 && cControl.multiple == false && cControl.options[cControl.selectedIndex].value != "")
      sSelected[0] = cControl.options[cControl.selectedIndex].value;

    // Clear the select's current contents
    iOptions  = cControl.options.length;
    iSelected = 0;

    for (iOption = 0; iOption < iOptions; iOption++) {

      // Get the Previously Selected Values, Just incase we need them - Only for a Multi Select
      if (cControl.multiple == true && cControl.selectedIndex >= 0 && cControl.options[0].selected == true && cControl.options[0].value != "") {
        sSelected[iSelected] = cControl.options[0].value;

        iSelected += 1;
      }
      // Continually strip off the first option (iOptions number of times)
      cControl.options[0] = null;
    }

    for (iOption = 0; iOption < sListItemPairs.length; iOption++) {
      sOption = (sListItemPairs[iOption].split("="));

      if (sOption.length >= 2) {
        sValue  = sOption[1];
        sOption = sOption[0];
      }
      else {
        sValue  = sOption[0];
        sOption = sOption[0];
      }

      cTempOption = new Option(sOption, sValue);

      cControl.options[iOption] = cTempOption;
    }

    // Loop through the Options to determine which ones, if any, should be selected
    if (psNewValue != "" || sSelected != "") {

      for (iOption = 0; iOption < cControl.options.length; iOption++) {

        if (psNewValue != "" && cControl.options[iOption].value == psNewValue) {
            cControl.options[iOption].selected = true;

            lNewValueSelected = true;
        }
        else
          for (iSelected = 0; iSelected < sSelected.length; iSelected++) {
            if (cControl.options[iOption].value == sSelected[iSelected]) cControl.options[iOption].selected = true;
          }
      }

      if (lNewValueSelected == false && psNewValue != "") wsAlert("Could not find '" + psNewValue + "' in new Combo List!\n\n");
    }

    if (cControl.options.selectedIndex < 0) cControl.options[0].selected = true;
  }
}

function replaceCellContents (psTableID, psCellContents) {
/* --------------------------------------------------------------------------------
     Purpose: To replace the contents of a cell in a table

  Parameters: psTableID      - The id of the table. We cannot pass in a name
                               as tables do not carry a name property.
          psLabelInformation - Pipe delimited list containing the information
                               that will be used to find the specified cells
                               and replace the contents with that specified
                               The format of the list is as follows:
                                 RaCb-[Contents]|RxCy-[Contents]|...|...
                               a (or x) refers to the row number and b (or y)
                               refers to the column number of the cell.
  -------------------------------------------------------------------------------- */
  var rgxCellContents = /^R\d+C\d+-/;
  var sCellContents;
  var sCoordinates;
  var iColumn;
  var iCell;
  var iRow;
  var cTable;

  // Make sure that we get a valid table id
  if (psTableID == undefined || psTableID == "") {
    wsAlert("A table must be specified when calling the 'replaceCellContents' function.");

    return false;
  }

  // Default unspecified parameter(s) to blanks/empty strings
  if (psCellContents == undefined) psCellContents = "";

  if (psCellContents == "")
    return true;

  // Try and locate the table using the id value - tables do not support a name attribute
  cTable = window.document.getElementById(psTableID);

  /* This is a workaround for IE - even though you use getElementById, they find a control using the name
     if they cannot find a unique control using the id!!! You query the id of the returned control and it
     is blank... Go figure */
  if (cTable != undefined && cTable.id != psTableID)
    cTable = null;

  // If we found a control (and seeing that the ID should be unique), if it is not a table, we cannot continue
  if (cTable != undefined && cTable.rows == undefined) {
    wsAlert("function 'replaceCellContents' found a control on the page with an id of '" + psTableID + "' but it was not a table.\n\n");

    return false;
  }

  // If we still do not have a table, then nothing on the form exists with the specified id
  if (cTable == undefined) {
    wsAlert("function 'replaceCellContents' did not find a valid table on the page with an id of '" + psTableID + "'.\n\n");

    return false;
  }

  sCellContents = psCellContents.split("|");

  for (iCell = 0; iCell < sCellContents.length; iCell++) {
    // Only if we have a string that is in the format we expect, process it
    if (rgxCellContents.test(sCellContents[iCell])) {
      sCoordinates         = sCellContents[iCell].substring(0, sCellContents[iCell].indexOf("-"));
      sCellContents[iCell] = sCellContents[iCell].substring(sCellContents[iCell].indexOf("-") + 1);

      /* We assume a 1 based count when dealing with rows and columns in this API - not
         0 based like the array elements are. Subtract 1 from the values that we passed
         in to get us in sync with what we have in the table row and column arrays */
      iRow    = sCoordinates.split("C")[0].split("R")[1] - 1;
      iColumn = sCoordinates.split("C")[1] - 1;

      // Check to see if we can find the row in the table
      if (cTable.rows[iRow] != undefined)  {
        // Check to see if we can find the cell within the row
        if (cTable.rows[iRow].cells[iColumn] != undefined)
          // Upon reaching this point, we found the cell. Replace its contents with the contents passed into the function.
          cTable.rows[iRow].cells[iColumn].innerHTML = sCellContents[iCell];
        else
          wsAlert("function 'replaceCellContents' could not find column number " + (iColumn + 1) + " in row number " + (iRow + 1) + " in the table specified.\n\n");
      }
      else
        wsAlert("function 'replaceCellContents' could not find row number " + (iRow + 1) + " in the table specified.\n\n");
    }
    else
      wsAlert("The content information '" + sCellContents[iCell] + "' is not in the format expected.\n\nPlease correct.");
  }
}

function insertRowInTable (psTableID, piPosition, pcRowClass, pcAlternatingRowClasses, pbAutoInsertColumns) {
/* --------------------------------------------------------------------------------
     Purpose: To insert a row in a given table

  Parameters:     psTableID - The id of the table. We cannot pass in a name
                              as tables do not carry a name property.
                 piPosition - The position we want to add a row.
                 pcRowClass - If this is not null, we will use this value as the
                              class for this row - even if it is empty. If it is
                              null, we will determine the row based on the alternating
                              row argument.
    pcAlternatingRowClasses - This is a 2 entry comma seperated list that will
                              be used if we need to alternate the row styles.
                              If nothing is specified, we will default to clRw1,clRw2.
        pbAutoInsertColumns - If this argument is not specified, it defaults to true.
-------------------------------------------------------------------------------- */
  var sRow1Class;
  var sRow2Class;
  var cTable;
  var iTotalColumns = 0;
  var iColumn;
  var iRow;

  // Make sure that we get a valid table id
  if (psTableID == undefined || psTableID == "") {
    wsAlert("A table must be specified when calling the 'insertRowInTable' function.");

    return false;
  }

  // Default unspecified parameter(s) to blanks/empty strings
  if (pcAlternatingRowClasses == undefined)       pcAlternatingRowClasses = "clRw1,clRw2";
  if (pbAutoInsertColumns     == undefined)       pbAutoInsertColumns     = true;
  if (piPosition == undefined || piPosition < -1) piPosition = -1;

  // Try and locate the table using the id value - tables do not support a name attribute
  cTable = window.document.getElementById(psTableID);

  /* This is a workaround for IE - even though you use getElementById, they find a control using the name
     if they cannot find a unique control using the id!!! You query the id of the returned control and it
     is blank... Go figure */
  if (cTable != undefined && cTable.id != psTableID)
    cTable = null;

  // If we found a control (and seeing that the ID should be unique), if it is not a table, we cannot continue
  if (cTable != undefined && cTable.rows == undefined) {
    wsAlert("function 'insertRowInTable' found a control on the page with an id of '" + psTableID + "' but it was not a table.\n\n");

    return false;
  }

  // If we still do not have a table, then nothing on the form exists with the specified id
  if (cTable == undefined) {
    wsAlert("function 'insertRowInTable' did not find a valid table on the page with an id of '" + psTableID + "'.\n\n");

    return false;
  }

  /* If we want to add to the end of the table, find out what the last row in the table was */
  if (piPosition == -1)
    piPosition = cTable.rows.length;
  else
    piPosition = piPosition - 1;

  cTable.insertRow(piPosition);

  if (pcRowClass == undefined) {
    sRowClass1 = pcAlternatingRowClasses.split(",")[0];

    if (pcAlternatingRowClasses.split(",")[1] == undefined)
      sRowClass2 = sRowClass1;
    else
      sRowClass2 = pcAlternatingRowClasses.split(",")[1];

    for (iRow = 0; iRow < cTable.rows.length; iRow++) {
      if (piPosition == iRow || cTable.rows[iRow].className == sRowClass1
                             || cTable.rows[iRow].className == sRowClass2)
        cTable.rows[iRow].className = (iRow % 2 == 0 ? sRowClass1 : sRowClass2);
    }
  }
  else
    cTable.rows[piPosition].className = pcRowClass;

  if (pbAutoInsertColumns == true) {
    // Check to see how many columns we have in the table
    for (iRow = 0; iRow < cTable.rows.length; iRow++) {
      iTotalColumns = Math.max(iTotalColumns, cTable.rows[iRow].cells.length);
    }

    for (iColumn = 0; iColumn < iTotalColumns; iColumn ++) {
      cTable.rows[piPosition].insertCell(iColumn);
    }
  }

  return cTable.rows[piPosition];
}

function insertCellInRow (psTableID, piRowNumber, piPosition, pcCellClass, piColumnSpan, psCellContents) {
/* --------------------------------------------------------------------------------
     Purpose: To insert a cell in a row in a given table

  Parameters:     psTableID - The id of the table. We cannot pass in a name
                              as tables do not carry a name property.
                piRowNumber - The row number in which we want to add the cell.
                 piPosition - The position we want to add a cell.
                pcCellClass - If not specified, we will default it to empty string.
               piColumnSpan - The number of columns a cell must span. If not specified
                              or if less than 1, it will be defaulted to 1.
-------------------------------------------------------------------------------- */
  var cTable;
  var iColumn;

  // Make sure that we get a valid table id
  if (psTableID == undefined || psTableID == "") {
    wsAlert("A table must be specified when calling the 'insertCellInRow' function.");

    return false;
  }

  // Make sure that we get a valid row number
  if (piRowNumber == undefined || piRowNumber < 1) {
    wsAlert("A valid row number must be specified when calling the 'insertCellInRow' function.");

    return false;
  }

  // Default unspecified parameter(s) to blanks/empty strings
  if (piColumnSpan   == undefined || piColumnSpan < 1)  piColumnSpan   = 1;
  if (piPosition     == undefined || piPosition   < -1) piPosition     = -1;
  if (psCellContents == undefined)                      psCellContents = "";
  if (pcCellClass    == undefined)                      pcCellClass    = "";

  // Try and locate the table using the id value - tables do not support a name attribute
  cTable = window.document.getElementById(psTableID);

  /* This is a workaround for IE - even though you use getElementById, they find a control using the name
     if they cannot find a unique control using the id!!! You query the id of the returned control and it
     is blank... Go figure */
  if (cTable != undefined && cTable.id != psTableID)
    cTable = null;

  // If we found a control (and seeing that the ID should be unique), if it is not a table, we cannot continue
  if (cTable != undefined && cTable.rows == undefined) {
    wsAlert("function 'insertCellInRow' found a control on the page with an id of '" + psTableID + "' but it was not a table.");

    return false;
  }

  // If we still do not have a table, then nothing on the form exists with the specified id
  if (cTable == undefined) {
    wsAlert("function 'insertCellInRow' did not find a valid table on the page with an id of '" + psTableID + "'.");

    return false;
  }

  piRowNumber = piRowNumber - 1;

  if (cTable.rows[piRowNumber] == undefined) {
    wsAlert("Invalid row specified when the 'insertCellInRow' function was called.");

    return false;
  }

  /* If we want to add to the end of the row, find out what the last cell in the row was */
  if (piPosition == -1)
    piPosition = cTable.rows[piRowNumber].cells.length;
  else
    piPosition = piPosition - 1;

  cTable.rows[piRowNumber].insertCell(piPosition);
  cTable.rows[piRowNumber].cells[piPosition].colSpan    = piColumnSpan;
  cTable.rows[piRowNumber].cells[piPosition].className  = pcCellClass;
  cTable.rows[piRowNumber].cells[piPosition].innerHTML  = psCellContents;
}

function controlVisible (pControlOrIdOrName, pbVisible) {
  var cControl;
  var iControl;

  // If we got nothing to work with, return an error
  if (pControlOrIdOrName == undefined) {
    wsAlert("A valid control or id of, or name of a control needs to be specified when calling the function 'controlVisibility'.");

    return false;
  }

  // If a control was not passed in, try to locate it with the information passed in
  if (pControlOrIdOrName.className == undefined) {
    // First try and locate the control by using the value as an ID
    cControl = window.document.getElementById(pControlOrIdOrName);

    /* This is a workaround for IE - even though you use getElementById, they find a control using the name
       if they cannot find a unique control using the id!!! You query the id of the returned control and it
       is blank... Go figure */
    if (cControl != undefined && cControl.id != pControlOrIdOrName)
      cControl = null;

    // If we still do not have a control at this stage, see what controls we can find by using the value as a name
    if (cControl == undefined)
      cControl = window.document.getElementsByName(pControlOrIdOrName);

    // If we still do not have a control, then nothing on the form exists with the specified id or name
    if (cControl == undefined) {
      wsAlert("function 'controlVisibility' found no valid select controls on the page with an id or name of '" + pControlOrIdOrName + "'.");

      return false;
    }
  }
  else
    cControl = pControlOrIdOrName;

  // Default unspecified parameter(s)
  if (pbVisible == undefined) pbVisible = true;

  if (cControl != undefined) {
    /* If we got back something but it does not have a className attribute, it might be an array of controls.
       In that case, check each one of them to make sure that they have the className attribute */
    if (cControl.style == undefined) {
      for (iControl = 0; iControl < cControl.length; iControl++) {
        cControl[iControl].style.display = (pbVisible ? "" : "none")

        if (pbVisible == true)
          cControl[iControl].className = trim((" " + cControl[iControl].className + " ").replace(" clHid ", ""));
        else
          cControl[iControl].className = trim((" " + cControl[iControl].className + " ").replace(" clHid ", "") + " clHid");
      }
    }
    else {
      cControl.style.display = (pbVisible ? "" : "none")

      if (pbVisible == true)
        cControl.className = trim((" " + cControl.className + " ").replace(" clHid ", ""));
      else
        cControl.className = trim((" " + cControl.className + " ").replace(" clHid ", "") + " clHid");
    }
  }
}

function trim (psString, psTrimCharacters, psTrim) {
  var rgxPattern = new RegExp();
  var sCharacter = "";
  var sPattern   = "";
  var iChar      = 0;

  if (psTrimCharacters == undefined) psTrimCharacters = " ";
  if (psString         == undefined) psString         = "";
  if (psTrim           == undefined) psTrim           = "both";

  // If we do not have valid values, it is no use to continue
  if (psTrim != "both" && psTrim != "left" && psTrim != "right") {
    wsAlert("An invalid value has been passed to the 'Trim' argument of the 'trim' function.\n\nValid values are null, 'both', 'left' or 'right'.");

    return null;
  }

  for (iChar = 0; iChar < psTrimCharacters.length; iChar++) {
    sCharacter = psTrimCharacters.substr(iChar, 1);

    switch (sCharacter) {
      case "\f": sCharacter = "\\f";  break;
      case "\n": sCharacter = "\\n";  break;
      case "\r": sCharacter = "\\r";  break;
      case "\t": sCharacter = "\\t";  break;
      case "\v": sCharacter = "\\v";  break;
      case "/":  sCharacter = "\\/";  break;
      case "\\": sCharacter = "\\\\"; break;
      case ".":  sCharacter = "\\.";  break;
      case "*":  sCharacter = "\\*";  break;
      case "+":  sCharacter = "\\+";  break;
      case "?":  sCharacter = "\\?";  break;
      case "|":  sCharacter = "\\|";  break;
      case "(":  sCharacter = "\\(";  break;
      case ")":  sCharacter = "\\)";  break;
      case "[":  sCharacter = "\\[";  break;
      case "]":  sCharacter = "\\]";  break;
      case "{":  sCharacter = "\\{";  break;
      case "}":  sCharacter = "\\}";  break;
      case " ":  sCharacter = "\\s";  break;
    }

    sPattern = sPattern + sCharacter;
  }

  if (psTrim == "both" || psTrim == "left") {
    // Trim the left side if so required
    rgxPattern.compile("^[" + sPattern + "]*", "gi");

    psString = psString.replace(rgxPattern, "");
  }

  if (psTrim == "both" || psTrim == "right") {
    // Trim the right side if so required
    rgxPattern.compile("[" + sPattern + "]*$", "gi");

    psString = psString.replace(rgxPattern, "");
  }

  return psString;
}

function fnDialogFocus(poDialogWindow) {

  if (poDialogWindow != undefined) {
    poDialogWindow.focus();

    return false;
  }

  return true;
}

function fnGetControls (pControlOrIdOrName, psTagName, pbUniqueOnly, pcDocument) {
/* --------------------------------------------------------------------------------
     Purpose: A central API to get back a specific control or set of controls or
              to ensure that a given control is of a specific type.

  Parameters: pControlOrIdOrName    - The object, id of an object or the name of the
                                      object(s).
                       psTagName    - The type of object
                      pbUniqueOnly  - Unique Object? is there one or more?
                     pcDocument     - The Document which this element should be located on

       Notes: The function will first check to see if an object has been passed in.
              If so, it will ONLY evaluate that the object is of the specified type
              and return that object only if it is of the type specified. If the value
              received was not an object, the function will then try to find an object
              with an id of the value passed. If an object is found, it will again
              ensure that the object is of the type specified and only return it if
              it is. 
-------------------------------------------------------------------------------- */
  var cControls = new Array();
  var cControl;
  var iControl = 0;
  var iElement = 0;

  // If an alternate document object was supplied, but it was not a document, we should not continue
  if (pcDocument != undefined && pcDocument.getElementById == undefined) {
    wsAlert("An invalid alternate document object was passed to the 'fnGetControls' function.");

    return null;
  }

  // Assign default values for unspecified parameters
  if (pbUniqueOnly == undefined) pbUniqueOnly = true;
  if (pcDocument   == undefined) pcDocument   = window.document;

  if (pControlOrIdOrName != undefined) {
    if (pControlOrIdOrName.tagName != undefined && (psTagName == undefined ||
                                                   (psTagName != undefined &&
                                                    psTagName.toUpperCase() == pControlOrIdOrName.tagName.toUpperCase())))
      cControls[0] = pControlOrIdOrName;
    else {
      // Try and locate the object / control using the id value
      cControl = pcDocument.getElementById(pControlOrIdOrName);

      /* This is a workaround for IE - even though you use getElementById, they find a control using the name
         if they cannot find a unique control using the id!!! You query the id of the returned control and it
         is blank... Go figure. */
      if (cControl != undefined && cControl.id != pControlOrIdOrName)
        cControl = null;

      if (cControl != undefined) {
        // If we got here, we have a unique control, so if it is of the correct type, make sure we return it
        if (psTagName == undefined || cControl.tagName.toUpperCase() == psTagName.toUpperCase())
          cControls[0] = cControl;
      }
      else {
        cControl = pcDocument.getElementsByName(pControlOrIdOrName);

        if (pbUniqueOnly == true) {
          if (cControl != undefined && cControl.length == 1) {
            if (psTagName == undefined || cControl[0].tagName.toUpperCase() == psTagName.toUpperCase())
              cControls[0] = cControl[0];
          }
        }
        else {
          if (cControl != undefined && cControl.length >= 1) {
            for (iControl = 0; iControl < cControl.length; iControl++) {
              if (psTagName == undefined || cControl[iControl].tagName.toUpperCase() == psTagName.toUpperCase()) {
                cControls[iElement] = cControl[iControl];
                iElement            = iElement + 1;
              }
            }
          }
        }
      }
    }
  }

  return cControls;
}

function fnGetControlValue(pControlOrIdOrName) {
/* -----------------------------------------------------------------------------
     Purpose: A central API to get back a Control Value or Comma Seperated List
              of values.

  Parameters: pControlOrIdOrName - The object, id of an object or the name of the
                                   object(s).

       Notes: The function will check which type of element was specified and return
              the appropriate (list of) value(s).
----------------------------------------------------------------------------- */
  var oControls, oControl, cControlValueList="", iControl, iOption;

  oControls = fnGetControls(pControlOrIdOrName, null, false);

  for(iControl=0; iControl<oControls.length; iControl++) {
    oControl = oControls[iControl];
    switch(oControl.tagName.toUpperCase()) {

      case ("SELECT") :
        if(oControl.selectedIndex >= 0) {
          for(iOption=0; iOption<oControl.options.length; iOption++) {
            if(oControl.options[iOption].selected == true)
              cControlValueList += (cControlValueList=='' ? '' : ',') + (oControl.options[iOption].value=='' ? ' ' : oControl.options[iOption].value);
          }
        }
        break;

      case ("INPUT") :
        if(oControl.type.toUpperCase()=="RADIO" || oControl.type.toUpperCase()=="CHECKBOX") {
          if(oControl.checked==true)
            cControlValueList += (cControlValueList=='' ? '' : ',') + (oControl.value=='' ? ' ' : oControl.value);
        }
        else
            cControlValueList += (cControlValueList=='' ? '' : ',') + (oControl.value=='' ? ' ' : oControl.value);
        break;

      default :
        break;
    }
  }
  return trim(cControlValueList, " ", "right");
}

function setMultiSelectValue (pSelectOrIdOrName, psValue) {
  var iOption = 0;
  var sValue  = "";
  var cSelect;

  if (psValue == undefined)
    psValue = "";

  sValue = "," + psValue + ",";

  if (pSelectOrIdOrName != undefined) {
    if (pSelectOrIdOrName.tagName == "SELECT") {
      cSelect = pSelectOrIdOrName;
    }
    else {
    }
  }

  // If we could not find a select control, there is no use to continue
  if (cSelect == undefined) {
    wsAlert("function 'setMultiSelectValue' could not find a select control with the parameters given.");

    return false;
  }

  for (iOption = 0; iOption < cSelect.options.length; iOption++) {
    if (sValue.indexOf("," + cSelect.options[iOption].value + ",") != -1)
      cSelect.options[iOption].selected = true;
    else
      cSelect.options[iOption].selected = false;
  }

  cSelect.value = psValue;

  return true;
}

function getMultiSelectValue (pSelectOrIdOrName) {
  var iOption = 0;
  var sValue  = "";
  var cSelect;

  cSelect = fnGetControls(pSelectOrIdOrName, "SELECT");

  // If we could not find a select control, there is no use to continue
  if (cSelect[0] == undefined) {
    wsAlert("function 'getMultiSelectValue' could not find a select control with the parameters given.");

    return false;
  }

  for (iOption = 0; iOption < cSelect[0].options.length; iOption++) {
    if (cSelect[0].options[iOption].selected == true)
      sValue = sValue + (sValue == "" ? "" : ",") + cSelect[0].options[iOption].value;
  }

  return sValue;
}

function fnFireLookup (psFieldList, psDataType) {
  var sControlValues = new Array();
  var sKeyFieldValue = "";
  var sControlNames;
  var sButtonName    = "";
  var bFireLookup    = false;
  var iControl       = 0;
  var cControl;

  if (psFieldList == undefined || trim(psFieldList) == "" ||
      psDataType  == undefined || trim(psDataType)  == "") {
    wsAlert("Please ensure that a valid field list and data type are supplied when calling the 'fnFireLookup' function.");

    /* Return a true so that the submit continues ok - all that it means is that
       the lookup won't fire automatically - it should still be validated by the
       server anyway */
    return true;
  }

  if (psFieldList.split("!").length != 1) {
    sButtonName = trim(psFieldList.split("!")[1]);
    psFieldList = trim(psFieldList.split("!")[0]);
  }

  sControlNames = psFieldList.split(",");
  
  // Let us get the values of the controls so that we can compare them afterwards
  for (iControl = 0; iControl < sControlNames.length; iControl++) {
    cControl = fnGetControls(sControlNames[iControl]);

    if (cControl[0] == undefined || !(cControl[0].tagName == "INPUT" || cControl[0].tagName == "SPAN")) {
      wsAlert("The function 'fnFireLookup' could not find a control with the name of '" + sControlNames[iControl] + "' could not be found.");

      /* Return a true so that the submit continues ok - all that it means is that
         the lookup won't fire automatically - it should still be validated by the
         server anyway */
      return true;
    }

    if (iControl == 0) {
      sControlValues[0] = "";
      sKeyFieldValue    = (cControl[0].value == undefined ? "" : cControl[0].value);
    }
    else
      sControlValues[iControl] = (cControl[0].value == undefined ? "" : cControl[0].value);
  }

  switch (psDataType.toUpperCase()) {
    case ("DECIMAL"):
      if ((sKeyFieldValue             == "" ||
           parseFloat(sKeyFieldValue) == 0) &&
           sControlValues.join("")    != "")
        bFireLookup = true;

      break; // case ("DECIMAL")

    case ("INTEGER"):
      if ((sKeyFieldValue             == "" ||
           parseFloat(sKeyFieldValue) == 0) &&
           sControlValues.join("")    != "")
        bFireLookup = true;

      break; // case ("INTEGER")

    default:
      if (sKeyFieldValue == "" && sControlValues.join("") != "")
        bFireLookup = true;

      break; // default
  }

  if (bFireLookup == true) {
    cControl = fnGetControls((sButtonName == "" ? sControlNames[0] + "LkpImg" : sButtonName), "IMG");

    cControl[0].onclick();

    return false;
  }
  
  return true;
}

function fnViewFirstHiddenRow (psTableOrIdOrName) {
  var cTable;
  var iRow = 0;

  cTable = fnGetControls(psTableOrIdOrName, "TABLE");

  if (cTable[0] == undefined) {
    wsAlert("The function 'fnViewFirstHiddenRow' could not find a table with the details specified.");

    return false;
  }
  
  for (iRow == 0; iRow < cTable[0].rows.length; iRow++) {
    if (cTable[0].rows[iRow].className.indexOf("clHid") >= 0) {
      controlVisible(cTable[0].rows[iRow], true);

      return true;
    }
  }
  
  wsAlert("The function 'fnViewFirstHiddenRow' could not find any hidden rows in the specified table to view.");

  return false;
}

// Open the HREF Window, and fire the HyperLink Request.
function fnHREF(hrefRun, hrefObj, hrefArgs, hrefCtx, hrefMst, hrefTarget)
{
  hrefArgs = (hrefArgs == undefined ? "" : trim(hrefArgs));

  if (hrefArgs != "")
    hrefArgs = (hrefArgs.substring(0,1) == "&" ? "" : "&") + hrefArgs;

  if (hrefMst == "")
  {
    vMenuStatus = fnGetControls("menuStatus", "INPUT");
    vMenuStatus = vMenuStatus[0];
    if (vMenuStatus == undefined)
    { hrefMst="OPEN"; }
    else
    { hrefMst=vMenuStatus.value;}
  }

  if (hrefMst == "")
  { hrefMst="OPEN"; }

  if (hrefTarget == "") {hrefTarget="winHREF";}

  var hrefURL = hrefRun
              + "&obj=" + hrefObj
              + hrefArgs
              + "&ctx=" + cSpf + ":" + hrefCtx
              + "&mst=" + hrefMst;
  var winPtr=window.open(hrefURL,hrefTarget,"");
}

function fnMenuToggle(pBaseClass)
{
  var vMenuShow;
  var vMenuHide;
  var vMenuStatus;
  var vImagePath;
  var vImage = new Array();

  vMenuShow   = fnGetControls("divMenuShow", "TD");   vMenuShow   = vMenuShow[0];
  vMenuHide   = fnGetControls("divMenuHide", "TD");   vMenuHide   = vMenuHide[0];
  vMenuStatus = fnGetControls("menuStatus", "INPUT"); vMenuStatus = vMenuStatus[0];
  vImagePath  = (pBaseClass == undefined ? cThemePath : (cThemePath + "img/cnt/" + pBaseClass).toLowerCase() + "/");
  //vImage      = window.document.getElementsByName("btnshm");
  vImage      = fnGetControls("btnshm",undefined,false);

  // In case we have a split that does not make provision for this, leave
  if (vMenuShow == undefined)
    return true;

  if (vMenuShow != undefined && vMenuShow.style.display == "")
  {
    if (vMenuShow   != undefined) vMenuShow.style.display = "none";
    if (vMenuHide   != undefined) vMenuHide.style.display = "";
    if (vMenuStatus != undefined) vMenuStatus.value = "CLOSE";
    if (vImage[0]   != undefined) vImage[0].src = vImagePath + (vImage.length == 1 ? "menu_show.gif" : "menu_show.gif");
    if (vImage[1]   != undefined) vImage[1].src = vImagePath + (vImage.length == 1 ? "menu_show.gif" : "menu_hide.gif");
    if (vImage[0]   != undefined) vImage[0].title = "Show Menu";
    if (vImage[1]   != undefined) vImage[1].title = "Show Menu";
  }
  else
  {
    if (vMenuShow   != undefined) vMenuShow.style.display = "";
    if (vMenuHide   != undefined) vMenuHide.style.display = "none";
    if (vMenuStatus != undefined) vMenuStatus.value = "OPEN";
    if (vImage[0]   != undefined) vImage[0].src = vImagePath + (vImage.length == 1 ? "menu_hide.gif" : "menu_show.gif");
    if (vImage[1]   != undefined) vImage[1].src = vImagePath + (vImage.length == 1 ? "menu_hide.gif" : "menu_hide.gif");
    if (vImage[0]   != undefined) vImage[0].title = "Hide Menu";
    if (vImage[1]   != undefined) vImage[1].title = "Hide Menu";
  }
}

function join_objects()
{
	var x = [];
	for(var i=0; arguments && i < arguments.length; i++)
		for(var k in arguments[i]) x[k] = arguments[i][k];
	return x;
}

function wsGetParent(pObject, pTagName, pMaxIterations)
{
  pMaxIterations = (pMaxIterations == undefined || isNaN(pMaxIterations) ? 100 : pMaxIterations);
  pTagName       = (pTagName       == undefined ? "" : trim(pTagName)).toLowerCase();

  if (pObject == undefined || pTagName == "")
  {
    wsAlert("Invalid parameters passed to wsGetParent.\n\n  Ensure a valid object AND parent object type is specified.");

    return null;
  }

  var vParent    = pObject;
  var vIteration = 0;

  while (vParent != undefined)
  {
    vIteration++;

    if (vParent.tagName.toLowerCase() == pTagName)
      return vParent;
    else
    {
      if (vIteration == pMaxIterations)
      {
        wsAlert("Could not find a parent object of type'" + pTagName + "' after " + pMaxIterations.toString() + ".\n\n  Search abandoned!");
      }

      vParent = vParent.parentNode;
    }
  }
}


function wsLookupChange(pControl, pFieldList)
{
  var vControl = new Array();
  var iField   = 0;

  pFieldList = (pFieldList == undefined ? "" : trim(pFieldList));

  if (pControl == undefined)
  {
    wsAlert("Please ensure that a valid control is specified when calling the wsLookupChange function.");
    
    return false;
  }

  if (pFieldList == "")
  {
    wsAlert("Please ensure that a valid list of fields are specified when calling the wsLookupChange function.");
    
    return false;
  }

  pFieldList = pFieldList.split(",");

  if (pFieldList.length == 1)
    return true;

  for (iField = 0; iField < pFieldList.length; iField++)
  {
    vControl[iField] = fnGetControls(trim(pFieldList[iField]))[0];

    if (vControl[iField] == undefined)
    {
      wsAlert("The field '" + trim(pFieldList[iField]) + "' supplied to function wsLookupChange is invalid.");

      return false;
    }

    if (iField == 0 && vControl[iField].value == "")
      return true;
  }

  for (iField = 0; iField < vControl.length; iField++)
  {
    if (vControl[iField] == pControl)
      continue;

    if (vControl[iField].tagName == "INPUT")
      vControl[iField].value = "";
    else
      vControl[iField].innerHTML = "";
  }

  return true;
}


