/* static variables */

/* Data type values */
_FT_BOOL = 16;
_FT_CHAR = 253;
_FT_DATE = 10;
_FT_TIME = 11;
_FT_INT = 3;
_FT_UINT = 3.1;
_FT_DEC1 = 0.1;
_FT_DEC2 = 0.2;
_FT_DEC3 = 0.3;

// field control constants
_CT_REQ = 101;   /* non-null value is required */
_CT_PULL = 102;  /* pulldown field with following 2 array elements: table-name, "field-val,field-desc" */

/* ======================================================================= */
/* add escape "\" for quote, double-quote and backwards slash */
function addslashes(textval) {
   return(textval.replace(/['"\\]/g, '\\$&'));
}
/* ======================================================================= */
/* Abbreviation for getElementById */
/* Also allows the element id object to be passed (just returns it) */
function eid(element)
{
if (typeof(element) == "string")
   return(document.getElementById(element));
else
    return(element);
}
/* ======================================================================= */
/* set a select element to its passed selection */
function set_select(element, matchvalue)
{
try {
    var i=0;
    var x = eid(element);
    while(i < x.length) {
         if (x.options[i].value == matchvalue)
         break;
         ++i;
    }
    x.selectedIndex = i;
}
catch(e) {
}
}
/* ======================================================================= */
/* set a radio or checkbox element to its passed checked status */
/* (use the group name; must be in order with initial value = 0) */
function set_radio(elementname, pos)
{
try {
    var x = document.getElementsByName(elementname);
    x[pos].checked = true;
}
catch(e) {
}
}
/* ======================================================================= */
/* clears all radio buttons in a group */
function clr_radio(radioname)
{
try {
   var x = document.getElementsByName(radioname);
   for (var i = 0; i < x.length; i++) {
      if (x[i].checked)
         x[i].checked = false;
   }
}
catch(e) {
}
}
/* ======================================================================= */
/* return the value of the radio button that is checked */
/* return an empty string if none are checked, or */
/* there are no radio buttons */
function getCheckedValue(radioObjName) {
    if (typeof(radioObjName) == 'string')
       var radioObj = document.getElementsByName(radioObjName);
    else
       var radioObj = radioObjName;
	if(!radioObj)
		return '';
	var radioLength = radioObj.length;
	if(radioLength == undefined) {
		if(radioObj.checked)
			return radioObj.value;
		else
			return '';
    }
	for(var i = 0; i < radioLength; i++) {
		if(radioObj[i].checked)
			return radioObj[i].value;
	}
	return '';
}
/* ======================================================================= */
/* set the radio button with the given value as being checked  */
/* do nothing if there are no radio buttons */
/* if the given value does not exist, all the radio buttons */
/* are reset to unchecked */
function setCheckedValue(radioObjName, newValue) {
    if (typeof(radioObjName) == 'string')
       var radioObj = document.getElementsByName(radioObjName);
    else
       var radioObj = radioObjName;
	if(!radioObj)
		return;
	var radioLength = radioObj.length;
	if(radioLength == undefined) {
		radioObj.checked = (radioObj.value == newValue.toString());
		return;
	}
	for(var i = 0; i < radioLength; i++) {
		radioObj[i].checked = false;
		if(radioObj[i].value == newValue.toString()) {
			radioObj[i].checked = true;
		}
	}
}
/* ======================================================================= */
/* clear related checkboxes if one in the group is checked */
/* call this routine with onclick=
/* pass the element object (this) followed by any number of related checkbox ids */
function clr_rel_ck(elemobj, related1, related2 /* ... */)
{
   if (elemobj.checked) {
      for (var i = 1; i < arguments.length; i++)
         eid(arguments[i]).checked = false;
   }
}
/* ======================================================================= */
/* changes a property of all child nodes */
function chg_node_prop(elem, propstr)
{
   if (typeof(elem) == 'string')
      var par = document.getElementById(elem);
   else
      var par = elem;
   for (var i = 0; i < par.childNodes.length; i++) {
      var node = par.childNodes[i];
      var propset = 'node.' + propstr;
//      alert(node.id + ' ' + propset);
      eval(propset);
   }
}
/* ======================================================================= */
/* convert rgb to hex equivalent */
function rgb(red, green, blue)
{
var decColor = blue + 256 * green + 65536 * red;
return decColor.toString(16);
}
/* ======================================================================= */
/* get the absolute X coordinate of an element */
function getX(e)
{
var x = 0;
while(e) {
x += e.offsetLeft;
e = e.offsetParent;
}
return x;
}
/* ======================================================================= */
/* get the absolute Y coordinate of an element */
function getY(e)
{
var y = 0;
while(e) {
y += e.offsetTop;
e = e.offsetParent;
}
return y;
}
/* ======================================================================= */
function Trim(str)
/* PURPOSE: Remove leading and trailing blanks from our string. */
/* IN: str - the string we want to Trim */
{
var whitespace = new String(" \t\n\r");
var s = new String(str);
if (whitespace.indexOf(s.charAt(0)) != -1) {
   /* We have a string with leading blank(s)... */
   var j=0, i = s.length;
   /* Iterate from the far left of string until we */
   /* don't have any more whitespace... */
   while (j < i && whitespace.indexOf(s.charAt(j)) != -1)
         j++;
   /* Get the substring from the first non-whitespace */
   /* character to the end of the string... */
   s = s.substring(j, i);
}
/* Remove trailing blanks */
i = s.length - 1;
while (i >= 0 && whitespace.indexOf(s.charAt(i)) != -1)
      i--;
if (i >= 0)
   s = s.substr(0, i + 1);
else
    s = "";
return s;
}
/* ======================================================================= */
/* Only allow number keys to be accepted */
/* Optionally may allow decimal point and minus sign and forward slash */
/* to call: onkeypress = return(isNumberKey(event)); */
function isNumberKey(evt, allowdecpoint, allowsign, allowslash)
{
   var keynum = 0;
   if(window.event) // IE
     keynum = evt.keyCode;
   else if(evt.which) // Netscape/Firefox/Opera
     keynum = evt.which;
   if (keynum < 32) /* accept control codes */
      return true;
   if (allowdecpoint && keynum == 46)  /* decimal point allowed */
      return true;
   if (allowsign && keynum == 45)   /* minus sign allowed */
      return true;
   if (allowslash && keynum == 47)   /* forward slash allowed */
      return true;
   if (keynum > 31 && (keynum < 48 || keynum > 57)) /* invalid character */
      return false;
   return true;
}
/* ======================================================================= */
/* Verify characters entered, only allowing specific characters */
/* to call: onkeypress = return(verifyChar(event, valid-chars)); */
function verifyChar(evt, valchars)
{
   var arrSpecialChars = new Array(0, 8, 9, 35, 36, 37, 38, 39, 40, 46);
   var keynum = 0;
   if(window.event) // IE
     keynum = evt.keyCode;
   else if(evt.which) // Netscape/Firefox/Opera
     keynum = evt.which;
   if (InArray(arrSpecialChars, keynum) >= 0) /* special characters OK */
      return true;
   var strChar = String.fromCharCode(keynum);
   return ((valchars.indexOf(strChar)) >= 0);
}
/* ======================================================================= */
/* return position of requested key in array */
/* returns -1 if not found */
function InArray(arr, key)
{
   for (var i=0; i<arr.length; i++) {
      if (arr[i] == key)
         return i;
   }
   return -1;
}
/* ======================================================================= */
/* Rounds a number to a specific number of digits after the decimal point */
/* Returns NaN if an invalid number */
function numRound(num, digits)
{
   var q = num - 0;   /* forces type to a number */
   return q.toFixed(digits);
}
/* ======================================================================= */
/* Validates/rounds a numeric field, returning FALSE if invalid */
/* The field is updated with the rounded number unless 'digits' is not numeric */
/* Optionally changes the color or background color of the element if invalid/valid */
/* (Pass '' to restore color, omit or pass null for no change) */
function numfldValidate(numfld, digits, errColor, validColor, errBkgColor, validBkgColor)
{
   var n = eid(numfld);
   if (typeof digits == 'number')
      var q = numRound(n.value, digits);
   else
      var q = n.value;
   if (isNaN(q)) {
      if (typeof errColor == 'string')
         n.style.color = errColor;
      if (typeof errBkgColor == 'string')
         n.style.backgroundColor = errBkgColor;
      return false;
   }
   else {
      if (typeof validColor == 'string')
         n.style.color = validColor;
      if (typeof validBkgColor == 'string')
         n.style.backgroundColor = validBkgColor;
      n.value = q;
      return true;
   }
}
/* ======================================================================= */
/* Checks if a number is between a range of numbers (returns true or false) */
/* Number should be validated first */
/* Optionally changes the color of the element if inrange or not */
/* (Pass '' to restore color, omit or pass null for no change) */
function numfldRange(numfld, minval, maxval, errColor, validColor, errBkgColor, validBkgColor)
{
   var n = eid(numfld);
   var nv = n.value - 0;
   if (nv >= minval && nv <= maxval) {
      if (typeof validColor == 'string')
         n.style.color = validColor;
      if (typeof validBkgColor == 'string')
         n.style.backgroundColor = validBkgColor;
      return true;
   }
   else {
      if (typeof errColor == 'string')
         n.style.color = errColor;
      if (typeof errBkgColor == 'string')
         n.style.backgroundColor = errBkgColor;
      return false;
   }
}
/* ======================================================================= */
/* Sets or clears the error text following an input field in a table element */
/* The field ID or object must be passed; can change the color and/or background color of the field */
/* (Pass '' to restore color, omit or pass null for no change) */
function setTblFldErr(fld, errText, errColor, validColor, errBkgColor, validBkgColor)
{
   var fset = eid(fld);
   var fv = fset.value;
   var fid = fset.id;
   var tset = fset.parentNode;
   var ihtml = tset.innerHTML;
   var ip = ihtml.toLowerCase().lastIndexOf('<input'); /* find end of last <input> element */
   if (ip == -1)
      ihtml = '';
   else {
      ip = ihtml.toLowerCase().indexOf('>', ip);
      if (ip == -1)
         ihtml = '';
      else
         ihtml = ihtml.substr(0, ip + 1);
   }
   if (errText == '') {  /* clear error */
      tset.innerHTML = ihtml;
      fset = eid(fid);
      fset.value = fv;  /* restore value */
      if (typeof validColor == 'string')
         fset.style.color = validColor;
      if (typeof validBkgColor == 'string')
         fset.style.backgroundColor = validBkgColor;
   }
   else {   /* set error */
      tset.innerHTML = ihtml + '<B style="color:red;"><I><small>&nbsp;&nbsp;' + errText + '</small></I></B>';
      fset = eid(fid);
      fset.value = fv;  /* restore value */
      if (typeof errColor == 'string')
         fset.style.color = errColor;
      if (typeof errBkgColor == 'string')
         fset.style.backgroundColor = errBkgColor;
   }
}
/* ======================================================================= */
/* Validates a list of fields passed in two arrays */
/* Returns true if all are valid; otherwise returns false */
/* (to restore colors to original value, use ''; to not change, use null) */
/* Parm 1: Array of required fields: */
/*    0 = field text color if error */
/*    1 = field text color if okay */
/*    2 = field background color if error */
/*    3 = field background color if okay */
/*  The following entries repeat for each field  */
/*    4 = field ID or object, 5 = error text if field is empty, 6 = repeat . . . */
/* Parm 2: Array of numeric fields: */
/*    0 to 3 = color settings (same as above) */
/*    4 = field ID or object, 1 = true if empty value is allowed, and keep empty, */
/*    5 = decimal positions to round to (if not a number, no rounding is done) */
/*    6 = error text if validation fails, */
/*    7 = minimum value, 5 = maximum value, */
/*    8 = error text if outside of allowed min-max (if empty string, use previous error text) */
/*    9 = repeat . . . */
function fldsValidate(reqarr, numarr)
{
   var allvalid = true;
   if (reqarr) {
      var errColor = reqarr[0];
      var okColor = reqarr[1];
      var errBkgColor = reqarr[2];
      var okBkgColor = reqarr[3];
      for (var i = 4; i < reqarr.length; i++) {
         var errtext = '';
         var f = eid(reqarr[i++]);
         f.value = Trim(f.value);
         if (f.value.length == 0) {  /* trimmed field is empty */
            allvalid = false;
            errtext = reqarr[i];
         }
         setTblFldErr(f, errtext, errColor, okColor, errBkgColor, okBkgColor);
      }
   }
   if (numarr) {
      var errColor = numarr[0];
      var okColor = numarr[1];
      var errBkgColor = numarr[2];
      var okBkgColor = numarr[3];
      for (var i = 4; i < numarr.length; i++) {
         errtext = '';
         f = eid(numarr[i++]);  /* field id or reference */
         f.value = Trim(f.value);
         if (numarr[i++] && f.value.length == 0) {  /* if empty & empty keep = true, skip field */
            i += 4;
            continue;
         }
         if (!(numfldValidate(f, numarr[i++], errColor, okColor, errBkgColor, okBkgColor))) {   /* validate & round */
            allvalid = false;
            errtext = numarr[i++];
            i += 2;
         }
         else if (!(numfldRange(f, numarr[++i], numarr[++i], errColor, okColor, errBkgColor, okBkgColor))) {   /* check range */
            allvalid = false;
            errtext = numarr[++i];
            if (errtext == '')    /* if no min-max error, use validation error */
               errtext = numarr[i - 3];
         }
         else
            ++i;
         setTblFldErr(f, errtext, errColor, okColor, errBkgColor, okBkgColor);
      }
   }
   return allvalid;
}
/* ======================================================================= */
/* Change the text of a node's first child */
/* Adds a text node if no child */
function updnodetxt(node, text) {
   if (node.firstChild == null) {
      var textnode = document.createTextNode(text);
      node.appendChild(textnode);
   } else
      node.firstChild.nodeValue = text;
}
/* ======================================================================= */
/* Replace HTML in a table row with IE workaround */
/* Each table row (<tr>) must be enclosed by <tbody> tags */
/* The <tbody> node is referenced by tbnode */
/* Htmlstr contains all HTML for the row, including the <tr> tag */
function replaceHTML(tbnode, htmlstr) {
   try {  // try innerHTML which works with Firefox, but not IE6
      tbnode.innerHTML = htmlstr;
   }
   catch(e) {   // build a temp node used to replace updated table row
      var tempnode = document.createElement("span");
      tempnode.style.visibility = 'hidden';
      tempnode.innerHTML = '<table><tbody id="tb_replace">' + htmlstr + '</tbody></table>';
      var tid = tbnode.id;
      tbnode.parentNode.replaceChild(tempnode.firstChild.firstChild, tbnode);
      var rnode = document.getElementById('tb_replace');
      rnode.id = tid;
   }
}
/* ======================================================================= */
/* Build radio selection entries, returning the table HTML */
/* First entry is 'clr' which will clear all entries if clicked */
/*   Parm 1 = name of radio group */
/*   Parm 2 = group description  */
/*   Parm 3 = group description style (default is vertical-align:top;border:0px none;) */
/*   Parm 4 = name of class to describe each table element */
/*    (example: .tradio {border:0px none;padding:0px;width:20px;text-align:center;font-size:75%;}) */
/*   Parm 5 = minimum value of entries (0 or greater) */
/*   Parm 6 = maximum value of entries */
/*   Parm 7 = value that should be selected (optional) */
/*   Parm 8 = style parameter of table (optional) */
function bldRadioslc(groupname, groupdesc, groupdescstyle, tclassname, minvalue, maxvalue, slcvalue, tblstyle) {
   var rhtml = '<table';
   if (tblstyle != undefined && tblstyle != '')
      rhtml += ' style="' + tblstyle + '"';
   rhtml += ' border="0" cellpadding="0" cellspacing="0"><tbody><tr>';
   if (groupdesc != '') {
      rhtml += '<td style="';
      if (groupdescstyle != '')
         rhtml += groupdescstyle + '">';
      else
         rhtml += 'vertical-align:top;border:0px none;">';
      rhtml += groupdesc + '</td>';
   }
   for (var i = minvalue; i <= maxvalue; i++) {
      rhtml += '<td class="' + tclassname + '"><input name="' + groupname + '" value="' +
               i + '" type="radio"';
      if (slcvalue != undefined && slcvalue == i)
         rhtml += ' checked="checked"';
      rhtml += '><br>' + i + '</td>';
   }
   rhtml += '<td class="' + tclassname + '"><input style="padding:0px;font-weight:bold;font-size:90%;color:yellow;background-color:rgb(255,128,128);" type="button" onclick="clr_radio(\'' + groupname + '\');" value="Clr"></td>';
   rhtml += '</tr></tbody></table>';
   return(rhtml);
}
/* ======================================================================= */
/* Returns an array of Date objects from an ISO date array */
function ISO_to_Date(ISOdates) {
   var a = new Array();
   for (var i = 0; i < ISOdates.length; i++) {
      var ISOdt = ISOdates[i];
      var d = new Date();
      d.setHours(0,0,0,0);
      d.setFullYear(ISOdt.substr(0,4));
      d.setMonth(ISOdt.substr(5,2) - 1);
      d.setDate(ISOdt.substr(8,2));
      a[i] = d;
   }
   return a;
}
/* ======================================================================= */
/* Returns an array of ISO dates from an array of Date objects */
function Date_to_ISO(Dates) {
   var a = new Array();
   for (var i = 0; i < Dates.length; i++) {
      d = Dates[i];
      dm = d.getMonth() + 1;
      if (dm <= 9)
         dm = '0' + dm.toString();
      dd = d.getDate();
      if (dd <= 9)
         dd = '0' + dd.toString();
      a[i] = d.getFullYear() + '-' + dm + '-' + dd;
   }
   return a;
}
/* ======================================================================= */
/* Load external script from a URL */
function LoadScript(url) {
   var e = document.createElement("script");
   e.setAttribute('type', 'text/javascript');
   e.setAttribute('src', url);
   document.getElementsByTagName('head')[0].appendChild(e);
}

/* ======================================================================= */
/* Custom alert that allows HTML text */
/***** NOTE: THIS IS JUST TEST CODE AND SHOULD NOT BE USED *****/
/* Script execution does NOT wait after execution */
/* URL path must be the path of images required (tp.png, alert.png) and may be relative */
/* URL path must include ending '/' */
function alertHTML(msg, title, button_text, url_path) {
   if (typeof(title) == 'undefined' || typeof(title) == 'object' || title == '')
      var a_title = "Alert";
   else
      var a_title = title;
   if (typeof(button_text) == 'undefined' || typeof(button_text) == 'object' || button_text == '')
      var a_button_text = 'OK';
   else
      var a_button_text = button_text;
   if (typeof(url_path) == 'undefined' || typeof(url_path) == 'object' || url_path == '')
      var a_url_path = '';
   else
      var a_url_path = url_path;
   d = document;
   if (d.getElementById("modalContainer")) return;  /* An alert is already on the page */
   mObj = d.getElementsByTagName("body")[0].appendChild(d.createElement("div"));  /* create container over entire body */
   mObj.id = "modalContainer";
   mObj.style.height = d.documentElement.scrollHeight + "px";
   mObj.style.backgroundColor = 'transparent';
   mObj.style.position = 'absolute';
   mObj.style.width = '100%';
   mObj.style.height = '100%';
   mObj.style.top = '0px';
   mObj.style.left = '0px';
   mObj.style.zIndex = 10000;
   mObj.style.backgroundImage = 'url(' + a_url_path + 'tp.png)';
   alertObj = mObj.appendChild(d.createElement("div"));   /* create div for alert box */
   alertObj.id = "alertBox";
   h1 = alertObj.appendChild(d.createElement("h1"));
   h1.appendChild(d.createTextNode(a_title)); /* add title line */
   h1.style.margin = 0;
   h1.style.font = 'bold 0.9em verdana, arial';
   h1.style.backgroundColor = '#78919B';
   h1.style.color = '#FFF';
   h1.style.borderBottom = '1px solid #000';
   h1.style.padding = '2px 0 2px 5px';
   alertObj.innerHTML += '<p style="font:0.7em verdana,arial;height:50px;padding-left:5px;margin-left:55px;">' + msg + '</p>'; /* add message HTML text */
   alertObj.style.position = 'fixed';
   alertObj.style.width = '300px';
   alertObj.style.minHeight = '100px';
   alertObj.style.marginTop = '50px';
   alertObj.style.border = '2px solid #000';
   alertObj.style.backgroundColor = '#F2F5F6';
   alertObj.style.backgroundImage = 'url(' + a_url_path + 'alert.png)';
   alertObj.style.backgroundRepeat = 'no-repeat';
   alertObj.style.backgroundPosition = '20px 30px';
   if(d.all && !window.opera) alertObj.style.top = document.documentElement.scrollTop + "px";
   alertObj.style.left = (d.documentElement.scrollWidth - alertObj.offsetWidth)/2 + "px";
   alertObj.style.visiblity="visible";
   btn = alertObj.appendChild(d.createElement("a"));   /* build OK button */
   btn.id = "closeBtn";
   btn.appendChild(d.createTextNode(a_button_text));
   btn.href = "#";
   btn.style.display = 'block';
   btn.style.position = 'relative';
   btn.style.margin = '5px auto';
   btn.style.padding = '3px';
   btn.style.border = '2px solid #000';
   btn.style.width = '70px';
   btn.style.font = '0.7em verdana,arial';
   btn.style.textAlign = 'center';
   btn.style.color = '#FFF';
   btn.style.backgroundColor = '#78919B';
   btn.style.textDecoration = 'none';
   btn.focus();
   btn.onclick = function() { removeCustomAlert();return false; }
   alertObj.style.display = "block";
}
function removeCustomAlert() {
	document.getElementsByTagName("body")[0].removeChild(document.getElementById("modalContainer"));
}

