var TypeAheadInfo = {
   last: 0,
   current: "",
   delay: 500,
   timeout: null,
   reset: function() { this.last = 0; this.current = ""; }
};

function DualSubmitCheck(frm) {
   var bOk = event.returnValue;

   if (bOk) {
      var oSubmitted = frm.attributes['Submitted'];

      if ((oSubmitted != null) && (oSubmitted.value == 'True')) {
         bOk = false;
         alert('Already submitted.');
      }
      else if ((typeof(Page_IsValid) == 'undefined') || Page_IsValid) {
         //bOk = true;
         frm.attributes['Submitted'].value = 'True';
      }
   }

   event.returnValue = bOk;
   return bOk;
}

// validator to post back only if all validators succeed (used by AutoPostBackValidator)
function AutoPostBackValidatorEvaluate(val) {
   var bIsValid = true;
   var ctl = document.getElementById(val.controltovalidate);
   var aVals = ctl.Validators;

   for (var i = 0; i < aVals.length; i++) {
      if (!aVals[i].isvalid) {
         bIsValid = false;
         break;
      }
   }

   if (bIsValid) IGPostBack(ctl.id, '');
      else return true;
}

// DropFilter methods
function DropFilterValidatorEvaluate(val) {
   var bIsValid = true;
   var ddf = document.getElementById(val.controltoupdate);
   var ddl = document.getElementById(val.controltoupdate + '_ddl');

   var sConnKey    = ddf.attributes['ConnectionKey'].value;
   var sSource     = ddf.attributes['Source'].value;
   var sFilter     = ddf.attributes['Filter'].value;
   var sDfltFilter = ddf.attributes['DefaultFilter'].value;
   var sSort       = ddf.attributes['Sort'].value;
   var sDataValue  = ddf.attributes['DataValue'].value;
   var sDataText   = ddf.attributes['DataText'].value;

   // get value of each control
   // replace variables
   try {
      var bAllBlankFilters = true;
      var sControlID;
      var sControlValue;
      var ctl;

      i1 = sFilter.indexOf('{');

      while (i1 >= 0) {
         i2 = sFilter.indexOf('}', i1 + 1);

         if (i2 >= i1) {
            sControlID = sFilter.substring(i1 + 1, i2);
            sControlValue = '';

            if (sControlID.substring(0, 1) == '?') {
               // skip for now -- will be implemented on server by RSExecute below
               i1 = sFilter.indexOf('{', i1 + 1);
            }
            else {
               ctl = document.getElementById(sControlID.split(':').join('_'));
               sControlValue = ctl.value;

               sFilter = sFilter.replace('{' + sControlID + '}', sControlValue);
               i1 = sFilter.indexOf('{', i1 + sControlValue.length + 1);
               bAllBlankFilters = bAllBlankFilters && (sControlValue == '');
            }
         }
         else i1 = -1;
      }

      var result = RSExecute(INTEGRA_CLIENT_PATH + 'UtilityRS.aspx', 'DropFilter_Retrieve', sConnKey, sSource, bAllBlankFilters ? sDfltFilter : sFilter, sSort, sDataValue, sDataText);
      bIsValid = (result.status == MSRS_COMPLETED);

      if (bIsValid) {
         var sSelItem = null;
         var s = result.return_value;

         if (ddl.selectedIndex >= 0) sSelItem = ddl.options[ddl.selectedIndex].value;
         RemoveFromList(ddl, true);

         if (ddf.attributes['BlankItem'].value == 'True') {
            var sBlankValue = ddf.attributes['BlankValue'].value;
            var sBlankText  = ddf.attributes['BlankText'].value;
            s = sBlankValue + ';' + sBlankText + ((s != '') ? '|' : '') + s;
         }

         AddListItems(ddl, s, sSelItem);
      }
   }
   catch (ex) {
      alert(ex.message);
      bIsValid = false;
   }

   return bIsValid;
}

// Client-Side Navigation (not yet implemented)
function ReturnToCaller(vsID) {
   var result = RSExecute(INTEGRA_CLIENT_PATH + 'UtilityRS.aspx', 'ReturnToCaller', vsID);
   window.location.href = sUrl;
}

function DateDiff(earlyDate,laterDate) {
   // returns number of days between two date objects
   var earlySecs=earlyDate.getTime();
   var laterSecs=laterDate.getTime();
   return Math.floor ((((((laterSecs-earlySecs)/1000)/60)/60)/24));
}

function LTrim(vsStr) {
   if (vsStr != null) {
      while ((vsStr != '') && (vsStr.substring(0, 1) == ' ')) {
         vsStr = vsStr.substring(1);
      }
   }

   return vsStr;
}

function RTrim(vsStr) {
   if (vsStr != null) {
      while ((vsStr != '') && (vsStr.substring(vsStr.length - 1) == ' ')) {
         vsStr = vsStr.substring(0, vsStr.length - 1);
      }
   }

   return vsStr;
}

function Trim(vsStr) {
   vsStr = LTrim(vsStr);
   vsStr = RTrim(vsStr);
   return vsStr;
}

function HelpCheck(vsHelpCode) {
   try {
      ShowHelp(vsHelpCode);
      event.keyCode = 0;
      event.cancelBubble = true;
      event.returnValue = false;
      return false;
   }
   catch (ex) {
      // allow normal help to execute
   }
}

// TODO: 
function TypeAhead() {
   if (window.event && !window.event.ctrlKey) {
      var dtNow = new Date();

      if ((TypeAheadInfo.current == "") || (dtNow - TypeAheadInfo.last < TypeAheadInfo.delay)) {
         var lst = event.srcElement;
         var nKeyCode = event.keyCode;

		   // The NumPad returns slightly differant nKeyCodes then the numbers on the type of the keyboard.
		   // If we subtract 48 it will return the correct nKeyCode.
		   if ((nKeyCode >= 96) && (nKeyCode <= 105)) nKeyCode -= 48;

         if ((nKeyCode == 8) || (nKeyCode == 32)  || (nKeyCode >= 48  && nKeyCode <= 90) || 
             (nKeyCode >= 106 && nKeyCode <= 111) || (nKeyCode >= 186 && nKeyCode <= 222)) {

            if (nKeyCode == 8) {
               TypeAheadInfo.current = TypeAheadInfo.current.substring(0, TypeAheadInfo.current.length - 1);
            }
            else {
               var newChar = String.fromCharCode(nKeyCode).toUpperCase();
               TypeAheadInfo.current += newChar;
            }

            var sText;
            var nNearest;

            for (var i = 0; i < lst.options.length; i++) {
               // change this from .text to .value to use the value of the item instead of the visual text if desired
               sText = lst.options[i].text.toUpperCase();
               nNearest = (TypeAheadInfo.current > sText.substring(0, TypeAheadInfo.current.length)) ? i : nNearest;

               if (sText.indexOf(TypeAheadInfo.current) == 0) {
                  clearTimeout(TypeAheadInfo.timeout);
                  TypeAheadInfo.last = dtNow;
                  TypeAheadInfo.timeout = setTimeout("TypeAheadInfo.reset()", TypeAheadInfo.delay);
                  lst.selectedIndex = i;

                  event.cancelBubble = true;
                  event.returnValue = false;

                  return false;
               }
            }

            if (nNearest != null) lst.selectedIndex = nNearest;
         }
         else {
            clearTimeout(TypeAhead.timeout);
         }
      }  // if ((TypeAheadInfo.current == "") || ...
      else {
         clearTimeout(TypeAheadInfo.timeout);
      }

      TypeAheadInfo.reset();
   }

   return true;
}

// attributes
function GetAttribute(ctl, vsAttr, voDefault) {
   if ((ctl != null) && (ctl.attributes[vsAttr])) {
      return ctl.attributes[vsAttr].value;
   }
   return voDefault;
}

function SetAttribute(ctl, vsAttr, voValue) {
   if (ctl == null) return;

   if (ctl.attributes[vsAttr] == null) {
      var a = document.createAttribute(vsAttr);
      ctl.attributes.setNamedItem(a);
   }

   ctl.attributes[vsAttr].value = voValue;
}

// style/class management
function RemoveClassName(ctl, vsName) {
   if (ctl.className == null) return;

   // Remove the given class name from the element's className property.
   var aNewList = new Array();
   var aCurList = ctl.className.split(" ");

   for (var i = 0; i < aCurList.length; i++) {
      if (aCurList[i] != vsName) aNewList.push(aCurList[i]);
   }

   ctl.className = aNewList.join(" ");
}

// QueryString management
function AppendQueryString(vsUrl, vsQueryString) {
   if ((vsQueryString == null) || (vsQueryString == '')) return vsUrl;

   var n = vsQueryString.indexOf('=');
   if (n < 0) return vsUrl;

   var s = vsQueryString.substring(0, n);
   if ((vsUrl.indexOf('&' + s + '=') >= 0) || (vsUrl.indexOf('?' + s + '=') >= 0)) return vsUrl;

   return vsUrl + ((vsUrl.indexOf('?') < 0) ? '?' : '&') + vsQueryString;
}

function RemoveQueryString(vsUrl, vsQueryKey) {
   if ((vsQueryKey == null) || (vsQueryKey == '')) return vsUrl;

   var n = vsUrl.indexOf('&' + vsQueryKey + '=');
   if (n < 0) n = vsUrl.indexOf('?' + vsQueryKey + '=');

   if (n >= 0) {
      var s = vsUrl.substring(n + 2 + vsQueryKey.length);
      vsUrl = vsUrl.substring(0, n + 1);
      n = s.indexOf('&');
      if (n >= 0) vsUrl += s.substring(n + 1);
      var c = vsUrl.substring(vsUrl.length - 1, vsUrl.length);
      if ((c == '?') || (c == '&')) vsUrl = vsUrl.substring(0, vsUrl.length - 1);
   }

   return vsUrl;
}

function ReplaceQueryString(vsUrl, vsQueryString) {
   if ((vsQueryString == null) || (vsQueryString == '')) return vsUrl;

   var n = vsQueryString.indexOf('=');
   if (n < 0) return vsUrl;

   var s = RemoveQueryString(vsUrl, vsQueryString.substring(0, n));
   s = AppendQueryString(s, vsQueryString);
   return s;
}

function GetQueryStringItem(vsKey) {
   vsKey = vsKey.toUpperCase();
   var sSearch = document.location.search;
   var i = sSearch.toUpperCase().indexOf(vsKey);

   if (i == -1) return null;

   sSearch = sSearch.substring(i + vsKey.length);
   i = sSearch.indexOf('&');
   if (i >= 0) sSearch = sSearch.substring(0,i);

   return sSearch;
}

// positioning methods
function findPosX(obj) {
   var curleft = 0;

   if (obj.offsetParent) {
      while (obj.offsetParent) {
         curleft += obj.offsetLeft
         obj = obj.offsetParent;
      }
   }
   else if (obj.x) curleft += obj.x;

   return curleft;
}

function findPosY(obj) {
   var curtop = 0;

   if (obj.offsetParent) {
      while (obj.offsetParent) {
         curtop += obj.offsetTop
         obj = obj.offsetParent;
      }
   }
   else if (obj.y) curtop += obj.y;

   return curtop;
}

// display of windowed controls
function ShowHideDDL(visibility) {
   for (i = 0; i < document.forms[0].elements.length; i++) {
      if (document.forms[0].elements[i].type.indexOf('select') == 0)
         document.forms[0].elements[i].style.visibility = visibility;
   }
}

// Control to Click on Enter
function ControlToClickOnEnter(e, ctlName){ 
   var ctl = document.getElementById(ctlName);

   if (ctl != null) {
      if (navigator.appName.indexOf("Netscape") > (-1)) {
            if (e.keyCode == 13) {
            ctl.click();
            return false;
         }
      }

      if (navigator.appName.indexOf("Microsoft Internet Explorer") > (-1)) {
         if (event.keyCode == 13) {
            event.cancelBubble = true;
            event.returnValue = false;
            ctl.click();
            return false;
         }
      }
   }
}

function IgnoreBackspaceNavigation(evt) {
   var e;
   var ctl;
   var key;

   if (navigator.appName.indexOf('Microsoft Internet Explorer') >= 0) {
      e = window.event;
      ctl = event.srcElement;
      key = event.keyCode;
   }
   else {
      e = evt;
      ctl = evt.target;
      key = evt.which;
   }

   var b = (ctl.tagName.toUpperCase() == 'INPUT');
   if (b) b = (ctl.type == 'text') || (ctl.type == 'password') || (ctl.type == 'file');
   if (!b) b = (ctl.tagName.toUpperCase() == 'TEXTAREA');

   if (!b && (key == 8)) {
      if (e.cancelBubble) e.cancelBubble = true;
      if (e.returnValue) e.returnValue = false;
      if (e.stopPropagation) e.stopPropagation();
      return false;
   }
}

// delete confirmation
function ConfirmDelete(sMessage,img) {
   var sOldImage = '';
   if (img != null) {
      sOldImage = img.src;
      img.src = INTEGRA_CLIENT_PATH + 'delete-ani.gif';
   }
   if ((sMessage == null) || (sMessage == '')) sMessage = 'Are you sure you want to delete this item?';
   var x = confirm(sMessage);
   if (img != null) img.src = sOldImage;
   return x;
}

function ConfirmGridDelete(sMessage,trName,tblName) {
   var tr = document.getElementById(trName);
   var tbl = document.getElementById(tblName);
   var sItemCss;

   if (tr != null) {
      sItemCss = tr.className;
      if (tbl != null) tr.className = tbl.SelCss;
   }

   if ((sMessage == null) || (sMessage == '')) sMessage = 'Are you sure you want to delete this item?';
   var x = confirm(sMessage);
   if (tr != null) tr.className = sItemCss;
   return x;
}

// grid methods
function GridSelectionCheck(sPrefix,sSuffix,bValue) {
   var bOkToCheck;
   var i;
   var n;
   var ctl;
   var sCtlName;
   var sOnClick;

   sPrefix = sPrefix.toUpperCase();
   sSuffix = sSuffix.toUpperCase();

   for (i = 0; i < document.forms[0].elements.length; i++) {
      ctl = document.forms[0].elements[i];
      sCtlName = ctl.name.toUpperCase();
      bOkToCheck = false;

      if (sCtlName.indexOf(sPrefix) == 0) {
         if (sSuffix != '') {
            n = sCtlName.lastIndexOf(sSuffix);
            if (n >= 0) sCtlName = sCtlName.substring(n);
            if (sCtlName == sSuffix) bOkToCheck = (ctl.checked != bValue);
         }
         else bOkToCheck = (ctl.checked != bValue);

         if (bOkToCheck) {
            try {
               ctl.checked = bValue;
               sOnClick = ctl.attributes["onclick"].value;
               if ((sOnClick != null) && (sOnClick != "")) eval(sOnClick);
            }
            catch (ex) {
               // ignore
            }
         }
      }
   }

   return false;
}

function ToggleNestedGrid(hidID) {
   var sID = hidID.split(":").join("_");
   var hid = document.getElementById(sID);
   var img = document.getElementById(sID + '_img');

   var sStatus = hid.value;

   if (sStatus.substring(0, 1) == 'N') {
      hid.value = 'L1';
      __doPostBack('', '');
   }
   else {
      var bOpen       = (sStatus.substring(1, 2) == '1');
      var asGridNames = img.attributes['GridNames'].value.split('|');
      var row;

      for (var i = 0; i < asGridNames.length; i++) {
         row = document.getElementById(sID + '_row' + asGridNames[i]);
         if (row != null) row.style.display = bOpen ? 'none' : '';
      }

      hid.value = bOpen ? 'L0' : 'L1';

      if (bOpen) img.src = img.src.replace('minus', 'plus');
         else img.src = img.src.replace('plus', 'minus');
   }

   return false;
}

// date & time validation (.NET validator)
function ValidateDateNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes["PromptText"]) {
         sPromptText = ctl.attributes["PromptText"].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         ctl.value = sPromptText;
         arguments.IsValid = true;
         return true;
      }
      else {
         var bForceDelim = false;  //(source.attributes["ForceDelim"].value == 'True');
         var dtDate = ValidateDate(arguments.Value, bForceDelim);

         if (dtDate != null) {
            var sDisplayFmt = ctl.attributes["DisplayFormat"].value;
            ctl.value = FormatDate(dtDate, sDisplayFmt);
            arguments.IsValid = true;
            return true;
         }
         else if (ctl.value == '') {
            arguments.IsValid = true;
            return true;
         }
         else {
            arguments.IsValid = false;
            return false;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

// time only validation (.NET validator)
function ValidateTimeNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes["PromptText"]) {
         sPromptText = ctl.attributes["PromptText"].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         ctl.value = sPromptText;
         arguments.IsValid = true;
         return true;
      }
      else {
         var bForceDelim = false;  //(source.attributes["ForceDelim"].value == 'True');
         var dtTime = ValidateTime(arguments.Value, bForceDelim);

         if (dtTime != null) {
            var sDisplayFmt = ctl.attributes["DisplayFormat"].value;
            ctl.value = FormatTime(dtTime, sDisplayFmt);
            arguments.IsValid = true;
            return true;
         }
         else if (ctl.value == '') {
            arguments.IsValid = true;
            return true;
         }
         else {
            arguments.IsValid = false;
            return false;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

// date & time validation (for Grid)
function ValidateDateGrid(ctl) {
   var bIsValid = true;

   try {
      var dtDate = ValidateDate(ctl.value, false);

      if (dtDate != null) {
         var sDisplayFmt = ctl.attributes["DisplayFormat"].value;
         ctl.value = FormatDate(dtDate, sDisplayFmt);
      }
   }
   catch (ex) {
      bIsValid = false;
   }

   return bIsValid;
}

// time only validation (for Grid)
function ValidateTimeGrid(ctl) {
   var bIsValid = true;

   try {
      var dtTime = ValidateTime(ctl.value, false);

      if (dtTime != null) {
         var sDisplayFmt = ctl.attributes["DisplayFormat"].value;
         ctl.value = FormatTime(dtTime, sDisplayFmt);
      }
   }
   catch (ex) {
      bIsValid = false;
   }

   return bIsValid;
}

// date range validation (.NET validation)
function ValidateDateRangeNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes["PromptText"]) {
         sPromptText = ctl.attributes["PromptText"].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         arguments.IsValid = true;
         return true;
      }
      else {
         var dtDate = ValidateDate(arguments.Value, false);

         if (dtDate != null) {
            var ctl = document.getElementById(source.controltovalidate);
            var i = ctl.id.lastIndexOf("_");
            if (i >= 0) i = ctl.id.lastIndexOf("_", i - 1);
            var sPrefix = (i >= 0) ? ctl.id.substring(0, i + 1) : "";

            var dt;
            var dtMinDate = new Date(source.MinValue);
            var dtMaxDate = new Date(source.MaxValue);

            var sMinCtl = source.MinValueCtl;
            var sMaxCtl = source.MaxValueCtl;

            if (sMinCtl != '') {
               var ctlMin = document.getElementById(sPrefix + sMinCtl + '_txt');
               if (ctlMin != null) {
                  dt = ValidateDate(ctlMin.value, false);
                  if (dt != null) dtMinDate = dt;
               }
            }

            if (sMaxCtl != '') {
               var ctlMax = document.getElementById(sPrefix + sMaxCtl + '_txt');
               if (ctlMax != null) {
                  dt = ValidateDate(ctlMax.value, false);
                  if (dt != null) dtMaxDate = dt;
               }
            }

            arguments.IsValid = ((dtDate >= dtMinDate) && (dtDate <= dtMaxDate));
            return arguments.IsValid;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

function StripPunctuation(sStr, bAllowLetters, bAllowNumbers, bAllowSpaces) {
   var i;
   var c;
   var sNew = '';

   for (i = 0; i < sStr.length; i++) {
      c = sStr.substring(i, i + 1).toUpperCase();

      if ((bAllowLetters && (c >= 'A') && (c <= 'Z')) || 
          (bAllowNumbers && (c >= '0') && (c <= '9')) || 
          (bAllowSpaces && (c == ' '))) {
         sNew += c;
      }
   }

   return sNew;
}

function ValidateDate(sDate, bForceDelim) {
   try {
      var dt = new Date();
      sDate = RTrim(sDate);
      if ((sDate == null) || (sDate == '')) return null;
      if (sDate.toLowerCase() == 'n') return dt;

      var dtTime = null;
      var nMonth, nDay, nYear;
      var sMonth, sDay, sYear;
      var bSpaceDelim = false;

      // strip off weekday
      var i = sDate.indexOf(",");
      if (i >= 0) sDate = sDate.substring(i + 1);
      
      // assume: month day [year] format
      var i1 = sDate.indexOf("/");
      if (i1 < 0) i1 = sDate.indexOf("-");
      if (i1 < 0) i1 = sDate.indexOf(".");
      if (i1 < 0) { i1 = sDate.indexOf(" "); bSpaceDelim = true; }

      if ((i1 < 0) && (sDate.length > 1)) {
         if ((sDate.toLowerCase().substring(0, 1) == 't') || (sDate.toLowerCase().substring(0, 1) == 'y')) {
            sDate = sDate.substring(0, 1) + ' ' + sDate.substring(1);
            i1 = 1;
            bSpaceDelim = true;
         }
      }

      if ((i1 < 0) && bForceDelim) return null;

      if (i1 < 0) {
         // no punctuation -- assume MMddyyyy format
         sDate = StripPunctuation(sDate, true, true, false);
         sYear = dt.getFullYear().toString();

         switch (sDate.length) {
            case 1:
               switch (sDate.toLowerCase()) {
                  case 't':
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     break;

                  case 'y':
                     dt = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate() - 1);
                     sDay   = dt.getDate().toString();
                     nMonth = dt.getMonth() + 1;
                     sMonth = nMonth.toString();
                     break;

                  default: throw "bad date entry";
               }
               break;

            case 2:
            case 3:
               sMonth = sDate.substring(0, 1);
               sDay   = sDate.substring(1);
               break;

            case 4:
               sMonth = sDate.substring(0, 2);
               sDay   = sDate.substring(2, 4);
               break;

            // if 5 or 7 digits, make 6 or 8 and fall through
            case 5:
            case 7:
               sDate = '0' + sDate;

            case 6:
            case 8:
               sMonth = sDate.substring(0, 2);
               sDay   = sDate.substring(2, 4);
               sYear  = sDate.substring(4);
               break;

            default: throw "bad date entry";
         }

         if ((sMonth.length > 1) && (sMonth.substring(0, 1) == '0')) sMonth = sMonth.substring(1);
         if ((sDay.length   > 1) && (sDay.substring(0, 1)   == '0')) sDay   = sDay.substring(1);
         while ((sYear.length > 1) && (sYear.substring(0, 1) == '0')) sYear = sYear.substring(1);

         nMonth = parseInt(sMonth);
         nDay   = parseInt(sDay);
         nYear  = parseInt(sYear);

         if ((nMonth <= 0) || (nMonth > 12) || (nDay <= 0) || (nDay > 31)) throw "bad date entry";

         if (nYear < 100) {
            var nCentury = parseInt(dt.getFullYear().toString().substring(0, 2) + '00');
            if (nYear > 50) nCentury -= 100;
            nYear += nCentury;
            sYear = nYear.toString();
         }

         sMonth = nMonth.toString();
         sDay   = nDay.toString();
         sYear  = nYear.toString();
      }
      else {
         var i2 = sDate.indexOf("/", i1 + 1);
         if (i2 == -1) i2 = sDate.indexOf("-", i1 + 1);
         if (i2 == -1) i2 = sDate.indexOf(".", i1 + 1);
         if (i2 == -1) {
            i2 = sDate.indexOf(" ", i1 + 1);

            if ((i2 >= 0) && !bSpaceDelim) {
               dtTime = ValidateTime(sDate.substring(i2 + 1), false);
               if (dtTime == null) throw "bad time entry";
               sDate = sDate.substring(0, i2);
               i2 = -1;
            }
         }

         sMonth = sDate.substring(0, i1).toLowerCase();

         if ((sMonth == 't') || (sMonth == 'y')) {
            nDay   = dt.getDate() - (sMonth == 'y' ? 1 : 0);
            sDay   = nDay.toString();
            nMonth = dt.getMonth() + 1;
            sMonth = nMonth.toString();
            sYear  = dt.getFullYear().toString();
            dtTime = ValidateTime(sDate.substring(i1 + 1), false);
            if (dtTime == null) throw "bad time entry";
         }
         else if (i2 >= 0) {
            var i3 = sDate.indexOf(" ", i2 + 1);
            if (i3 >= 0) {
               dtTime = ValidateTime(sDate.substring(i3 + 1), false);
               if (dtTime == null) throw "bad time entry";
               sDate = sDate.substring(0, i3);
            }

            sDay = sDate.substring(i1 + 1, i2);
            sYear = sDate.substring(i2 + 1);
            while ((sYear.length > 0) && (sYear.substring(0, 1) == '0')) sYear = sYear.substring(1);
            if (sYear.length == 0) sYear = dt.getFullYear().toString();

            try {
               nYear = parseInt(sYear);

               if (nYear < 100) {
                  var nCentury = parseInt(dt.getFullYear().toString().substring(0, 2) + '00');
                  if (nYear > 50) nCentury -= 100;
                  nYear += nCentury;
                  sYear = nYear.toString();
               }
            }
            catch (ex) {
               sYear = dt.getFullYear();
            }
         }
         else {
            sDay = sDate.substring(i1 + 1);
            sYear = dt.getFullYear().toString();
         }
      }

      try {
         var s = sMonth.substring(0, 1);
         var b = (s >= "0") && (s <= "9");

         if (dtTime != null) s = ' ' + FormatTime(dtTime, 'hh:mm:ss tt');
            else s = '';

         if ((sMonth.length > 1) && (sMonth.substring(0, 1) == '0')) sMonth = sMonth.substring(1);
         if ((sDay.length   > 1) && (sDay.substring(0, 1)   == '0')) sDay   = sDay.substring(1);

         nMonth = parseInt(sMonth);
         nDay = parseInt(sDay);
         dt = new Date(sMonth + (b ? '/' : ' ') + sDay + (b ? '/' : ', ') + sYear + s);
         if ((nDay != dt.getDate()) || (b && (nMonth != dt.getMonth() + 1))) return null;
         return dt;
      }
      catch (ex) {
         return null;
      }
   }
   catch (ex) {
      return null;
   }
}

function ValidateTime(sTime, bForceDelim) {
   try {
      sTime = Trim(sTime).toUpperCase();
      if ((sTime == null) || (sTime == '')) return null;

      var sHour, sMin;
      var sSec = '0';
      var sTT = '';
      var i1 = sTime.length;

      if ((sTime.length > 2) && ((sTime.substring(i1 - 1) == 'A') || (sTime.substring(i1 - 1) == 'P'))) {
         sTT = sTime.substring(i1 - 1) + 'M';
         Trim(sTime = sTime.substring(0, i1 - 1));
      }
      else if ((sTime.length > 3) && ((sTime.substring(i1 - 2) == 'AM') || (sTime.substring(i1 - 2) == 'PM'))) {
         sTT = sTime.substring(i1 - 2);
         sTime = Trim(sTime.substring(0, i1 - 2));
      }

      i1 = sTime.indexOf(":");
      if (i1 < 0) i1 = sTime.indexOf(".");
      if (i1 < 0) i1 = sTime.indexOf("-");

      if ((i1 < 0) && bForceDelim) return null;

      if (i1 < 0) {
         i1 = sTime.indexOf(" ");

         if (i1 >= 0) {
            sTT = sTime.substring(i1 + 1);
            sTime = sTime.substring(0, i1);
         }

         switch (sTime.length) {
            // make 2 digits and fall through
            case 1: sTime = '0' + sTime;

            case 2:
               nHour = parseInt(sTime);
               if (nHour < 24) {
                  sHour = sTime;
                  sMin  = '0';
               }
               else {
                  sHour = sTime.substring(0, 1);
                  sMin  = sTime.substring(1);
               }
               break;

            // make 4 digits and fall through
            case 3: sTime = '0' + sTime;

            case 4:
               sHour = sTime.substring(0, 2);
               sMin  = sTime.substring(2);
               break;

            // make 6 digits and fall through
            case 5: sTime = '0' + sTime;

            case 6:
               sHour = sTime.substring(0, 2);
               sMin  = sTime.substring(2, 4);
               sSec  = sTime.substring(4);
               break;

            default: return null;
         }
      }
      else {
         sTime = sTime.replace(".", ":");
         sTime = sTime.replace("-", ":");

         i1 = sTime.indexOf(" ");
         if (i1 >= 0) {
            sTT = sTime.substring(i1);
            sTime = sTime.substring(0, i1);
         }

         var asParts = sTime.split(":");
         if (asParts.length > 4) throw "bad time entry";

         sHour = Trim(asParts[0]);
         sMin  = Trim(asParts[1]);
         if (asParts.length > 2) sSec = Trim(asParts[2]);

         if (sMin  == '') sMin = '0';
         if (sSec  == '') sSec = '0';
         if (sHour == '') throw "bad time entry";
      }

      // strip leading zeros -- parseInt doesn't like them
      if ((sHour.length > 1) && (sHour.substring(0, 1) == '0')) sHour = sHour.substring(1);
      if ((sMin.length  > 1) && (sMin.substring(0, 1)  == '0')) sMin  = sMin.substring(1);
      if ((sSec.length  > 1) && (sSec.substring(0, 1)  == '0')) sSec  = sSec.substring(1);

      var nHour = parseInt(sHour);
      var nMin  = parseInt(sMin);
      var nSec  = parseInt(sSec);

      if ((sTT != '') && ((nHour < 1) || (nHour > 12))) return null;
      if ((sTT == '') && ((nHour < 0) || (nHour > 23))) return null;
      if ((nMin < 0) || (sMin > 59) || (sSec < 0) || (sSec > 59)) return null;

      var dt = new Date(Date.parse('01/01/2000 ' + sHour + ':' + sMin + ':' + sSec + ' ' + sTT));
      return isNaN(dt.getHours()) ? null : dt;
   }
   catch (ex) {
      alert(ex);
      return null;
   }
}

function FormatDate(dtDate, sFormat) {
   var i;
   var sResult = sFormat;
   
   if (isNaN(dtDate.getMonth())) return '';

   // check for full month name
   i = sResult.indexOf('MMMM');
   if (i >= 0) {
      var asFullMonth = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
      sResult = sResult.substring(0, i) + 'asFullMonth[dtDate.getMonth()]' + sResult.substring(i + 4);
   }

   // check for abbreviated month name
   i = sResult.indexOf('MMM');
   if (i >= 0) {
      var asAbbrevMonth = new Array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
      sResult = sResult.substring(0, i) + asAbbrevMonth[dtDate.getMonth()] + sResult.substring(i + 3);
   }

   // check for two-digit month number
   i = sResult.indexOf('MM');
   if (i >= 0) {
      var nMonth = dtDate.getMonth() + 1;
      sResult = sResult.substring(0, i) + ((nMonth < 10) ? '0' : '') + nMonth.toString() + sResult.substring(i + 2);
   }

   // check for one-digit month number
   i = sResult.indexOf('M');
   if (i >= 0) {
      var nMonth = dtDate.getMonth() + 1;
      sResult = sResult.substring(0, i) + nMonth.toString() + sResult.substring(i + 1);
   }

   // check for full weekday
   i = sResult.indexOf('dddd');
   if (i >= 0) {
      var asFullWeekday = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
      sResult = sResult.substring(0, i) + asFullWeekday[dtDate.getDay()] + sResult.substring(i + 4);
   }

   // check for abbreviated weekday
   i = sResult.indexOf('ddd');
   if (i >= 0) {
      var asAbbrevWeekday = new Array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
      sResult = sResult.substring(0, i) + asAbbrevWeekday[dtDate.getDay()] + sResult.substring(i + 3);
   }

   // check for two-digit day
   i = sResult.indexOf('dd');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtDate.getDate() < 10) ? '0' : '') + dtDate.getDate().toString() + sResult.substring(i + 2);
   }

   // check for one-digit day
   i = sResult.indexOf('d');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtDate.getDate().toString() + sResult.substring(i + 1);
   }

   // check for four-digit year
   i = sResult.indexOf('yyyy');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtDate.getFullYear().toString() + sResult.substring(i + 4);
   }

   // check for four-digit year
   i = sResult.indexOf('yy');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtDate.getFullYear().toString().substring(2) + sResult.substring(i + 2);
   }

   // check for four-digit year
   i = sResult.indexOf('y');
   if (i >= 0) {
      var sYear = dtDate.getFullYear().toString();
      var nYear = parseInt(sYear.substring(2));
      sResult = sResult.substring(0, i) + nYear.toString() + sResult.substring(i + 1);
   }

   sResult = FormatTime(dtDate, sResult);
   return sResult;
}

function FormatTime(dtTime, sFormat) {
   var i;
   var sResult = sFormat;
   var nHour = dtTime.getHours();

   if (isNaN(nHour)) return '';

   // check for two-digit hour (24-hour format)
   i = sResult.indexOf('HH');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((nHour < 10) ? '0' : '') + nHour.toString() + sResult.substring(i + 2);
   }

   // check for one-digit hour (24-hour format)
   i = sResult.indexOf('H');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + nHour.toString() + sResult.substring(i + 1);
   }

   if (nHour > 12) nHour -= 12;
   if (nHour == 0) nHour = 12;

   // check for two-digit hour (12-hour format)
   i = sResult.indexOf('hh');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((nHour < 10) ? '0' : '') + nHour.toString() + sResult.substring(i + 2);
   }

   // check for one-digit hour (12-hour format)
   i = sResult.indexOf('h');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + nHour.toString() + sResult.substring(i + 1);
   }

   // check for two-digit minute
   i = sResult.indexOf('mm');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getMinutes() < 10) ? '0' : '') + dtTime.getMinutes().toString() + sResult.substring(i + 2);
   }

   // check for one-digit minute
   i = sResult.indexOf('m');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtTime.getMinutes().toString() + sResult.substring(i + 1);
   }

   // check for one-digit second
   i = sResult.indexOf('ss');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getSeconds() < 10) ? '0' : '') + dtTime.getSeconds().toString() + sResult.substring(i + 2);
   }

   // check for one-digit second
   i = sResult.indexOf('s');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + dtTime.getSeconds().toString() + sResult.substring(i + 1);
   }

   // check for two-character lowercase AM/PM
   i = sResult.indexOf('tt');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'am' : 'pm') + sResult.substring(i + 2);
   }

   // check for one-character lowercase AM/PM
   i = sResult.indexOf('t');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'a' : 'p') + sResult.substring(i + 1);
   }

   // check for two-character uppercase AM/PM
   i = sResult.indexOf('TT');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'AM' : 'PM') + sResult.substring(i + 2);
   }

   // check for one-character uppercase AM/PM
   i = sResult.indexOf('T');
   if (i >= 0) {
      sResult = sResult.substring(0, i) + ((dtTime.getHours() < 12) ? 'A' : 'P') + sResult.substring(i + 1);
   }

   return sResult;
}

// number validation (.NET validator)
function ValidateNumberNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var sNewValue = '';

   try {
      var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes["PromptText"]) {
         sPromptText = ctl.attributes["PromptText"].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         sNewValue = sPromptText;
         arguments.IsValid = true;
      }
      else {
         var s = arguments.Value;
         while (s.substring(s.length - 1, s.length) == ' ') { s = s.substring(0, s.length - 1); }

         if (s == '') {
            sNewValue = (ctl.attributes["AllowBlank"].value == 'True') ? '' : '0';
            arguments.IsValid = true;
         }
         else {
            var dNum = ValidateNumber(s);

            if (!isNaN(dNum)) {
               var nDec = parseInt(ctl.attributes["Decimals"].value);
               var bRound = (ctl.attributes["Round"].value == 'True');
               var bCommas = (ctl.attributes["ShowCommas"].value == 'True');
               var bCurrency = (ctl.attributes["ShowCurrency"].value == 'True');
               var sNegDisplay = ctl.attributes["NegDisplay"].value;

               arguments.IsValid = true;

               if (!bRound) {
                  s = dNum.toString();
                  i = s.indexOf(".");
                  if (i >= 0) {
                     s = s.substring(i + 1);
                     if (s.length > nDec) arguments.IsValid = false;
                  }
               }

               if (arguments.IsValid) sNewValue = FormatNumber(dNum, nDec, sNegDisplay, bCommas, bCurrency);
            }
            else {
               arguments.IsValid = false;
            }
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
   }

   if (arguments.IsValid) ctl.value = sNewValue;
   return arguments.IsValid;
}

// number validation (for Grid)
function ValidateNumberGrid(ctl) {
   var bIsValid = true;
   var sNewValue = '';

   try {
      var s = ctl.value;
      while (s.substring(s.length - 1, s.length) == ' ') { s = s.substring(0, s.length - 1); }

      if (s == '') {
         sNewValue = (ctl.attributes["AllowBlank"].value == 'True') ? '' : '0';
         bIsValid = true;
      }
      else {
         var dNum = ValidateNumber(s);

         if (!isNaN(dNum)) {
            var nDec = parseInt(ctl.attributes["Decimals"].value);
            var bRound = (ctl.attributes["Round"].value == 'True');
            var bCommas = (ctl.attributes["ShowCommas"].value == 'True');
            var bCurrency = (ctl.attributes["ShowCurrency"].value == 'True');
            var sNegDisplay = ctl.attributes["NegDisplay"].value;

            bIsValid = true;

            if (!bRound) {
               s = dNum.toString();
               i = s.indexOf(".");
               if (i >= 0) {
                  s = s.substring(i + 1);
                  if (s.length > nDec) bIsValid = false;
               }
            }

            if (bIsValid) sNewValue = FormatNumber(dNum, nDec, sNegDisplay, bCommas, bCurrency);
         }
         else {
            bIsValid = false;
         }
      }
   }
   catch (ex) {
      bIsValid = false;
   }

   if (bIsValid) ctl.value = sNewValue;
   return bIsValid;
}

// number range validation (.NET validation)
function ValidateNumberRangeNET(source, arguments) {
   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes["PromptText"]) {
         sPromptText = ctl.attributes["PromptText"].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         arguments.IsValid = true;
         return true;
      }
      else {
         var dNum = ValidateNumber(arguments.Value);

         if (!isNaN(dNum)) {
            var i = ctl.id.lastIndexOf("_");
            if (i >= 0) i = ctl.id.lastIndexOf("_", i - 1);
            var sPrefix = (i >= 0) ? ctl.id.substring(0, i + 1) : "";

            var d;
            var dMinValue = parseFloat(source.MinValue);
            var dMaxValue = parseFloat(source.MaxValue);

            var sMinCtl = source.MinValueCtl;
            var sMaxCtl = source.MaxValueCtl;

            if (sMinCtl != '') {
               var ctlMin = document.getElementById(sPrefix + sMinCtl + '_txt');
               if (ctlMin != null) {
                  d = ValidateNumber(ctlMin.value);
                  if (!isNaN(d)) dMinValue = d;
               }
            }

            if (sMaxCtl != '') {
               var ctlMax = document.getElementById(sPrefix + sMaxCtl + '_txt');
               if (ctlMax != null) {
                  d = ValidateNumber(ctlMax.value);
                  if (!isNaN(d)) dMaxValue = d;
               }
            }

            arguments.IsValid = ((dNum >= dMinValue) && (dNum <= dMaxValue));
            return arguments.IsValid;
         }
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

function ValidateNumber(sValue) {
   var sNewValue = '';
   var c;
   var bFoundMinus = false;
   var i;

   // strip commas and dollar signs (they confuse the parser)
   // also strip negative symbols and parentheses, record that the number is negative
   for (i = 0; i < sValue.length; i++) {
      c = sValue.substring(i, i + 1);

      if (c == "(") c = "-";

      if (c == "-") {
         bFoundMinus = true;
         c = ")";
      }

      if ((c != ",") && (c != "$") && (c != ")")) {
         if (((c < "0") || (c > "9")) && (c != ".")) return NaN;

         sNewValue += c;
      }
   }

   if (bFoundMinus) sNewValue = '-' + sNewValue;

   try {
      var d = parseFloat(sNewValue);
      return d;
   }
   catch (ex) {
      return NaN;
   }
}

function FormatNumber(dNum, nDec, sNegDisplay, bCommas, bCurrency) {
   if (isNaN(dNum)) return '';

   var sNum = '';
   var sDec = '';
   var i;
   var bIsNegative = (dNum < 0);

   dNum = Math.abs(dNum);

   // handle rounding to correct decimal place
   if (nDec >= 0) {
      var sZeros = '000000000000000'   // 15 zeros
      var nMult = parseInt('1' + sZeros.substring(0, nDec));
      dNum = (Math.round(dNum * nMult)) / nMult;

      // now add trailing zeros
      sNum = dNum.toString();
      i = sNum.indexOf(".");

      if (i >= 0) {
         sDec = sNum.substring(i);
         sNum = sNum.substring(0, i);
      }
      else sDec = '.';

      while (sDec.length < nDec + 1) sDec += '0';

      if (sDec != '.') sNum += sDec;
   }
   else {
      sNum = dNum.toString();
   }

   if (bCommas) {
      var nLen;

      // strip decimals for now (they are an unknown length)
      i = sNum.indexOf(".");

      if (i >= 0) {
         sDec = sNum.substring(i);
         sNum = sNum.substring(0, i);
      }
      else {
         sDec = '';
      }

      // add comma in thousands place
      if (dNum >= 1000) {
         nLen = sNum.length
         sNum = parseInt('' + (dNum / 1000)) + ',' + sNum.substring(nLen - 3, nLen)
      }

      // add comma in millions place
      if (dNum >= 1000000) {
         nLen = sNum.length
         sNum = parseInt('' + (dNum / 1000000)) + ',' + sNum.substring(nLen - 7, nLen)
      }

      // re-add decimals
      sNum += sDec;
   }

   if (sNum.substring(0, 1) == ".") sNum = '0' + sNum;

   if (bIsNegative) {
      switch (sNegDisplay) {
         case 'Parens':
            sNum = '(' + (bCurrency ? '$' : '') + sNum + ')';
            bCurrency = false;
            break;

         case 'Postfix': sNum += '-'; break;
         default: sNum = '-' + sNum; break;
      }
   }

   if (bCurrency) sNum = '$' + sNum;
   return sNum;
}

// phone number validation
function ValidatePhoneNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes["PromptText"]) {
      sPromptText = ctl.attributes["PromptText"].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var bAllowLetters = (source.attributes["AllowLetters"].value == 'True');
      var sPhone = StripPunctuation(arguments.Value, bAllowLetters, true, false);

      if (!bAllowLetters) {
         var s = StripPunctuation(arguments.Value, true, true, false);
         if (sPhone != s) sPhone = '';
      }

      if (sPhone.length == 7) {
         var sDfltAC = source.attributes["DefaultAreaCode"].value;
         if (sDfltAC != '') sPhone = sDfltAC + sPhone;
      }

      if (sPhone.length == 10) {
         var sDispFmt = source.attributes["DisplayFormat"].value;

         switch (sDispFmt) {
            case 'Local':
               sPhone = '(' + sPhone.substring(0, 3) + ') ' + sPhone.substring(3, 6) + '-' + sPhone.substring(6, 10);
               break;

            case 'Dashes':
            case 'Dots'  :
               var s = (sDispFmt == 'Dots') ? '.' : '-';
               sPhone = sPhone.substring(0, 3) + s + sPhone.substring(3, 6) + s + sPhone.substring(6, 10);
               break;

         }

         ctl.value = sPhone.toUpperCase();
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

// SSN validation
function ValidateSSNNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes["PromptText"]) {
      sPromptText = ctl.attributes["PromptText"].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var sSSN = StripPunctuation(arguments.Value, false, true, false);
      var s    = StripPunctuation(arguments.Value, true,  true, false);

      if (sSSN != s) sSSN = '';

      if (sSSN.length == 9) {
         ctl.value = sSSN.substring(0, 3) + '-' + sSSN.substring(3, 5) + '-' + sSSN.substring(5, 9);
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

// alien ID validation
function ValidateAlienNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes["PromptText"]) {
      sPromptText = ctl.attributes["PromptText"].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var sAlienID = StripPunctuation(arguments.Value, false, true, false);

      if (sAlienID.length == 9) {
         ctl.value = sAlienID.toUpperCase();
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

// zip code validation
function ValidateZipNET(source, arguments) {
   var ctl = document.getElementById(source.controltovalidate);
   var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
   var sPromptText = '';

   if (bPromptPersist && ctl.attributes["PromptText"]) {
      sPromptText = ctl.attributes["PromptText"].value;
   }

   if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
      ctl.value = sPromptText;
      arguments.IsValid = true;
   }
   else {
      var sZip = StripPunctuation(arguments.Value, false, true, false);
      var s    = StripPunctuation(arguments.Value, true,  true, false);

      if (sZip != s) sZip = '';

      if ((sZip.length == 5) || (sZip.length == 9)) {
         if (sZip.length == 9) sZip = sZip.substring (0, 5) + '-' + sZip.substring(5, 9);
         ctl.value = sZip;
         arguments.IsValid = true;
      }
      else arguments.IsValid = (arguments.Value == '');
   }

   return arguments.IsValid;
}

function LUHN(sCardNum) {
	var n;
	var nSum = 0;

   for (var i = 1; i <= sCardNum.length; i++) {
      n = parseInt(sCardNum.substring(sCardNum.length - i, sCardNum.length - i + 1));

      // every other digit is multiplied by 2
      // add the resulting digits (not number)
      // subtracting 9 does the trick
      // ex. 6 * 2 = 13, so add 1 + 3 (or 13 - 9) = 4
      if ((i % 2) == 0) {
         n *= 2;
         if (n > 9) n -= 9;
      }

      nSum += n;
   }

   return ((nSum % 10) == 0) ? true : false;
}

function ValidateCreditCardNET (source, arguments) {
   var CardType_VISA        = 1;
   var CardType_MasterCard  = 2;
   var CardType_Discover    = 4;
   var CardType_AMEX        = 8;
   var CardType_DinersClub  = 16;
   var CardType_AusBankCard = 32;
   var CardType_enRoute     = 64;
   var CardType_JCB         = 128;

   try {
      var ctl = document.getElementById(source.controltovalidate);
      var bPromptPersist = (ctl.attributes["PromptPersist"].value == 'True');
      var sPromptText = '';

      if (bPromptPersist && ctl.attributes["PromptText"]) {
         sPromptText = ctl.attributes["PromptText"].value;
      }

      if (bPromptPersist && (sPromptText.toUpperCase() == arguments.Value.toUpperCase())) {
         ctl.value = sPromptText;
         arguments.IsValid = true;
         return true;
      }
      else {
         var s = arguments.Value;
         var sNew = "";
         var c;
         var sDelimiter       = source.attributes["Delimiter"].value;
         var nAllowedTypes    = source.attributes["AllowedTypes"].value;
         var bPerformChecksum = (source.attributes["PerformChecksum"].value == 'True');

         if (sDelimiter == null) sDelimiter = ' ';

         // reset format message
         var sErrMsg = source.attributes["OrigMsg"].value;
         //source.attributes["FormatMessage"].value = '&nbsp;' + sErrMsg;

         for (var i = 0; i < s.length; i++) {
            c = s.substring(i, i + 1);
            if (((c < "0") || (c > "9")) && (c != " ") && (c != "-") && (c != ".")) {
               arguments.IsValid = false;
               break;
            }
            else if ((c >= "0") && (c <= "9")) sNew += c;
         }
         // validate general length
         if (arguments.IsValid) {
            arguments.IsValid = (sNew.length >= 13) && (sNew.length <= 16);
            sErrMsg = 'Must be 13 to 16 digits';
         }

         var sMasterCard = ',51,52,53,54,55,';
         var sDinersClub = ',300,301,302,303,304,305,';

         // validate lengths of known card types
         if (arguments.IsValid) {
            // VISA
            if ((nAllowedTypes & CardType_VISA) && (sNew.substring(0, 1) == '4')) {
               arguments.IsValid = (sNew.length == 13) || (sNew.length == 16);
               sErrMsg = 'VISA must be 13 or 16 digits';
            }
            // Discover
            else if ((nAllowedTypes & CardType_Discover) && (sNew.substring(0, 4) == '6011')) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'Discover must be 16 digits';
            }
            // MasterCard
            else if ((nAllowedTypes & CardType_MasterCard) && (sMasterCard.indexOf(',' + sNew.substring(0, 2) + ',') >= 0)) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'MasterCard must be 16 digits';
            }
            // American Express
            else if ((nAllowedTypes & CardType_AMEX) && ((sNew.substring(0, 2) == '34') || (sNew.substring(0, 2) == '37'))) {
               arguments.IsValid = (sNew.length == 15);
               sErrMsg = 'AMEX must be 15 digits';
            }
            // Diner's Club/Carte Blanche
            else if ((nAllowedTypes & CardType_DinersClub) && ((sNew.substring(0, 2) == '36') || (sNew.substring(0, 2) == '38') || 
                                                              (sDinersClub.indexOf(',' + sNew.substring(0, 3) + ',') >= 0))) {
               arguments.IsValid = (sNew.length == 14);
               sErrMsg = 'Diner\'s Club must be 14 digits';
            }
            // Australian BankCard
            else if ((nAllowedTypes & CardType_AusBankCard) && (sNew.substring(0, 4) == '5610')) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'Aus BankCard must be 16 digits';
            }
            // enRoute
            else if ((nAllowedTypes & CardType_enRoute) && ((sNew.substring(0, 4) == '2014') || (sNew.substring(0, 4) == '2149'))) {
               bPerformChecksum = false;
               arguments.IsValid = (sNew.length == 15);
               sErrMsg = 'enRoute must be 15 digits';
            }
            // JCB(1)
            else if ((nAllowedTypes & CardType_JCB) && ((sNew.substring(0, 4) == '2131') || (sNew.substring(0, 4) == '1800'))) {
               arguments.IsValid = (sNew.length == 15);
               sErrMsg = 'JCB(1) must be 15 digits';
            }
            // JCB(3)
            else if ((nAllowedTypes & CardType_JCB) && (sNew.substring(0, 1) == '3')) {
               arguments.IsValid = (sNew.length == 16);
               sErrMsg = 'JCB(3) must be 16 digits';
            }
            else {
               arguments.IsValid = false;
               sErrMsg = 'Invalid number';
            }
         }

         // perform checksum using LUHN formula (mod 10)
         if (arguments.IsValid && bPerformChecksum) {
            arguments.IsValid = LUHN(sNew);
            sErrMsg = 'Checksum failed';
         }

         if (arguments.IsValid) {
            ctl.value = sNew.substring(0,  4) + sDelimiter + sNew.substring(4, 8) + sDelimiter + 
                        sNew.substring(8, 12) + sDelimiter + sNew.substring(12);
         }
         else {
            source.innerHTML = '&nbsp;' + sErrMsg;
         }

         return arguments.IsValid;
      }
   }
   catch (ex) {
      arguments.IsValid = false;
      return false;
   }
}

// NumberBox spinner methods
function SpinCheck(nb) {
   var txt = document.getElementById(nb.id + '_txt');

   var curValue = parseInt(txt.value);
   var minValue = parseInt(txt.MinValue);
   var maxValue = parseInt(txt.MaxValue);

   var imbUp = document.getElementById(nb.id + '_imbSpinUp');
   var imbDn = document.getElementById(nb.id + '_imbSpinDown');

   if (imbUp != null) {
      imbUp.disabled = (curValue >= maxValue);
      imbUp.src = INTEGRA_CLIENT_PATH + (imbUp.disabled ? 'up-dis.gif' : 'up.gif');
   }

   if (imbDn != null) {
      imbDn.disabled = (curValue <= minValue);
      imbDn.src = INTEGRA_CLIENT_PATH + (imbDn.disabled ? 'down-dis.gif' : 'down.gif');
   }
}

function SpinNumber(nb,val) {
   var txt = eval(document.forms[0].elements[nb.id + '_txt']);

   var curValue = parseInt(txt.value);
   var minValue = parseInt(txt.MinValue);
   var maxValue = parseInt(txt.MaxValue);

   curValue += val;
   if (curValue > maxValue) curValue = maxValue;
   if (curValue < minValue) curValue = minValue;

   txt.value = curValue.toString();
   SpinCheck(nb);
}
