/*******************************************************************************
* File Name : functions.js                                                     *
*                                                                              *
* Copyright : Streamline Technologies, www.streamtechnologies.com              *
* Created   : 3/14/2003                                                        *
* Author    : Alex Short, ashort@streamtechnologies.com                        *
* Purpose   : General JavaScript Functions						               *
*******************************************************************************/                                   

//Global setting for whether or not a value is required.  This can be
//overwritten in most functions by submitting the emptyOK parameter.
  var defaultEmptyOK = false
  
//Array that holds number of days in each month  
  var daysInMonth = new Array();
  daysInMonth[1] = 31;
  daysInMonth[2] = 29;   // must programmatically check this
  daysInMonth[3] = 31;
  daysInMonth[4] = 30;
  daysInMonth[5] = 31;
  daysInMonth[6] = 30;
  daysInMonth[7] = 31;
  daysInMonth[8] = 31;
  daysInMonth[9] = 30;
  daysInMonth[10] = 31;
  daysInMonth[11] = 30;
  daysInMonth[12] = 31;

// Whitespace Characters
  var whitespace = " \t\n\r";
  
// Digits  
  var digits = "0123456789";
 
// non-digit characters which are allowed in phone numbers
  var phoneNumberDelimiters = "()- ";

// characters which are allowed in US phone numbers
  var validUSPhoneChars = digits + phoneNumberDelimiters;

// U.S. phone numbers have 10 digits.
// They are formatted as 123 456 7890 or (123) 456-7890.
  var digitsInUSPhoneNumber = 10;

//Decimal Point Delimiter  
  var decimalPointDelimiter = ".";
  
//Opens a new browser window
  function openWin(url,name,toolbar,width,height,status,scrollbars,resize,menubar) {
    window.open(url,name,"toolbar=" + toolbar + ",width=" + width + ",height=" + height + ",status=" + status + ",scrollbars=" + scrollbars + ",resize=" + resize + ",menubar=" + menubar);  
  }

// non-digit characters which are allowed in ZIP Codes
  var ZIPCodeDelimiters = "-";

// U.S. ZIP codes have 5 or 9 digits.
// They are formatted as 12345 or 12345-6789.
  var digitsInZIPCode1 = 5
  var digitsInZIPCode2 = 9

//Valid US State Codes  
  var USStateCodeDelimiter = "|";
  var USStateCodes = "AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY|AE|AA|AE|AE|AP"

// non-digit characters which are allowed in credit card numbers
  var creditCardDelimiters = "- "

//Sets focus on the first element on the page
  function setFocus() {
    var i;
    var j;    
    if (document.forms.length > 0) {
      for (i=0; i<document.forms.length; i++) {
        var theForm = document.forms[i];
        for (j=0; j<theForm.length; j++) {
          if (((theForm.elements[j].type == "text") ||
          (theForm.elements[j].type == "password") ||
		  (theForm.elements[j].type == "textarea")) &&
		  (theForm.elements[j].disabled == false)) {
		    theForm.elements[j].focus();
		    return;
		  }		  
		}
	  }
	}
  }

//Returns the value of a radio button
  function getRadioButtonValue (radio) {   
    for (var i=0; i<radio.length; i++) {   
      if (radio[i].checked) { break }
    }
    return radio[i].value
  }

//Submits the form
  function submitForm(theForm) {
    for (i=0; i<document.forms.length; i++) {
      if (document.forms[i].name == theForm)
        document.forms[i].submit();   
    }
  }

// Removes all characters which appear in string bag from string s.
  function stripCharsInBag (s, bag) {   
    var i;
    var returnString = "";

    for (i=0; i<s.length; i++) {   
      // Check that current character isn't whitespace.
      var c = s.charAt(i);
      if (bag.indexOf(c) == -1) returnString += c;
    }
    return returnString;
  }
  
//Returns true if string s is empty
  function isEmpty(s) {   
    return ((s == null) || (s.length == 0))
  }

// Returns true if string s is empty or whitespace characters only.
  function isWhitespace (s) {   
    var i;
    if (isEmpty(s)) return true;
    for (i=0; i<s.length; i++) {   
      var c = s.charAt(i);
      if (whitespace.indexOf(c) == -1) return false;
    }
    return true;
  }
  
//Returns true if character c is a digit (0 .. 9)
  function isDigit (c) {   
    return ((c >= "0") && (c <= "9"))
  }

//Returns true if all characters in string s are digits
  function isInteger (s) {   
    var i;
    if (isEmpty(s)) 
      if (isInteger.arguments.length == 1) return defaultEmptyOK;
      else return (isInteger.arguments[1] == true);
    for (i=0; i<s.length; i++) {
      var c = s.charAt(i);
      if (!isDigit(c)) return false;
    }
    return true;  
  }

//Returns true if string s is an integer within the range of 
//integer arguments a and b
  function isIntegerInRange (s, a, b) {   
    if (isEmpty(s)) 
      if (isIntegerInRange.arguments.length == 3) return defaultEmptyOK;
      else return (isIntegerInRange.arguments[3] == true);
    if (!isInteger(s, false)) return false;
    var num = parseInt (s);
    return ((num >= a) && (num <= b));
  }

//Returns true if string s has a length in the range of integer arguments a and b
  function isStringInRange (s, a, b) {   
    if (isEmpty(s)) 
      if (isStringInRange.arguments.length == 3) return defaultEmptyOK;
      else return (isStringInRange.arguments[3] == true);
	var len = s.length;
    return ((len >= a) && (len <= b));
  }

//Returns true if string s is an integer >= 0
  function isNonnegativeInteger (s) {   
    var secondArg = defaultEmptyOK;
    if (isNonnegativeInteger.arguments.length > 1)
      secondArg = isNonnegativeInteger.arguments[1];
    return (isSignedInteger(s, secondArg)
      && ((isEmpty(s) && secondArg) || (parseInt (s) >= 0)));
  }
  
//Returns true if string s is an integer > 0
  function isPositiveInteger (s) {   
    var secondArg = defaultEmptyOK;
    if (isPositiveInteger.arguments.length > 1)
      secondArg = isPositiveInteger.arguments[1];
    return (isSignedInteger(s, secondArg)
      && ((isEmpty(s) && secondArg) || (parseInt (s) > 0)));
  }

//Returns true if all characters are numbers; first character can be + or -
  function isSignedInteger (s) {   
    if (isEmpty(s)) 
      if (isSignedInteger.arguments.length == 1) return defaultEmptyOK;
      else return (isSignedInteger.arguments[1] == true);
    else {
      var startPos = 0;
      var secondArg = defaultEmptyOK;
      if (isSignedInteger.arguments.length > 1)
        secondArg = isSignedInteger.arguments[1];
      if ((s.charAt(0) == "-") || (s.charAt(0) == "+"))
        startPos = 1;    
      return (isInteger(s.substring(startPos, s.length), secondArg))
    }
  }

//Returns true if all characters in s are digits;  allows 1 decimal point
  function isFloat (s) {   
    var i;
    var seenDecimalPoint = false;
    if (isEmpty(s)) 
      if (isFloat.arguments.length == 1) return defaultEmptyOK;
      else return (isFloat.arguments[1] == true);
    if (s == decimalPointDelimiter) return false;
    for (i=0; i<s.length; i++) {   
      var c = s.charAt(i);
      if ((c == decimalPointDelimiter) && !seenDecimalPoint) seenDecimalPoint = true;
      else if (!isDigit(c)) return false;
    }
    return true;
  }
  
//Returns true if string s is an integer between 1 and 12
  function isMonth (s) {   
    if (isEmpty(s)) 
      if (isMonth.arguments.length == 1) return defaultEmptyOK;
      else return (isMonth.arguments[1] == true);
    return isIntegerInRange (s, 1, 12);
  }

//Returns true if string s is an integer between 1 and 31
  function isDay (s) {
    if (isEmpty(s)) 
      if (isDay.arguments.length == 1) return defaultEmptyOK;
      else return (isDay.arguments[1] == true); 
    return isIntegerInRange (s, 1, 31);
  }

//Returns true if string s is a valid year number (2 or 4 digits) 
  function isYear (s) {   
    if (isEmpty(s)) 
      if (isYear.arguments.length == 1) return defaultEmptyOK;
      else return (isYear.arguments[1] == true);
    if (!isNonnegativeInteger(s)) return false;
    return ((s.length == 2) || (s.length == 4));
}

//Returns number of days in February of year
  function daysInFebruary (year) {
    return (((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) )) ? 29 : 28);
  }

//Returns true if string s is an integer between 1 and 12
  function isHour (s) {   
    if (isEmpty(s)) 
      if (isHour.arguments.length == 1) return defaultEmptyOK;
      else return (isHour.arguments[1] == true);
    return isIntegerInRange (s, 1, 12);
  }

//Returns true if string s is an integer between 1 and 59
  function isMinuteOrSecond (s) {   
    if (isEmpty(s)) 
      if (isMinuteOrSecond.arguments.length == 1) return defaultEmptyOK;
      else return (isMinuteOrSecond.arguments[1] == true);
    if(!isIntegerInRange (s, 0, 59)) return false;
    return (s.length == 2)
  }
  
//Returns true if string s is a valid time (hh:mm:ss or hh:mm)
  function isTime (s) { 
    if (isEmpty(s)) 
      if (isTime.arguments.length == 1) return defaultEmptyOK;
      else return (isTime.arguments[1] == true);
    var elems = s.split(":");
    if (!((elems.length == 2) || (elems.length == 3))) return false; //should be 2 or 3 components to the time
    if (!(isHour(elems[0], false) && isMinuteOrSecond(elems[1], false))) return false;
    if (elems.length == 3) { //validate seconds
	  if (!(isMinuteOrSecond(elems[2], false))) return false    
    }
    return true;
  }

//Returns true if string s is a valid date (mm/dd/yyyy or mm/dd/yy)
  function isDate (s) { 
    if (isEmpty(s)) 
      if (isDate.arguments.length == 1) return defaultEmptyOK;
      else return (isDate.arguments[1] == true);
    var elems = s.split("/");
    if (!(elems.length == 3)) return false; //should be 3 components to the date
    if (!(isYear(elems[2], false) && isMonth(elems[0], false) && isDay(elems[1], false))) return false;
    var month = parseInt(elems[0],10);
    var day = parseInt(elems[1],10);
    var year = parseInt(elems[2],10); 
    if (day > daysInMonth[month]) return false; 
    if ((month == 2) && (day > daysInFebruary(year))) return false;
    return true;
  }
  
//Returns true if string s is in valid email format
  function isEmail (s) {   
    if (isEmpty(s)) 
      if (isEmail.arguments.length == 1) return defaultEmptyOK;
      else return (isEmail.arguments[1] == true);
    if (isWhitespace(s)) return false;
    var i = 1;
    var sLength = s.length;
    while ((i < sLength) && (s.charAt(i) != "@")) { 
      i++ 
    }
    if ((i >= sLength) || (s.charAt(i) != "@")) return false;
    else i += 2;
    while ((i < sLength) && (s.charAt(i) != ".")) { 
      i++ 
    }
    if ((i >= sLength - 1) || (s.charAt(i) != ".")) return false;
    else return true;
  }

//Returns true if string s is a valid state code 
  function isStateCode (s) {   
    if (isEmpty(s)) 
      if (isStateCode.arguments.length == 1) return defaultEmptyOK;
      else return (isStateCode.arguments[1] == true);
    return ((USStateCodes.indexOf(s) != -1) && (s.indexOf(USStateCodeDelimiter) == -1))
  }

//Returns true if string s is a valid zip code
  function isZIPCode (s) {  
    if (isEmpty(s)) 
      if (isZIPCode.arguments.length == 1) return defaultEmptyOK;
      else return (isZIPCode.arguments[1] == true);
    return (isInteger(s) && ((s.length == digitsInZIPCode1) || (s.length == digitsInZIPCode2)))
  }

//Returns true if string s is a valid US phone number
  function isUSPhoneNumber (s) {   
    if (isEmpty(s)) 
      if (isUSPhoneNumber.arguments.length == 1) return defaultEmptyOK;
      else return (isUSPhoneNumber.arguments[1] == true);
    return (isInteger(s) && s.length == digitsInUSPhoneNumber)
  }

//Returns true if cardNumber is a valid number for cardType  
  function isCardMatch (cardType, cardNumber) {
    cardType = cardType.toUpperCase();
	var doesMatch = true;
	if ((cardType == "VISA") && (!isVisa(cardNumber))) doesMatch = false;
	if ((cardType == "MASTERCARD") && (!isMasterCard(cardNumber))) doesMatch = false;
	if (((cardType == "AMERICANEXPRESS") || (cardType == "AMEX")) && (!isAmericanExpress(cardNumber))) doesMatch = false;
	if ((cardType == "DISCOVER") && (!isDiscover(cardNumber))) doesMatch = false;
	return doesMatch;
  }

//Returns true if cc is a valid Visa number
  function isVisa(cc) {
    if (((cc.length == 16) || (cc.length == 13)) && (cc.substring(0,1) == 4))
      return isCreditCard(cc);
    return false;
  }

//Returns true if cc is a valid MasterCard number
  function isMasterCard(cc) {
    firstdig = cc.substring(0,1);
    seconddig = cc.substring(1,2);
    if ((cc.length == 16) && (firstdig == 5) && ((seconddig >= 1) && (seconddig <= 5)))
      return isCreditCard(cc);
    return false;
  }

//Returns true if cc is a valid American Express number
  function isAmericanExpress(cc) {
    firstdig = cc.substring(0,1);
    seconddig = cc.substring(1,2);
    if ((cc.length == 15) && (firstdig == 3) && ((seconddig == 4) || (seconddig == 7)))
      return isCreditCard(cc);
    return false;
  }

//Returns true if cc is a valid Discover number
  function isDiscover(cc) {
    first4digs = cc.substring(0,4);
    if ((cc.length == 16) && (first4digs == "6011")) 
      return isCreditCard(cc);
    return false;
  }

//Uses the "Luhn Mod 10" test to see if string s is a valid credit card number
  function isCreditCard(s) {
    if (s.length > 19)  // Encoding only works on cards with less than 19 digits
      return (false);

    sum = 0; 
    mul = 1; 
    l = s.length;
  
    for (i=0; i<l; i++) {
      digit = s.substring(l-i-1,l-i);
      tproduct = parseInt(digit,10) * mul;
      if (tproduct >= 10)
        sum += (tproduct % 10) + 1;
      else
        sum += tproduct;
      if (mul == 1)
        mul++;
      else
        mul--;
    }

    if ((sum % 10) == 0)
      return (true);
    else
      return (false);
  }

//Returns true if strings match
  function compareStrings (s1, s2) {   
    var doesMatch = false;
    if (s1 == s2) doesMatch = true;
    return doesMatch;
  }


/* FUNCTIONS TO INTERACTIVELY CHECK VARIOUS FORM FIELDS */

  function checkDate (theField, fieldLabel, emptyOK) {
    if (checkDate.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isDate(theField.value)) 
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkTime (theField, fieldLabel, emptyOK) {
    if (checkTime.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isTime(theField.value)) 
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkEmail (theField, fieldLabel, emptyOK) {
    if (checkEmail.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isEmail(theField.value)) 
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkInteger (theField, fieldLabel, emptyOK) {
    if (checkInteger.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isInteger(theField.value))
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkNonnegativeInteger (theField, fieldLabel, emptyOK) {
    if (checkNonnegativeInteger.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isNonnegativeInteger(theField.value))
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkPositiveInteger (theField, fieldLabel, emptyOK) {
    if (checkPositiveInteger.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isPositiveInteger(theField.value))
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkIntegerInRange (theField, fieldLabel, minValue, maxValue, emptyOK) {
    if (checkIntegerInRange.arguments.length == 4) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isIntegerInRange(theField.value, minValue, maxValue))
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkStringInRange (theField, fieldLabel, minValue, maxValue, emptyOK) {
    if (checkStringInRange.arguments.length == 4) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isStringInRange(theField.value, minValue, maxValue))
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkFloat (theField, fieldLabel, emptyOK) {
    if (checkFloat.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isFloat(theField.value))
      warnInvalid (theField, fieldLabel)
    else return true;
  }
  
  function checkRadioButton (theField, fieldLabel) {
    var result = false;

    if (theField.length == undefined) { 
	  if (theField.checked) {
	    result = true;
	  }
	}	
	else {
	  for (i=0; i<theField.length; i++) {
        if (theField[i].checked) {
          result = true;
          break;
        }
      }
    }
    if (!result) { 
      alert('Invalid Field: ' + fieldLabel);
    }
    return result;
  }
   
  function checkStateCode (theField, fieldLabel, emptyOK) {   
    if (checkStateCode.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else { 
      theField.value = theField.value.toUpperCase();
      if (!isStateCode(theField.value, false)) 
        warnInvalid (theField, fieldLabel);
      else return true;
    }
  }
  
  function reformat (s) {   
    var arg;
    var sPos = 0;
    var resultString = "";

    for (var i = 1; i < reformat.arguments.length; i++) {
       arg = reformat.arguments[i];
       if (i % 2 == 1) resultString += arg;
       else {
           resultString += s.substring(sPos, sPos + arg);
           sPos += arg;
       }
    }
    return resultString;
  }

  function reformatZIPCode (ZIPString) {   
    if (ZIPString.length == 5) return ZIPString;
    else return (reformat (ZIPString, "", 5, "-", 4));
  }

  function checkZIPCode (theField, fieldLabel, emptyOK) {   
    if (checkZIPCode.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else { 
      var normalizedZIP = stripCharsInBag(theField.value, ZIPCodeDelimiters)
      if (!isZIPCode(normalizedZIP, false)) 
        warnInvalid (theField, fieldLabel);
      else {  
      // if you don't want to insert a hyphen, comment next line out
       theField.value = reformatZIPCode(normalizedZIP)
       return true;
      }
    }
  } 
  
  function reformatUSPhone (USPhone) {   
    return (reformat (USPhone, "(", 3, ") ", 3, "-", 4))
  }

  function checkUSPhone (theField, fieldLabel, emptyOK) {
    if (checkUSPhone.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else {
      var normalizedPhone = stripCharsInBag(theField.value, phoneNumberDelimiters)
      if (!isUSPhoneNumber(normalizedPhone, false)) 
        warnInvalid (theField, fieldLabel);
      else {  
      // if you don't want to reformat as (123) 456-789, comment next line out
        theField.value = reformatUSPhone(normalizedPhone)
        return true;
      }
    }
  }
  
  function checkCreditCard (radio, theField) {   
    var cardType = getRadioButtonValue (radio)
    var normalizedCCN = stripCharsInBag(theField.value, creditCardDelimiters)
    if (!isCardMatch(cardType, normalizedCCN)) 
      return warnInvalid (theField, cardType);
    else {  
      theField.value = normalizedCCN
      return true
    }
  }
  
  function checkStringMatch (theField1, theField2, fieldLabel) {
    if (!compareStrings(theField1.value, theField2.value))
      warnInvalid (theField1, fieldLabel);
    else return true;
  }
  
  function warnInvalid (theField, fieldLabel) {
    theField.focus()
    alert('Invalid Field: ' + fieldLabel)
    return false  
  }
 
  
  
  
  