var extendedCharacters = "_\\(\\)#!\\.,\\?@$\-/ :'\\s";

/*
When using a date dropdown, use this function to dynamically
redraw the day depending on the month and year - use as an onChange() event
--- month, day and year are select form elements
*/
function updateDay(month, day, year)
{
	// offset is set, if the month dropdown has more than 12 elements (in the case of a blank option at the top)
	// IMPORTANT: if there IS an offset for months, we assume the same offset for days!
	var offset = 0;
	if (month.length > 12)
		offset = month.length - 12;
		
	var maxDay = 31;
	if (month[3+offset].selected == true ||
		month[5+offset].selected == true ||
		month[8+offset].selected == true ||
		month[10+offset].selected == true)
	{
		maxDay = 30;
	}
	else if (month[1+offset].selected == true)
	{
		if (getSelectValue(year) != null && !isLeapYear(getSelectValue(year))) 
			maxDay = 28;
		else
			maxDay = 29;
	}
	
	if (day.selectedIndex > maxDay)
		day.selectedIndex = 0;
	
	while (day[maxDay+offset] != null)
		day[maxDay+offset] = null;
	
	for(var i=28; i<maxDay+offset; ++i)
		if (day[i] == null)
		{
			if (offset == 0)
				day[i] = new Option(i+1,i+1);
			else
				day[i] = new Option(i,i);
		}
}


/*
Pad Cents and Dollars
*/
function padCents(elem, required)
{
	var retVal = '';
	
	for (var i=0; i<elem.value.length; i++)
		if (isInteger(elem.value.charAt(i)))
			retVal += elem.value.charAt(i);
	
	if (retVal.length == 1)
		retVal = retVal+'0';
	else if (required && retVal == '')
		retVal = '00';
	
	elem.value = retVal; 
}

function padDollars(elem, required)
{
	var retVal = '';
	for (var i=0; i<elem.value.length; i++)
	{
		if (isInteger(elem.value.charAt(i)))
			retVal += elem.value.charAt(i);
		else
			break;
	}
	
	if (required && retVal.length == 0)
		retVal = '0';
		
	elem.value = retVal;
	
}

/*
* isValidInputString() - Returns true if all the characters in the 
* string are valid input characters
*/
function isValidInputString(s)
{
    var expression = new RegExp("[^A-Za-z0-9"+extendedCharacters+"]","g");
    return !expression.test(s);
}

/*
* getSelectValue() - Given a select, returns the value currently selected
*/
function getSelectValue(sel)
{
	return sel[sel.selectedIndex].value;
}

/*
* getSelectText() - Given a select, returns the text of the item currently selected
*/
function getSelectText(sel)
{
	return sel[sel.selectedIndex].text;
}

/*-------------------------------------------
* Checks for the existence of an email address.
* Since it is not a required field, if there is
* no email address, lets it pass. If anything
* is entered, then checks if the "@" character
* is present. If not generates an error message.
* Date: 12/09/1999
* Written by: Srirangan Tirumalai (Sri)
*--------------------------------------------*/
function isValidEmail(e)
{
    if (e.length == 0)
    {
        return true;
    }
    else
    {
      var reg1 = /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/; // not valid
      var reg2 = /^.+\@[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3})$/; // valid
      if (!reg1.test(e) && reg2.test(e)) { // if syntax is valid
          return true;
      }
      else
      {
          return false;
      }
    }
}

/*
* isValidZipcode() - Returns true if the string is a valid US zipcode
*/
function isValidZipcode(zip)
{
	// returns true for empty strings
	if (isBlank(zip))
		return true;

	if (!isValidInputString(zip))
		return false;

	// currently checks if the length is 5 or 10
    if (zip.length == 5)
    	if (isInteger(zip))
    		return true;
    	else
    		return false;
    
    if (zip.length == 10)
	{
		if (isInteger(zip.substring(0,5)) && isInteger(zip.substring(6,10)) && zip.charAt(5)=='-')
			return true;
	}
    	
    return false;
}

/* 
* isValidPhone() - Takes a phone number form element
* Returns true if the phone number could be formatted
*/
function isValidPhone(phone)
{
	if (!isValidInputString(phone.value))
		return false;
		
    var digits = phone.value.replace(/[^0-9]/g,"");
	if (digits.length < 10)
		return false;
		
	var phoneNum = "(" + digits.substr(0,3) + ") " + digits.substr(3, 3) + "-" + digits.substr(6, 4);
	
	// get rest of the phone number and append it at the end
	var digitsRead = 0;
	//var i = 0;
	for(var i=0; i<phone.value.length; i++)
	{
		if (isInteger(phone.value.charAt(i)))
		{
			digitsRead++
			if (digitsRead == 10)
				break;
		}
	}
	
	//var i = digitsRead;
	if (phone.value.substr(i+1,1) != " " && phone.value.substr(i+1,1) != "")
	{
		if (isInteger(phone.value.substr(i+1,1)))
			phoneNum += " x" + phone.value.substr(i+1);
		else
			phoneNum += " " + phone.value.substr(i+1);
	}
	else// if (phone.value.length > i+1)
		phoneNum += phone.value.substr(i+1);
	
	phone.value = phoneNum;
	return true;
}
/*
* validateForm() - loops through all of the form elements and returns an error string
* that corresponds to all of the elements that have not been filled out correctly
*/
function validateForm(form)
{
	var errstr = "";
	
	// An array of all of the radio buttons already validated
	// We keep track of which radios have already been validated
	// because all radio buttons appear in the elements[] array
	var radiosValidated = new Array;
	var radioIdx = 0;
	
	for(var i=0; i<form.elements.length; i++)
	{
		with(form)
		{
			if (elements[i].type == "text")
			{
				if (elements[i].required && isBlank(elements[i].value))
					errstr += elements[i].nicename + " is required\n";
				else if (!isBlank(elements[i].value))
				{
					if (elements[i].isinteger && !isInteger(elements[i].value))
						errstr += elements[i].nicename + " is not an integer\n";
					else if (elements[i].isnumber && !isNumber(elements[i].value))
						errstr += elements[i].nicename + " is not a number\n";
					else if (elements[i].iszip && !isValidZipcode(elements[i].value))
						errstr += elements[i].nicename + " is not a valid zip code\n";
					else if (elements[i].isphone && !isValidPhone(elements[i]))
						errstr += elements[i].nicename + " is not a valid phone number - Please use the following format: (503) 123-4567 x123\n";
					else if (elements[i].isemail && !isValidEmail(elements[i].value))
						errstr += elements[i].nicename + " is not a valid email address - Please use the following format: username@domain.com\n";
				}
			}
			else if (elements[i].type == "textarea")
			{
				if (elements[i].required && isBlank(elements[i].value))
					errstr += elements[i].nicename + " is required\n";
			}
			else if (elements[i].type == "password")
			{
				if (elements[i].required && isBlank(elements[i].value))
					errstr += elements[i].nicename + " is required\n";
			}
			else if (elements[i].type == "select-one")
			{
				if (elements[i].required && elements[i].selectedIndex == 0)
					errstr += elements[i].nicename + " is required\n";
			}
			else if (elements[i].type == "radio")
			{
				// First check if this radio button has
				// been validated already or not
				var alreadyValidated = false;
				for(var k=0; k<radiosValidated.length; k++)
				{
					if (elements[i].name == radiosValidated[k])
					{
						// The radio button has already been validated
						alreadyValidated = true;
						break;
					}
				}

				// We will check for requiredness if the radio has not already
				// been validated
				if (!alreadyValidated)
				{
					if (elements[i].required == true)
					{
						// loop through all radios with the same name
						var radioName = elements[i].name;
						var checked = false;
						for(var j=0; j<elements.length; j++)
						{
							if (elements[j].name == radioName && elements[j].checked)
							{
								checked = true;
								break;
							}
						}
					
						if (!checked)
							errstr += elements[i].nicename + " is required\n";
					}
					
					radiosValidated[radioIdx++] = elements[i].name;
				}
			}
		}
	}
	
	return errstr;
}

/*
* isBlank() - returns true if a string contains only whitespace characters
*/
function isBlank(str)
{
	if (str == "")
		return true;
	else
	  	return !str.match(/[^\s]/);
}

/*
* isNumber() - returns true if the string is a number
*/
function isNumber(str)
{
	numdecs = 0
	for (i = 0; i < str.length; i++) {
		mychar = str.charAt(i)
		if ((mychar >= "0" && mychar <= "9") || mychar 
			== ".") {
			if (mychar == ".")
				numdecs++
		}
		else 
			return false
	}
	if (numdecs > 1)
		return false	
	return true
}

/*
* isInteger() - returns true if all characters in the string are numbers
*/
function isInteger(i)
{
	return i.match(/^[0-9]*$/);
}


/*
* isLeapYear() - returns true if the year is a leap year
*/
function isLeapYear(year)
{
   if (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0))
      return true;
   return false;
}

/*
* getCurrentYear() - returns the current year
*/
function getCurrentYear()
{
   aDate = new Date();
   return aDate.getFullYear();
}

// Validate credit card info.

var creditCardDelimiters = " -"

function isValidCreditCard(theField)
{
    var normalizedCCN = theField.value.replace(/[- ]/g,"");
    if (!isAnyCard(normalizedCCN))
       return false
    else
    {  
		theField.value = normalizedCCN
       	return true;
    }
}

/*  ================================================================
    Credit card verification functions
    Originally included as Starter Application 1.0.0 in LivePayment.
    ================================================================ */

/*  ================================================================
    FUNCTION:  isCreditCard(st)

    INPUT:     st - a string representing a credit card number

    RETURNS:  true, if the credit card number passes the Luhn Mod-10
            test.
          false, otherwise
    ================================================================ */

function isCreditCard(st) {
  // Encoding only works on cards with less than 19 digits
  if (st.length > 19)
    return (false);

  sum = 0; mul = 1; l = st.length;
  for (i = 0; i < l; i++) {
    digit = st.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--;
  }

// Uncomment the following line to help create credit card numbers
// 1. Create a dummy number with a 0 as the last digit
// 2. Examine the sum written out
// 3. Replace the last digit with the difference between the sum and
//    the next multiple of 10.

//  document.writeln("<BR>Sum      = ",sum,"<BR>");
//  alert("Sum      = " + sum);

  if ((sum % 10) == 0)
    return (true);
  else
    return (false);
} 


/*  ================================================================
    FUNCTION:  isVisa()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid VISA number.

          false, otherwise

    Sample number: 4111 1111 1111 1111 (16 digits)
    ================================================================ */

function isVisa(cc)
{
  if (((cc.length == 16) || (cc.length == 13)) &&
      (cc.substring(0,1) == 4))
    return isCreditCard(cc);
  return false;
}  


/*  ================================================================
    FUNCTION:  isMasterCard()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid MasterCard
            number.

          false, otherwise

    Sample number: 5500 0000 0000 0004 (16 digits)
    ================================================================ */

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;
}


/*  ================================================================
    FUNCTION:  isAmericanExpress()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid American
            Express number.

          false, otherwise

    Sample number: 340000000000009 (15 digits)
    ================================================================ */

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;

}


/*  ================================================================
    FUNCTION:  isDinersClub()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid Diner's
            Club number.

          false, otherwise

    Sample number: 30000000000004 (14 digits)
    ================================================================ */

function isDinersClub(cc)
{
  firstdig = cc.substring(0,1);
  seconddig = cc.substring(1,2);
  if ((cc.length == 14) && (firstdig == 3) &&
      ((seconddig == 0) || (seconddig == 6) || (seconddig == 8)))
    return isCreditCard(cc);
  return false;
}


/*  ================================================================
    FUNCTION:  isCarteBlanche()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid Carte
            Blanche number.

          false, otherwise
    ================================================================ */

function isCarteBlanche(cc)
{
  return isDinersClub(cc);
}


/*  ================================================================
    FUNCTION:  isDiscover()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid Discover
            card number.

          false, otherwise

    Sample number: 6011000000000004 (16 digits)
    ================================================================ */

function isDiscover(cc)
{
  first4digs = cc.substring(0,4);
  if ((cc.length == 16) && (first4digs == "6011"))
    return isCreditCard(cc);
  return false;
}


/*  ================================================================
    FUNCTION:  isEnRoute()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid enRoute
            card number.

          false, otherwise

    Sample number: 201400000000009 (15 digits)
    ================================================================ */

function isEnRoute(cc)
{
  first4digs = cc.substring(0,4);
  if ((cc.length == 15) &&
      ((first4digs == "2014") ||
       (first4digs == "2149")))
    return isCreditCard(cc);
  return false;
}


/*  ================================================================
    FUNCTION:  isJCB()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is a valid JCB
            card number.

          false, otherwise
    ================================================================ */

function isJCB(cc)
{
  first4digs = cc.substring(0,4);
  if ((cc.length == 16) &&
      ((first4digs == "3088") ||
       (first4digs == "3096") ||
       (first4digs == "3112") ||
       (first4digs == "3158") ||
       (first4digs == "3337") ||
       (first4digs == "3528")))
    return isCreditCard(cc);
  return false;
}


/*  ================================================================
    FUNCTION:  isAnyCard()

    INPUT:     cc - a string representing a credit card number

    RETURNS:  true, if the credit card number is any valid credit
            card number for any of the accepted card types.

          false, otherwise
    ================================================================ */

function isAnyCard(cc)
{
  if (!isCreditCard(cc))
    return false;
  if (!isMasterCard(cc) && !isVisa(cc) && !isAmericanExpress(cc) && !isDinersClub(cc) &&
      !isDiscover(cc) && !isEnRoute(cc) && !isJCB(cc)) {
    return false;
  }
  return true;
}


/*  ================================================================
    FUNCTION:  isCardMatch()

    INPUT:    cardType - a string representing the credit card type
          cardNumber - a string representing a credit card number

    RETURNS:  true, if the credit card number is valid for the particular
          credit card type given in "cardType".

          false, otherwise
    ================================================================ */

function isCardMatch (cardType, cardNumber)
{
    var doesMatch = true;

    if ((cardType == "Visa") && (!isVisa(cardNumber)))
        doesMatch = false;
    if ((cardType == "MasterCard") && (!isMasterCard(cardNumber)))
        doesMatch = false;
    if ((cardType == "AMEX") && (!isAmericanExpress(cardNumber)))
                doesMatch = false;
    if ((cardType == "Discover") && (!isDiscover(cardNumber)))
        doesMatch = false;
    if ((cardType == "JCB") && (!isJCB(cardNumber)))
        doesMatch = false;
    if ((cardType == "DINERS") && (!isDinersClub(cardNumber)))
        doesMatch = false;
    if ((cardType == "CARTEBLANCHE") && (!isCarteBlanche(cardNumber)))
        doesMatch = false;
    if ((cardType == "ENROUTE") && (!isEnRoute(cardNumber)))
        doesMatch = false;
    return doesMatch;
}

/*************************************
phone-formatting functions.  these only 
work in Internet Exploder.
**************************************/
function phoneFormat()
{
	if (event.keyCode < 48 || event.keyCode > 57)
	{
		event.returnValue = false;
		return;
	}
	
	var elem = event.srcElement;
	var val = elem.value;
	var len = val.length;
	var newchar = String.fromCharCode(event.keyCode);
	var pos = getCursorPos(elem);
	
	if (pos < len)
	{
		while (!isInteger(val.charAt(pos)) && pos < len)
			pos++;
		
		elem.value = val.substr(0, pos) + newchar + val.substr(pos+1);
		
		//event.returnValue = false;
		var newpos = pos + 1;
		while (!isInteger(val.charAt(newpos)) && pos < len)
			newpos++;
		
		setCursorAt(elem, newpos);
	}
	else
	{
		switch(pos)
		{
			case 0:
				elem.value = '(' + newchar;
				break;
			case 3:
				elem.value = val + newchar + ') ';
				break;
			case 4:
				elem.value = val + ') ' + newchar;
				break;
			case 5:
				elem.value = val + ' ' + newchar;
				break;
			case 8:
				elem.value = val + newchar + '-';
				break;
			case 9:
				elem.value = val + '-' + newchar;
				break;
			case 14:
				elem.value = val + ' x' + newchar;
				break;
			case 15:
				elem.value = val + 'x' + newchar;
				break;
			default:
				elem.value += newchar;
				break;
		}
	}
	
	event.returnValue = false;
}

function setCursorAt(elem, pos)
{
	if (elem.createTextRange)
	{
		var r = elem.createTextRange();
		r.moveStart('character', pos);
		r.collapse();
		r.select();
	}
}

function getCursorPos(elem)
{
	var saveText = elem.value;  // save for restoring later
	//elem.focus(); // n.c.e. commented this line out because it didn't have any effect when used from phoneFormat()
	var range = document.selection.createRange();
	var weirdStr = String.fromCharCode(1);   // a weird string to recognize the place
	range.text = weirdStr;
	var pos = elem.value.indexOf(weirdStr);  // get the position
	elem.value = saveText;                   // restore the previous text
	range = elem.createTextRange();
	range.move('character', pos);            // restore the cursor (also shows how to set the cursor)
	range.collapse();
	range.select();
	
	return pos;
}

