// generic VerifyForm object
// you must instantiate one of these with v = new VerifyForm() and then access
// it through its methods and properties
function VerifyForm() {
  // modify v.msgSeparator to change separator between error messages
  this.msgSeparator = '\n';
  // modify v.blankValue to change what is considered a "blank" value in the form
  // for instance, if all fields should be considered blank when "n/a" is their
  // value, then you can set that
  this.blankValue   = '';
  // private array for storage of errors
  // don't access directly, use addError() and showErrors() defined below
  this._errors      = new Array();
  this._email_Errs='';
  //Values for submit button
  this.submit_msg="Processing...";
  // import functions defined below as methods of this object
  // see below for usage
  this.addError = _addError;
  this.showErrors = _showErrors;
  this.hasValue = _hasValue;
  this.getValue = _getValue;
  this.isEmail = _checkEmail;
  this.isValidCard = _checkCreditCard;
  this.isNumber = _checkNum;
  return this;
}

/////
//
// The following methods are for handling errors
//
/////

// v.addError() method
// adds an error message to queue, brings keyboard focus to first one
// may be modified someday to put a visual indicator next to fields
// field - the actual form field object
// msg - string of error text to show
// no return value
function _addError (field, msg) {
  if ( ! this._errors.length) {
    // IE 4.x Mac bug workaround: "object.method" produces error
    // instead of returning true when method exists!!!
    // therefore we also test for field.all here
    if (field.all || field.focus)  field.focus();
    if (field.value && (field.all || field.select)) field.select();
  }
  this._errors[this._errors.length] = msg;
}

// v.showErrors() method
// when done checking for errors, call this to do alert popup
// head - text to put above error msgs
// foot - text to put below error msgs
// returns true (ok) if no errors, false if there were errors
function _showErrors (head, foot) {
  if (this._errors.length) {
    alert((head ? head + this.msgSeparator : '') + this._errors.join(this.msgSeparator) + (foot ? this.msgSeparator + foot : ''));
    return false;
  }
  return true;
}

/////
//
// The following methods are for getting/testing data from form fields
// these are all safe for all known field types
// including multi-valued fields (same as multiple fields with same name)
// return values are true or value(s) for the following fields: if and when:
//     button: ignored
//   checkbox: checked and value is non-blank
//       file: value is non-blank
//     hidden: value is non-blank
//   password: value is non-blank
//      radio: checked and value is non-blank
//      reset: ignored
// select-one: selected and value is non-blank
// select-mul: selected and value is non-blank
//     submit: ignored
//       text: value is non-blank
//   textarea: value is non-blank
//  (unknown): value is non-blank
//
/////

// v.hasValue() method
// check if field has a value
// field - the actual form field object
// returns true/false
function _hasValue (field) {
  if ( ! field.type && field.length ) {
    for (var i = 0; i < field.length; i++)
      if (field[i].type && this.hasValue(field[i]))
        return true;
    return false;
  }
  if (/select/.test(field.type))
    return (field.selectedIndex != -1 && (field.options[field.selectedIndex].value != this.blankValue));
  if (/(checkbox|radio)/.test(field.type))
    return ( field.checked && (field.value != this.blankValue) );
  if (/(button|reset|submit)/.test(field.type))
    return false;
  return (field.value != this.blankValue)
}

// v.getValue() method
// get value of field if there is a value
// field - the actual form field object
// returns value or null
// note: on multi-valued fields, returns only the first value encountered
function _getValue (field) {
  if ( ! field.type && field.length ) {
    for (var i = 0; i < field.length; i++) {
      if (field[i].type) {
        var value = this.getValue(field[i]);
        if (value) return value;
      }
    }
    return null;
  }
  if (/select/.test(field.type))
    return ( (field.selectedIndex != -1 && (field.options[field.selectedIndex].value != this.blankValue))
      ? field.options[field.selectedIndex].value : null );
  if (/(checkbox|radio)/.test(field.type))
    return ( (field.checked && (field.value != this.blankValue)) ? field.value : null );
  return ( ( ! /(button|reset|submit)/.test(field.type) && (field.value != this.blankValue)) ? field.value : null )
}

//check number
function _checkNum(num){
	if(isNaN(num))
  		return false;
	else
		return true;
}

///////////////////////////////////////////////////////////////////////////
//Verify Email Function
function _checkEmail(sEmail) {
	var re;
	//length check: remove leading and trailing spaces and then test length
	//x@x.xx is the smallest address... that's 6 characters.
	sEmail = sEmail.replace(/^\s*|\s*$/g, "");
	if (sEmail == "undefined" || sEmail.length < 6) {
		this.email_err="too few characters!";
		return false;
	}
	//test for spaces before checking syntax. spaces are illegal in email address 
	re = /\s+/g
	if (re.test(sEmail)) {
		this.email_err="spaces not allowed!";
		return false;
	}
	//validate email address syntax
	re = /^(\w|[^_]\.|[\-])+((\@){1}([^_]))(([a-z]|[\d]|[\-]|\.)+|([^_]\.[^_])*)+\.[a-z]{2,6}$/i
	if (!re.test(sEmail)) {
		this.email_err="syntax error!";
		return false;
	}
	//validate domain part of the email against all known TLDs as of May 2001 
	re = /\.(a[c-gil-oq-uwz]|b[a-bd-jm-or-tvwyz]|c[acdf-ik-orsuvx-z]|d[ejkmoz]|e[ceghr-u]|f[i-kmorx]|g[abd-ilmnp-uwy]|h[kmnrtu]|i[delm-oq-t]|j[emop]|k[eg-imnprwyz]|l[a-cikr-vy]|m[acdghk-z]|n[ace-giloprtuz]|om|p[ae-hk-nrtwy]|qa|r[eouw]|s[a-eg-ort-vyz]|t[cdf-hjkm-prtvwz]|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[admrw]|com|net|org|edu|int|mil|gov|arpa|biz|pro|aero|coop|info|name|museum)$/i
	if (!re.test(sEmail)) {
		this.email_err="invalid domain!";
		return false;
	}
	//fix the @@ problem...
	re = /\@\@/
	return(!re.test(sEmail));
}

//Cleanup comma delimited list
function cleanCommaList(sInput) {
	sInput=trimStr(sInput);
	if (sInput.charAt(sInput.length-1)==',')
		sInput=sInput.substring(0,(sInput.length-1));
	var arr=sInput.split(',');
	for (i=0; i<arr.length; i++) {
		arr[i]=trimStr(arr[i]);
	}
	sInput=arr.join(',');
	return sInput;
}

//Trims leading and trailing spaces
function trimStr(sInput) {
	sInput = sInput.replace(/^\s*|\s*$/g, "");
	return sInput;
}

//Credit Card Verification
//returns card type which is true or 0 if card type is not VISA/MC/AMEX/DISC/DC
function _checkCreditCard(num) {
	num=num.replace(/\s+/g, "");
	var re = /^(4)(\d{12}|\d{15})$|^(5[1-5])\d{14}$|^(6011)\d{12}$|^(3[47])\d{13}$|^(3(0[0-5]|[68]))\d{11,12}$/
	var arr = re.exec(num);
	reVISA=/^4$/
	reMC= /^5[1-5]$/
	reAMEX=/^3[47]$/
	reDISC=/^6011$/
	reDCCB=/^3(0[0-5]|[68])$/

	if (reVISA.test(RegExp.$1)) {
		var cardtype='VISA';
	} else if (reMC.test(RegExp.$3)) {
		var cardtype='MC';
	} else if (reDISC.test(RegExp.$4)) {
		var cardtype='DISCOVER';
	} else if (reAMEX.test(RegExp.$5)) {
		var cardtype='AMEX';
	} else if (reDCCB.test(RegExp.$6)) {
		var cardtype='DINERSCLUB';
	} else {
		var cardtype=0;
	}
	if (_checkCCNum(num)) {
		return cardtype;
	} else {
		return false;
	}
}

//verifies mod10 check
function _checkCCNum(num) {
	var digit;
	var sum = 0;
	var flag = 0;
	for ( i=(num.length - 1); i>=0; i-- ) {
		if (flag == 1) {
			digit = parseInt(num.charAt(i)) * 2;
			if (digit > 9) digit -= 9;
			sum += digit;
			flag = 0;
		} else {
			sum += parseInt(num.charAt(i));
			flag = 1;
		}
	}
	if ((sum%10) == 0) {
		return true;
	} else {
		return false;
	}
}

