function validate_cc(s) {
	var ccnumber = s.value.replace(/\D/g, '');
	if (ccnumber.length < 13 || ccnumber.length > 16) return 0;

	//
	// Credit card LUHN number checker
	// See http://en.wikipedia.org/wiki/Luhn_formula
	//
	var cclength = ccnumber.length;
	var parity = cclength % 2;
	var sum= 0;
	for (i= 0; i < cclength; i++) {
		var ccdigit=ccnumber.charAt(i);
		if (i % 2 == parity)
			ccdigit = ccdigit * 2;
		if (ccdigit > 9) 
			ccdigit = ccdigit - 9;
		sum = sum + parseInt(ccdigit);
	}
	var valid = (sum % 10 == 0);
	return valid
}

function validate_cc_expiry(month,year) {
	var now = new Date();
	var current_month = now.getMonth()+1;
	var current_year = now.getFullYear().toString().replace(/^\d\d/,'');
	if (year > current_year) return true;
	if (year == current_year && month >= current_month) return true;
	return false;
}

//
// This function returns the cardtype which corresponds to the
// cardnumber prefix.
//
// Sources:
// http://www.eway.com.au/support/ccprefixlength.aspx
// http://en.wikipedia.org/wiki/Credit_card_numbers
//
function get_cardtype(s) {
	var type = '';
	if (s.match(/^4\d+/)) type = "VISA";
	else if (s.match(/^34|35\d+/)) type = "American Express";
	else if (s.match(/^51|52|53|54|55\d+/)) type = "MasterCard";
	else if (s.match(/^36|38|30[12345]\d+/)) type = "Diners Club";
	else if (s.match(/^3|2131|1800\d+/)) type = "JCB";
	else if (s.match(/^56\d+/)) type = "Bank Card";
	return type;
}

FormsClassParser.addRules({
	validate_cc : {
		'onblur,onformsubmit' : function() {
			if (this.value.length && !validate_cc(this)) {
				return block_alert(this, "Invalid Credit Card Number.");
			}
			return true;
		}
	},
	validate_cc_expiry : {
		'onblur,onformsubmit' : function() {
			if (this.className.match(/validate_cc_expiry::month=([^:\s]+)/)) {
				var elem = this.form.elements[RegExp.$1];
				if (elem.value != "" && !validate_cc_expiry(elem.value, this.value))
					return block_alert(this, "Invalid Credit Card Expiry Date");
			} else if (this.className.match(/validate_cc_expiry::year=([^:\s]+)/)) {
				var elem = this.form.elements[RegExp.$1];
				if (elem.value != "" && !validate_cc_expiry(this.value, elem.value))
					return block_alert(this, "Invalid Credit Card Expiry Date");
			}
		}
	},
	//
	// Usage: set_cctype::<creditcard_type_formfield>
	//
	set_cctype : {
		'onkeyup,onblur' : function() {
			if (this.className.match(/set_cctype::([^:\s]+)/) &&
				this.value.length > 2) {
				var elem = this.form.elements[RegExp.$1];
				cardtype = get_cardtype(this.value);
				for (var i = 0; i < elem.options.length; i++) {
					if (elem.options[i].value == cardtype) {
						elem.options[i].selected = 'selected';
					}
				}
			}
			return true;
		}
	}
});
