var checkObjects	= new Array();
var errors		= "";
var returnVal		= false;
var validate    	= true;

// JScript's best attempt at creating constants...
var BADCARD = 0, MC = 1, VISA = 2;
var AMEX = 3, DCCB = 4, DISC = 5;
var ENROUTE = 6, JCB = 7;

// ----------------------------------
// START CREDITCARD OBJECT DEFINITION
// ----------------------------------

//global private variable (as best as JScript can do it)
//that holds the reason that the card failed validation.
var FailedCause = "";

//formal definition of the CreditCard object
function CreditCard(num, month, year, date) {

	//remove -'s or spaces from the card number
	//interpret the credit card number as a string
	//regardless of entered data type...
	var re = /[ \-]*/g
	var tmpNum = new String(num);
	this.ccnum = tmpNum.replace(re, "");

	//add the entered date (no checks are made to
	//test the date when entered)
        this.ccmonth = month;
        this.ccyear  = year;
	this.ccdate = date;
}

//return string indicating why card failed verification
function GETCCFailureReason() {
	return FailedCause;
}

//returns entered ccnumber
function GETCCNumber() {
	return this.ccnum;
}

//returns entered ccexpiration date
function GETCCExpirationDate() {
	return this.ccdate;
}

//tests something passed with a passed regular expression
function testCCPrefix(match, pattern) {

	var re = pattern
	return re.test(match);
}

//determines the type of credit card - also validates
//the card by prefix. If this function returns 0,
//the card is definitely not valid... otherwise it
//returns a constant representing a Credit Card type
//constant from above...
function GETCCPrefix() {
	var cc = this.ccnum;
	var prefix = "";
    
  
        if (cc.length < 13) {
		FailedCause = "failed due to bad card number - length";
		return 0;
	}	

	// MASTERCARD
         prefix = cc.substring(0,2);
         if (cc.length == 16 && prefix >= "51" && prefix <= "55") 
	 	return MC;

  	// VISA
         prefix = cc.substring(0,1);
         if ((cc.length == 13 || cc.length == 16 ) && prefix == "4") 
		return VISA;	   


	// AMEX
         prefix = cc.substring(0,2);
         if (prefix == "34" || prefix == "37") 
		return AMEX;   


	// DCCB
         prefix = cc.substring(0,2);
         if (cc.length == 14 && (prefix == "36" || prefix == "38" || prefix == "30") )
	 	return DCCB;  
	 	 


	// DISC
	 prefix = cc.substring(0,4);
         if (cc.length == 16 && prefix == "6011") 
	 	return DISC; 

	// ENROUTE
	 prefix = cc.substring(0,4);
         if (prefix == "2014" || prefix == "2149") 
	 	return ENROUTE; 


	// JCB
	 prefix = cc.substring(0,4);
         if (prefix == "2131" || prefix == "1800") 
	 	return JCB;

 	prefix = cc.substring(0,1);
        if (prefix == "3" ) 
	 	return JCB; 

  

	FailedCause = "failed due to bad card number";
	return 0;
}

//returns the credit card type as a string based on the
//return code of GETCCPrefix( ) method
function resolveCCType(ccCode) {
	switch(ccCode) {
		case MC:
			return "MasterCard";
		case VISA:
			return "Visa";
		case AMEX:
			return "American Express";
		case DCCB:
			return "Diner's Club/Carte Blanche";
		case DISC:
			return "Discover";
		case ENROUTE:
			return "EnRoute";
		case JCB:
			return "JCB";
		default:
			return "Bad Card Prefix";
	}
}

//returns last 4 digits of the entered ccnumber
function GETLast4Digits() {
	var re = /(\d{4})$/
	var arr = re.exec(this.ccnum);
	return RegExp.$1;
}

//determines if a number is odd...
function isOdd(n) {
	return CBool(n %= 2);
}

//converts numbers to boolean
function CBool(exp) {
	if (exp > 0) {return true;}
	return false;
}

//performs a mod10 validation on an entered ccnumber
function mod10validation(cc) {
	var s = strReverse(cc), hOut = 0, t = "";
	for (var i = 0;i < s.length; i++) {
		if (isOdd(i+1)) {
			hOut += parseInt(s.charAt(i));
		} else {
			t = parseInt(s.charAt(i)) * 2;
			if (t > 9) {t -= 9;}
			hOut += parseInt(t);
		}
	}

	if (hOut % 10 == 0) {return true;}
	FailedCause = "failed credit card validation";
	return false;
}

//reverses a string
function strReverse(s) {
	var o = "";
	for (var i = s.length; i > -1; i--) {
		o += s.charAt(i);
	}
	return o;
}

//validate card number and expiration date
function validateCardDetails() {
	if (mod10validation(this.ccnum)) {
		//mod 10 valid - must check dates
		return checkExpirationDate(this.ccmonth, this.ccyear)
	} else {
		//mod 10 failed - no need to check dates
		return false;
	}
}

//test expiration date

function checkExpirationDate(enteredMonth, enteredYear) {

	//first check year.
	//if entered year is larger than today's year, it's valid
	//if years match, check months...
	//if today's month is greater or equal to entered
	//month, it's valid. anything else - invalid

	//handy regular expression to remember the month and year
	//input and keep them separate... Regular expressions rule!
//	var re = /(\d{1,2})[ \-\/](\d{4})/
//	var arr = re.exec(d);
//	var enteredMonth = parseInt(RegExp.$1);
//	var enteredYear = parseInt(RegExp.$2);
//	var tmpDate = new Date();
	
	// use the server date not the clients
	var thisMonth = g_current_month;
	var thisYear = g_current_year;
	//alert(tmpDate);

	//var thisMonth = tmpDate.GETMonth( ) + 1;
	//var thisYear = tmpDate.GETYear( );


	if (enteredYear > thisYear) {return true;}
	if (enteredYear == thisYear) {
		if (enteredMonth >= thisMonth) {return true;}
	}
	FailedCause = "failed date validation - expired card";
	return false;
}


//return version information about this object
function CreditCardObject_Version() {
	return "3.5";
}



//publicly exported methods...

//returns ccnumber
CreditCard.prototype.GETNumber = GETCCNumber;

//return ccdate
CreditCard.prototype.GETExpirationDate = GETCCExpirationDate;

//returns cctype constant
CreditCard.prototype.GETPrefix = GETCCPrefix;

//returns the real name of a cc based on it's constant
CreditCard.prototype.GETRealName = resolveCCType;

//returns the results of a mod10 validation
CreditCard.prototype.isValid = validateCardDetails;

//returns the last 4 numbers of the CC
CreditCard.prototype.GETLast4Digits = GETLast4Digits;

//returns the reason why the entered card failed...
CreditCard.prototype.GETFailureMessage = GETCCFailureReason;

//returns version info...
CreditCard.prototype.CreditCardObject_Version = CreditCardObject_Version;

// ----------------------------------
// END CREDITCARD OBJECT DEFINITION
// ----------------------------------



// -----------------------------------------------------------------------------
// define - Call this function in the beginning of the page. I.e. onLoad.
// n = name of the input field (Required)
// type= text, textarea, num, email, date, futuredate (Required)
// min = the value must have at least [min] characters (Optional)
// max = the value must have maximum [max] characters (Optional)
// d = (Optional)
// -----------------------------------------------------------------------------
function define(n, type, HTMLname, optional, min, max,  d)
{
	var p;
	var i;
	var x;
	var elemname = n;

	if (!d) d = document;

	if ((p=n.indexOf("?"))>0&&parent.frames.length)
	{

		d = parent.frames[n.substring(p+1)].document;
		n = n.substring(0,p);
	}

	if (!(x = d[n]) && d.all)
		x = d.all[n];

	for (i = 0; !x && i < d.forms.length; i++)
	{
		x = d.forms[i][n];
	}

	for (i = 0; !x && d.layers && i < d.layers.length; i++)
	{
		x = define(n, type, HTMLname, min, max, d.layers[i].document);
		return x;
	}


	eval("V_"+n+" = new formResult(elemname, x, type, HTMLname, optional, min, max);");

	checkObjects[eval(checkObjects.length)] = eval("V_"+n);

}

function formResult(elemname, form, type, HTMLname, required, min, max )
{
	this.elemname = elemname;
	this.form = form;
	this.type = type;
	this.HTMLname = HTMLname;
	this.required = required;
	this.min  = min;
	this.max  = max;
}






function verifydate(datestr, afterToday){
	window.onerror=null // for all other strange errors


	var err=0;
	var psj=0;
	a=datestr;
	if (a.length != 10) err=1
	mm = a.substring(0, 2)// month
	c = a.substring(2, 3)// '/'
	dd = a.substring(3, 5)// day
	e = a.substring(5, 6)// '/'
	yy = a.substring(6, 10)// year

	//basic error checking
	if (mm<1 || mm>12) err = 1
	if (c != '/') err = 1
	if (dd<1 || dd>31) err = 1
	if (e != '/') err = 1
	if (yy<0 || yy>10000) err = 1

	//advanced error checking

	// months with 30 days
	if (mm==4 || mm==6 || mm==9 || mm==11){
		if (dd==31) err=1
	}

	// february, leap year
	if (mm==2){
		// feb
		var g=parseInt(yy/4)
		if (isNaN(g)) {
			err=1
		}

		if (dd>29) err=1
		if (dd==29 && ((yy/4)!=parseInt(yy/4))) err=1
	}
/*

	// make this a 4-digit year
    	if (yy >= 90)
		yy = 19 + yy;
	else
		yy = 20 + yy;

*/
	// check if after todays date if requested
	if (afterToday) {
		// define todays date and the date to compare against
		var now = new Date();
		var cdate = new Date();

		// set the comparison date
		cdate.setMonth(mm - 1); // months start with 0
		cdate.setDate(dd);
		cdate.setFullYear(yy);

		// create a variable that concat's the numbers toGETher
		var cdatefull  = cdate.GETTime();
		var nowfull = now.GETTime();

		// provided date is after today's date
		if (cdatefull <= nowfull)
			err=1;
	}

	if (err==1)
		return false;
	else
		return true;

}

// A utility function that returns true if a string contains only
// whitespace characters.
function isblank(s)
{
    for(var i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
    }
    return true;
}

function displayData(text) {
   alert(text);
 }



var expire_month = "";
var expire_year = "";
// This is the function that performs form verification. It will be invoked
// from the onSubmit() event handler. The handler should return whatever
// value this function returns.
//
function verify(f)
{

    var msg;
    var empty_fields = "";
    var errors = "";
    var elementerrors = "";
    var elem = "";
	var oCC = "";

  if (!validate) {
    returnVal = true;
    return true;
  }


	if (checkObjects.length > 0)
	{

  		// Loop through the elements of the form, looking for all
 		// text and textarea elements that don't have an "optional" property
    		// defined. Then, check for fields that are empty and make a list of them.
    		// Also, if any of these elements have a "min" or a "max" property defined,
    		// then verify that they are numbers and that they are in the right range.
    		// Put toGETher error messages for fields that are wrong.
		//
		for (i = 0; i < checkObjects.length; i++)
		{
			// GET the element object from the array
			//
			elem = new Object();
			elem.elemname = checkObjects[i].elemname;


			// First check if the element name that was define in the HTML
			// page init function is a valid element name
			//
			var found = false;
			for(var x = 0; x < f.length; x++) {
        			var e = f.elements[x];

				if (e.name == elem.elemname) {
					found = true;
					break;
				}
			}

			// if we did not find it report a program error and skip processing
			// that element
			//
			if (!found) {
				elementerrors += "\n          " + elem.elemname;
				continue;
			}

			// finish GETting the rest of the element data
			//

			elem.form = checkObjects[i].form;
			elem.HTMLname = checkObjects[i].HTMLname;

			elem.min = checkObjects[i].min;
			elem.max = checkObjects[i].max;
			elem.type = checkObjects[i].type;
			elem.required = checkObjects[i].required;

			// Assign the value of the gadGET
			// elem.value = checkObjects[i].form.value; does not work in all cases
			//
			switch (elem.type) {
				case 'checkbox'	:
					for (var x=0;x < elem.form.length;x++) {
						var cmd = "elem.form."+ elem.elemname + "[x].checked";
						if (eval(cmd)) {
							var cmd = "elem.form."+ elem.elemname + "[x].value";
							elem.value = eval(cmd);
							//break; // only GET first checked item
						}
					}
					break;
				case 'radio'	:
					for (var x=0;x < elem.form.length;x++) {
						var cmd = "elem.form."+ elem.elemname + "[x].checked";
						if (eval(cmd)) {
							elem.value = "checked";
						}
					}
					break;


				case 'selectbox':
					
					if (checkObjects[i].form.selectedIndex != -1) {
						elem.value = checkObjects[i].form.options[checkObjects[i].form.selectedIndex].text;
					}
					if (elem.elemname == "store_expire_month") {
					   expire_month = elem.value;
					}
					else if (elem.elemname == "store_expire_year") {
					   expire_year = elem.value;
					}

					
					
					
					break;

				case 'specialcheckbox' :
					for (var x=0;x < elem.form.length;x++) {
						var cmd = "elem.form."+ elem.elemname + "[x].checked";
						if (eval(cmd)) {
							var cmd = "elem.form."+ elem.elemname + "[x].value";
							elem.value = eval(cmd);
							//break; // only GET first checked item
						}
					}
					break;
				
				default :
					elem.len = checkObjects[i].form.value.length;
					elem.value = checkObjects[i].form.value;
					break;
			}



			// Check if the required element contains any data
			//
			if ((elem.value == null) || (elem.value == "") || isblank(elem.value)) {
				if (elem.required) {
              		 		empty_fields += "\n          " + elem.HTMLname;
                			continue;
				}
           		}



			// we have data
			//
			else {


				// Now we know that a value exists, check for correct contents
				switch (elem.type) {
					case 'text' :
						if (((elem.min != null) && (elem.len < elem.min)) || ((elem.max != null) && (elem.len > elem.max))) {

        	            				errors += "- The field '" + elem.HTMLname + "' must be a string";
							if (elem.min != null)
                        					errors += " that is greater than " + elem.min;
                    					if (elem.max != null && elem.min != null)
                        					errors += " and less than " + elem.max;
                    					else if (elem.max != null)
                        					errors += " that is less than " + elem.max;
  		              	    				errors += " characters.\n";
						}
						break;

					case 'number' :
						var v = parseFloat(elem.value);

	                			if (isNaN(v) || ((elem.min != null) && (v < elem.min)) || ((elem.max != null) && (v > elem.max))) {

        	            				errors += "- The field '" + elem.HTMLname + "' must be a number";
							if (elem.min != null)
                        					errors += " that is greater than " + elem.min;
                    					if (elem.max != null && elem.min != null)
                        					errors += " and less than " + elem.max;
                    					else if (elem.max != null)
                        					errors += " that is less than " + elem.max;
  		              	    				errors += ".\n";
						}
						break;

					case 'date' :
						if (!verifydate(elem.value, false)) {
        	            				errors += "- The field '" + elem.HTMLname + "' must be a valid date (MM/DD/YYYY).\n";
						}
						break;

					case 'futuredate' :
						if (!verifydate(elem.value, false)) {
        	            				errors += "- The field '" + elem.HTMLname + "' must be valid date (MM/DD/YYYY)";
							errors += " after today's date.\n";
						}
						else if (!verifydate(elem.value, true)) {
							errors += "- The field '" + elem.HTMLname + "' must be after today's date.\n";
						}

						break;

					case 'email' :
						// Checking existense of "@" and ".".
						// Length of must >= 5 and the "." must
						// not directly precede or follow the "@"
						if ((elem.value.indexOf("@") == -1) || (elem.value.charAt(0) == ".") ||
						    (elem.value.charAt(0) == "@") || (elem.len < 6) || (elem.value.indexOf(".") == -1) ||
						    (elem.value.charAt(elem.value.indexOf("@")+1) == ".") ||
						    (elem.value.charAt(elem.value.indexOf("@")-1) == ".")) {

							errors += "- The field '" + elem.HTMLname + "' must be valid email address.";
						}
						break;

					case 'selectbox' :
						if (elem.value == "Select State") {
							errors += "- The field '" + elem.HTMLname + "' must be a valid state.";
						}
						break;
						
					case 'creditcard' :
			
					  	oCC = new CreditCard(elem.value, expire_month, expire_year, expire_month + "/" + expire_year);
					  	//oCC = new CreditCard(elem.value, "12/2008");

					 
						if ( oCC.GETPrefix() == 0 ) {
						   
  							
                				errors += "- The field 'Credit Card Number Invalid: ";
                				errors += oCC.GETFailureMessage();
           
                    	} else if (oCC.GETPrefix() == 4 || oCC.GETPrefix() == 6 || oCC.GETPrefix() == 7) {
                    				
                    		errors += "- The field 'Credit Card Number: " + oCC.GETRealName(oCC.GETPrefix()) + "\n";
                    		errors += "    We only except Visa/MasterCard/American Express/Discover";

                    				
                    	}
                    	else if (!oCC.isValid( )) {
                 					errors += "- The field 'Credit Card' Invalid: ";
                    				errors += oCC.GETFailureMessage();
                    	}
                    		
                    	


					  break;
					
					

					case 'checkbox' :
						break;


					case 'specialcheckbox' :
						// need to GET the id from the checkbox value and
						// check if a vendor and needdate is selected and
						// the correct value (future date)
						for (var x=0;x < elem.form.length;x++) {

							// check if the checkbox is checked
							var cmd = "elem.form."+ elem.elemname + "[x].checked";

							if (eval(cmd)) {
								// GET the value
								cmd = "elem.form."+ elem.elemname + "[x].value";
								var elementid = eval(cmd);

								// verify that a vendor and needdate has been selected
								// here since I have the element id now.
								//
								if (elementid != null && elementid != undefined) {

									// Only need to check if more than one vendor
									//
									if (eval("document.the_form.Vendor_"+elementid+".length") >1) {
										// check if at least one vendor is selected
										var checked=false;
										for (var x=0;x < eval("document.the_form.Vendor_"+elementid+".length");x++) {
											cmd = "document.the_form.Vendor_"+ elementid + "[x].checked";

											if (eval(cmd)) {
												checked = true;
											}
										}
										if (!checked) {
											errors += "- The field 'Vendor' must have at least one check per selected element.\n";

										}
									}

									// check need date
									cmd = "document.the_form.NeedDate_"+elementid +".value";
									var needdate= eval(cmd);

									// check if this required date exists
									if ((needdate == null) || (needdate == "") || isblank(needdate)) {
              		 						empty_fields += "\n          Need Date";
                								continue;
									}
									else if (!verifydate(needdate, false)) {
        	            						errors += "- The field '" + elem.HTMLname + "' must be valid date (MM/DD/YYYY)";
										errors += " after today's date.\n";
									}
									else if (!verifydate(needdate, true)) {
										errors += "- The field '" + elem.HTMLname + "' must be after today's date.\n";
									}
								}
							}
						}

						break;

					default :
						break;

				}

			}
    		}
	}



    	// Now, if there were any errors, display the messages, and
    	// return false to prevent the form from being submitted.
    	// Otherwise return true.
    	if (!empty_fields && !errors) {
        	returnVal = true;
        	return true;
    	}

    	msg  = "______________________________________________________\n\n"
    	msg += "The form was not submitted because of the following error(s).\n";
    	msg += "Please correct these error(s) and re-submit.\n";
    	msg += "______________________________________________________\n\n"

    	if (empty_fields) {
        	msg += "- The following required field(s) are empty:" + empty_fields + "\n\n";
        	if (errors) msg += "\n";
    	}

   	if (elementerrors) {
        	msg += "- The following element(s) do not exist on page (Programming Error):" + elementerrors + "\n";
        	if (errors) msg += "\n";
    	}

   	msg += errors;
    	alert(msg);

    	returnVal = false;
    	return false;

}

