//-----------------------------------------------------------------------------
//     @name:  JavaScript General Validation and Formatting Functions
//
//  @purpose: JavaScript has absolutely NO basic field masking or validation.
//            All input type="Text" fields are just left justified character strings
//            that the operator enters; therefore, it is not possible to impose a
//            date mask (mm/dd/yyyy) for date fields, or number of decimal places for
//            Numeric types prior to entry of the data.  The following  validation routines
//            are necessary to prepare the entries for entry into a database field that
//            may be of specific type   (Date, Numeric w/ Decimals).  The built-in functions
//            ParseInt() and ParseFloat() are usefull for converting from string datatypes
//            to numeric datatypes but presume that the input string was correctly formatted
//            for conversion.
//
//            These routines are implementations of general programming practices and
//            therefore are considered public domain by virtue of common and frequent
//            use.
//
// @version:  JavaScript Validation Functions 1.0
//-----------------------------------------------------------------------------

// Global Variables
var errors = new Array();
var NotValid    = 0
var NotAlpha    = 1;
var NotDate     = 2;
var NotInRange  = 3;
var NotEntered  = 4;
var NotPhone    = 5;
var NotNumeric  = 6;
var NotTime     = 7;
errors[ NotValid   ] = "ERROR: This is not a valid entry!"
errors[ NotAlpha ]   = "ERROR: The Value entered does not contain all Alphabetic Characters!"
errors[ NotDate ]    = "ERROR: The Value entered is not a Valid Date!"
errors[ NotInRange ] = "ERROR: The Value entered is not within the accepted range!"
errors[ NotEntered ] = "ERROR: A Value must be entered in this Field!"
errors[ NotPhone   ] = "ERROR: A Valid Phone number must be entered!"
errors[ NotNumeric ] = "ERROR: The Value entered is not numeric!"
errors[ NotTime ]    = "ERROR: The Value entered is not a valid time!"

//-----------------------------------------------------------------------------
//     @name:   isEmpty( sValue )
//    @param:   sValue - Any String Variable
//  @purpose:   Determines if the passed string is empty.
//              send the string to trim() if there could be spaces in it that
//              still should be regarded as empty.
//   @return:   true if the string is empty, false if the string is not
//-----------------------------------------------------------------------------
function isEmpty( sValue ) {
  return( ( sValue == null ) || ( sValue == "" ) )
}


//-----------------------------------------------------------------------------
//     @name:   leftTrim( sValue )
//    @param:   sValue - Any String Variable
//  @purpose:   Removes leading spaces from a string
//   @return:   The string with the leading spaces removed
//-----------------------------------------------------------------------------
function leftTrim( sValue ) {
  var range = sValue.length;
  var i = 0;
  while ( ( i < range ) && ( sValue.charAt(i) == " " ) )
    i++;
  return sValue.substring(i, range )
  }


//-----------------------------------------------------------------------------
//     @name:   rightTrim( sValue )
//    @param:   sValue - Any String Variable
//  @purpose:   Removes trailing spaces from a string
//   @return:   The string with the trailing spaces removed
//-----------------------------------------------------------------------------
function rightTrim( sValue ) {
  var i = sValue.length - 1 ;
  var range = i;
  while ( ( i > 0  ) && ( sValue.charAt(i) == " " ) )
    i--;
  return sValue.substring(0, i+1 )
  }

//-----------------------------------------------------------------------------
//     @name:   trim( sValue )
//    @param:   sValue - Any String Variable
//  @purpose:   Removes leading and trailing spaces from a string
//   @return:   The string with the leading and trailing spaces removed
//-----------------------------------------------------------------------------
function trim( sValue ) {
  return ( rightTrim( leftTrim( sValue ) ) )
 }


//-----------------------------------------------------------------------------
//     @name:   isNumeric( sValue )
//    @param:   sValue - Any string representation of a numeric value
//  @purpose:   Determines if the passed string contains only characters
//              0-9 and "." or "-"  for validating entries that must be
//              numeric (can be positive or negative, Integer or Floating)
//   @return:   true if all characters are 0-9,. or -
//-----------------------------------------------------------------------------
function isNumeric( sValue ) {
  var range = sValue.length;
  var foundDecimalPoint = false;
  for ( var i = 0; i < range; i++) {
    var s = sValue.charAt(i);
    // the sign can only be in the first position
    if (i == 0 && s == "-") {
      continue
    }
    // There can only be one Decimal Point in the string
    if ( s == "." && !foundDecimalPoint) {
      foundDecimalPoint = true
      continue
    }
    if ( s < "0" || s > "9") {
      return false
    }
  }
  return true
}


//-----------------------------------------------------------------------------
//     @name:   isAlpha( sValue )
//    @param:   sValue - any string
//  @purpose:   Determines if the passed string contains only characters
//              a-z, A-Z or spaces.
//   @return:   true if all characters are a-z, A-Z or spaces.
//-----------------------------------------------------------------------------
function isAlpha( sValue ){
  var range = sValue.length;
  for ( var i = 0; i < range; i++) {
    var s = sValue.charAt(i);
    if ( ( s == " " ) || ( ( s >= "a") && ( s <= "z") ) || ( ( s >= "A") && ( s <= "Z") ) )
      continue
    else
      return false;
  }
  return true;
}


//-----------------------------------------------------------------------------
//     @name:   removeChars( sValue, sRemoveThese )
//    @param:   sValue - any string, sRemoveThese - Unwanted Characters
//  @purpose:   Remove characters from a string that are in another string
//   @return:   a string containing all characters excepth the unwanted ones
//-----------------------------------------------------------------------------
function removeChars( sValue, sRemoveThese )  {
  var i = 0;
  var s = "";
  for ( i = 0; i < sValue.length; i++ )  {
    var c = sValue.charAt( i );
    if ( sRemoveThese.indexOf( c ) < 0 )
      s += c ;
    }
  return ( s );
  }

//-----------------------------------------------------------------------------
//     @name:   validChars( sValue, sValidChars )
//    @param:   sValue - any string, sValidChars - Wanted Characters
//  @purpose:   Remove characters from a string that are NOT in another string
//   @return:   a string containing only the wanted characters
//              ie. Use stripping "()-  " from phone numbers
//-----------------------------------------------------------------------------
function validChars( sValue, sValidChars )  {
  var i = 0;
  var s = "";
  for ( i = 0; i < sValue.length; i++ )  {
    var c = sValue.charAt( i );
    if ( sValidChars.indexOf( c ) >= 0 )
      s += c ;
    }
  return ( s );
  }



//-----------------------------------------------------------------------------
//     @name:   inRange( sValue, sLower, sUpper )
//    @param:   sValue - any string, sLower - Lower Limit, sUpper - Upper limit
//  @purpose:   Checks if the passed value is between lower and upper limits
//   @return:   true if the value is in the range
//-----------------------------------------------------------------------------
function inRange( sValue, sLower, sUpper ) {
  var n = parseInt( sValue );
  var hi = parseInt( sUpper );
  var lo = parseInt( sLower );
  return ( ( n >= lo ) && ( n <= hi ) );
}

//-----------------------------------------------------------------------------
//     @name:   replaceWith( sValue, cThis, cThat )
//    @param:   sValue - any string, cThis - character to replace
//              cThat - replacement character
//  @purpose:   Replaces all occurences of one character with another
//              Use the string.replace() function for higher functionality.
//   @return:   the string with the characters replaced
//              ie. Preparing Date values "-" to "/"
//-----------------------------------------------------------------------------
function replaceWith( sValue, cThis, cThat )  {
  var i = 0;
  var s = "";
  for ( i = 0; i < sValue.length; i++ )  {
    var c = sValue.charAt( i );
    if ( c == cThis )
      s += cThat
    else
      s += c;
    }
  return ( s );
  }



//-----------------------------------------------------------------------------
//     @name:   isTime( sValue )
//    @param:   sValue - any Time string,
//  @purpose:   Accepts a time value in 9:99[:99] [x], 99:99[:99] [x] format
//              where x is  a, p, am, pm;  [:99] is optional seconds
//   @return:   true if the string contains a valid time value
//-----------------------------------------------------------------------------
function isTime( sValue ) {
  var nColon1 = sValue.indexOf(":");
  var nColon2 = sValue.lastIndexOf(":");
  var lNoSeconds = ( nColon1 == nColon2 ) ? true : false;
  if ( sValue.length == 0 ){
    return true
  }

  if ( nColon1 == - 1 ) {
    return false
  }

  var sAmPm = validChars( sValue, 'aApP' )
  if ( isEmpty( sAmPm  ) ) {
    return false;
  }

  var hh = parseInt( sValue.substring( 0, nColon1 ),10 );
  var mm = parseInt( sValue.substring( nColon1 + 1, nColon1 + 3 ),10 );
  if ( lNoSeconds ) {
    var ss = 0;
  } else {
    var ss = parseInt( sValue.substring( nColon2 + 1, nColon2 + 3 ),10 );
  }

  // Each field must be numeric
  if (isNaN( hh ) || isNaN( mm ) || isNaN( ss ) ) {
    return false;
  }

  s = 'Hours: ' + hh + '\n'
  s += 'Minutes: ' + mm + '\n'
  s += 'Seconds: ' + ss + '\n'
  s += 'AmPm: ' + sAmPm + '\n'
  // Diagnostics REMOVE
  //alert( s )

  if (  hh > 12  ||  mm > 59 || ss > 59 ){
    return false;
  } else {
    return true;
  }
}

//-----------------------------------------------------------------------------
//     @name:   isDate( sValue )
//    @param:   sValue - any date string, cThis - character to replace
//  @purpose:   Accepts dates in mmddyy, mmddyyyy, mm/dd/yy, mm/dd/yyyy,
//              mm-dd-yy or mm-dd-yyyy format
//   @return:   true if the string contains a valid date value
//-----------------------------------------------------------------------------
function isDate( sValue ) {
  var s = replaceWith( sValue, "-","/");
  var nSlash1 = s.indexOf("/");
  var nSlash2 = s.lastIndexOf("/");
  var bDelimited = ( nSlash1 > 0 );
  var daysInMonth = new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);

  if ( sValue.length == 0 ){
    return true
  }

  // There must be two and only 2 delimiters if there are any
  if ( bDelimited && nSlash1 == nSlash2) {
    return false;
  }

  if ( bDelimited ) {
    var mm = parseInt( s.substring( 0, nSlash1 ),10 );
    var dd = parseInt( s.substring( nSlash1 + 1, nSlash2 ), 10 );
    var yyyy = parseInt( s.substring( nSlash2 + 1, s.length ), 10 );
  } else {
    var mm = parseInt( s.substring( 0, 2 ), 10 );
    var dd = parseInt( s.substring( 2, 4 ), 10 );
    var yyyy = parseInt( s.substring( 4, s.length ), 10 );
  }

  // Each field must be numeric
  if (isNaN( mm ) || isNaN( dd ) || isNaN( yyyy ) ) {
    return false;
  }

  // Windowing technique for 2 Digit Dates ( 1930-2029 )
  yyyy = makeY2K( yyyy );

  if ( mm < 1 || mm > 12 ) {
    return false;
  }

  // Check number of Days in Month
  daysInMonth[2] = ( isLeapYear( yyyy )? 29:28 );

  if ( dd > daysInMonth[mm] ) {
    return false;
  }

  if (yyyy < 1753) {
    return false;
  }

  return true;
}


//-----------------------------------------------------------------------------
//     @name:   isLeapYear( nYear )
//    @param:   nYear - a 4 digit number
//  @purpose:   Determines whether a year represented as a 4 digit number
//              is a leap year
//   @return:   true if the number is a leap year
//-----------------------------------------------------------------------------
function isLeapYear( year ) {
  return ( (year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) ) )
}

//-----------------------------------------------------------------------------
//     @name:   makeY2K( nYear )
//    @param:   nYear - a 2 digit number
//  @purpose:   Turns a 2 digit year into a 4 digit year.
//              if the number is between 30 and 99 it is a 1900 year
//              otherwise it is a year between 2000 and 2029
//   @return:   A 4 digit year value
//-----------------------------------------------------------------------------
function makeY2K( year ) {
  // Windowing technique for 2 Digit Dates ( 1930-2029 )
  if ( year < 100)
    ( year >= 30 )? year += 1900 : year += 2000;
  return ( year )
}

//-----------------------------------------------------------------------------
//     @name:   date2String( oDate )
//    @param:   a Date object
//  @purpose:   Formats a date object as an 10 digit, "/" delimited date
//   @return:   a formated date string "mm/dd/yyyy"
//-----------------------------------------------------------------------------
function date2String( oDate ){
     return ( ( oDate.getMonth()+1) +"/"+ oDate.getDate() +"/"+ makeY2K(oDate.getFullYear()))
}

//-----------------------------------------------------------------------------
//     @name:   formatDate( sValue )
//    @param:   An 8 character string
//  @purpose:   Formats an 8, 10 or 12 digit string as a 12 character
//              "/" delimited date
//   @return:   a formated date string "mm/dd/yyyy"
//-----------------------------------------------------------------------------
function formatDate( sValue ){
  var s = replaceWith( sValue, "-","/");
  var nSlash1 = s.indexOf("/");
  var nSlash2 = s.lastIndexOf("/");
  var bDelimited = ( nSlash1 > 0 );

  if (!isDate(sValue)) {
      return "";
    }


  if ( bDelimited ) {
    var mm = parseInt( s.substring( 0, nSlash1 ),10 );
    var dd = parseInt( s.substring( nSlash1 + 1, nSlash2 ), 10 );
    var yyyy = parseInt( s.substring( nSlash2 + 1, s.length ), 10 );
    }
    else {
      var mm = parseInt( s.substring( 0, 2 ), 10 );
      var dd = parseInt( s.substring( 2, 4 ), 10 );
      var yyyy = parseInt( s.substring( 4, s.length ), 10 );
      }

  yyyy = makeY2K(yyyy);

  // Each field must be numeric
  if (isNaN( mm ) || isNaN( dd ) || isNaN( yyyy ) ) {
    return sValue;
    }
  else {
   return mm + "/" + dd + "/" + yyyy ;
   }

}

//-----------------------------------------------------------------------------
//     @name:   formatPhone( sValue )
//    @param:   A 10 character string
//  @purpose:   Formats an 10 character string as a phone number
//              The passed value is returned if it is not 10 characters
//   @return:   A formated phone number = (999) 999-9999
//-----------------------------------------------------------------------------
function formatPhone( sValue ) {
  var s = "(";
  if ( sValue.length == 10 ) {
    s += sValue.substr(0,3) +") "+ sValue.substr(3,3) +"-"
    s += sValue.substr(6,4)
    return ( s )
  } else {
    return ( sValue )
  }
}

//-----------------------------------------------------------------------------
//     @name:   ValiKeyPress(intKey, sValues, bolEditable)
//    @param:   intKey: integer value of the KeyPress
//              sValues:
//              bolEditable: 0 = not editable, 1 = editable
//
//  @purpose:
//   @return:   integer value of the KeyPress
//-----------------------------------------------------------------------------
function ValiKeyPress(intkey, svalues, bolEditable) {

  var strValidateList;
  var intKeyOut;
  If (bolEditable = 1)
    {
        strValidateList = svalues.toUpperCase() + String.fromCharCode(8);
      }
    Else
    {
        strValidateList = svalues.toUpperCase();
    }

  if (strValidateList.indexOf(String.fromCharCode(intkey)) > 0 )
    {
        intKeyOut = intKeyIn;
      }
    Else
    {
        intKeyOut = 0;
      }

  return intKeyOut;
}


//-----------------------------------------------------------------------------
//     @name:   validateData( f, aRay )
//    @param:   f: the form variable (passed as "this" from the onSubmit handler)
//              aRay: Array of form variables to validate in the form of
//              { formItemName, required, dataType }
//  @purpose:   Iterates through and validates all fields on the form
//              Displays an alert box if there are invalid fields using the
//              title declaration as the label
//   @return:   True if all fields are valid, false if not.
//-----------------------------------------------------------------------------
function validateData( f, aRay ) {
  var hasErrors = false;
  var eMsg = "___________________________________________________________\n\n";
  eMsg += "This Information was Not Submitted because of the following errors.\n";
  eMsg += "Please correct these error(s) and Resubmit.\n";
  eMsg += "___________________________________________________________\n\n";

  // for each element on the form
  for (var i = 0; i < f.length; i++ ) {
    var e = f.elements[i];
    var sVarName

    if (( e.type == "text" ) | ( e.type == "textarea" )) {

      // extract the subArray element
      for (var k = 0; k < aRay.length; k++ ) {
        var aDetail = aRay[k];

        // does the Text element name exist in the validation array
        if ( e.name == aDetail[0] ){

          // Use the Title attribute in the error message if present.
          sVarName = ( e.title != '' ) ? e.title : e.name;

          // Required Field
          if ( ( aDetail[1] ) && ( isEmpty( e.value ) ) ){
            eMsg += errors[ NotEntered] + " " + sVarName +"\n";
            hasErrors = true;
          }

          // Numeric Field
          if ( ( aDetail[2] == 'numeric' ) && (! isNumeric( e.value ) ) ){
            eMsg += errors[ NotNumeric] + " " + sVarName +"\n";
            hasErrors = true;
          }

          // Date Field
          if ( ( aDetail[2] == 'date' ) && (! isDate( e.value ) ) ){
            eMsg += errors[ NotDate] + " " + sVarName +"\n";
            hasErrors = true;
          }

          // Alpha Field
          if ( ( aDetail[2] == 'alpha' ) && (! isAlpha( e.value ) ) ){
            eMsg += errors[ NotAlpha] + " " + sVarName +"\n";
            hasErrors = true;
          }

          // Time Field
          if ( ( aDetail[2] == 'time' ) && (! isTime( e.value ) ) ){
            eMsg += errors[ NotTime] + " " + sVarName +"\n";
            hasErrors = true;
          }
        }
      }
    }
  }
  if ( hasErrors ) {
    alert( eMsg );
    return false;
  } else {
  return true;
  }
}

//-----------------------------------------------------------------------------
//     @name:   whichButtonIsChecked( oButtons )
//    @param:   The radio button group object
//  @purpose:   Determines which button in a radio button group is checked
//   @return:   Index of the button that is checked or 0 if none are checked
//              which basically defaults to the first button in the group
//-----------------------------------------------------------------------------
function whichButtonIsChecked( oButtons ) {
  for( var i = 0; i < oButtons.length; i++ ) {
    if ( oButtons[i].checked ) {
      return i;
    }
  }
  return 0;
}


//-----------------------------------------------------------------------------
//     @name:   goHome()
//    @param:   none
//  @purpose:   Return to the Home Page ( used on Abort Buttons )
//   @return:   nothing
//-----------------------------------------------------------------------------
function goHome(){
  window.location='/default.asp';
}


//-----------------------------------------------------------------------------
//     @name:   showData()
//    @param:   the form object
//  @purpose:   Diagnostic routine that displays all of the field/value pairs
//              in a separate window
//   @return:   nothing
//-----------------------------------------------------------------------------
function showData( f ) {
  var e = f.elements;
  var w = window.open( "","");
  var s = "<HTML><body>";
  for ( var i = 0; i < e.length ; i++ ) {
      s += e[i].name + " = " + e[i].value + "<br>";
  }
  s += "</body></html>";
  w.document.write( s );
  w.document.close()
}
