function printfire() {
	if (document.createEvent) {
		try {
			printfire.args = arguments;
			var ev = document.createEvent("Events");
			ev.initEvent("printfire", false, true);
			dispatchEvent(ev);
		} catch (e) {
			// ??
		}
	}
}

String.prototype.is_phone = function() {
	return (9 == this.toString().replace(/\D/g, '').length)
}
String.prototype.is_nif_or_nie = function() {
	var str = this.toString().replace(/^X/i, '')
	str = str.replace(/^([0-9]{7}[A-Z])/i, '0$1')
	if (-1 == str.search(/^[0-9]{8}[A-HJ-NP-TV-Z]$/i))
		return false
	var stack = 'TRWAGMYFPDXBNJZSQVHLCKE'
  var pos = parseInt(str.substr(0, 8), 10) % 23;
	if (str.substr(8, 1).toUpperCase() == stack.substr(pos, 1))
  	return true
	return false
}
String.prototype.is_nie = function() {
	if (-1 == this.toString().search(/^X/i))
		return false
	return this.is_nif_or_nie()
}
String.prototype.is_nif = function() {
	return this.is_nif_or_nie()
}
String.prototype.is_cif = function() {
	var str = this.toString()
  if (-1 == str.search(/^[A-HK-NPQS][0-9]{7}[A-J0-9]/i))
		return false
	var sum = 0;
  for (var i = 1;  i < str.length - 1; i++) {
		atom = parseInt(str.substr(i, 1))
		sum += (i % 2 == 0) ? atom :
					((atom * 2 > 9) ? ((atom * 2) - 9) : atom * 2)
  }
  var control = (sum % 10 == 0) ? 0 : 10 - (sum % 10)
  // El control puede ser un número o una letra
  if (str.substr(8, 1) == control || str.substr(8, 1).toUpperCase() == 'JABCDEFGHI'.substr(control, 1))
     return true;      
  return false;
}

String.prototype.is_email = function() {
	return (-1 != this.toString().search(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i))
}
String.prototype.is_luhn = function() {
	var cc_number = this.toString()
	if (16 != cc_number.length)
		return false;
	var total = 0
	for (i = 0; i < 16; i ++) {
		atom = parseInt(cc_number.substr(i))
		total += (i % 2 == 0) ? ((2 * atom) > 9 ? (2 * atom) - 9 : (2 * atom)) : atom;
	}
	return (0 == total % 10)
}

function radio_value(group) {
	for (i = 0; i < group.length; i++) {
		if (group[i].checked) return group[i].value
	}
	return null
}

function isArray(a) {
	if (a)
		return a.constructor == Array
	else
		return false
}
/* * * Validation object and methods * * */
function Validator(options) {
	this.message = options["warn_str"] || "Hay un error en el formulario:"
	this.invalid_class_name = options['class_name'] || "invalid__"
	this.errors = []
	this.first_responder = null
	
	this.validate = validate
	this.process = process
	this.reset = reset
	this.val_email = val_email
	this.val_not_selected = val_not_selected
	this.val_not_selected_multiple = val_not_selected_multiple
	this.val_at_least_one_selected = val_at_least_one_selected
	this.val_at_least_one_checked = val_at_least_one_checked
	this.val_at_least_one_checked_multiple = val_at_least_one_checked_multiple
	this.val_length = val_length
	this.val_format = val_format
	this.val_real_date = val_real_date
	this.val_equal = val_equal
	this.val_checked = val_checked
	this.val_luhn = val_luhn
	this.val_cc_expiry_select = val_cc_expiry_select
	this.val_cif_nif_nie = val_cif_nif_nie
	this.val_phone = val_phone
	this.val_cuenta_corriente = val_cuenta_corriente
}

function validate() {
	if (this.errors.length > 0) {
		alert(this.message + "\n\n - " + this.errors.join("\n - "))
		try {
			this.first_responder.focus()
		} catch (e) {
			// do nothing
		}
	}
	return (this.errors.length == 0)
}
process = function(passed_test, ele, err_str, options) {
	var options = options || { }
	var eles = (isArray(ele) || options.treat_as_array) ? ele : [ele]
	if (passed_test) {
		for (var i = 0; i < eles.length; i++) {
			var ele_collection = (eles[i].length && eles[i].tagName != 'SELECT') ? eles[i] : [eles[i]]
			for (j = 0; j < ele_collection.length; j++) {
				var hl_ele = (ele_collection[j].tagName == 'SELECT') ? ele_collection[j][0] : ele_collection[j]
				hl_ele.className = hl_ele.className.replace(this.invalid_class_name, '')
			}
		}
	} else {
		for (var i = 0; i < eles.length; i++) {
			var ele_collection = (eles[i].length && eles[i].tagName != 'SELECT') ? eles[i] : [eles[i]]
			for (j = 0; j < ele_collection.length; j++) {
				var hl_ele = (ele_collection[j].tagName == 'SELECT') ? ele_collection[j][0] : ele_collection[j]
				if (-1 == hl_ele.className.search(this.invalid_class_name)) hl_ele.className += ' '+this.invalid_class_name
				this.first_responder = this.first_responder || ele_collection[j]
			}
		}
		this.errors.push(err_str)
	}
	return passed_test
}

reset = function(ele) {
	eles = $A(ele)
	for (var i = 0; i < eles.length; i++) {
		this.process(true, eles[i], '', {})
	}
}

// Works with: Text field
function val_email(myEle, errStr) {
	return this.process(myEle.value.is_email(), myEle, errStr)
}
// Works with: Select
function val_not_selected(myEle, bad_index, errStr) {
	return this.process((myEle.selectedIndex != bad_index), myEle, errStr)
}
// Works with: One or more Selects
function val_not_selected_multiple(myEle, bad_index, errStr) {
	selects = isArray(myEle) ? myEle : [myEle]
	valid = false
	for (i = 0; i < selects.length; i++) {
		if (selects[i].selectedIndex != bad_index) valid = true
	}
	return this.process(valid, selects, errStr)
}
// Works with: Select
function val_at_least_one_selected(myEle, errStr) {
	var valid = false
	for (var i = 0; i < myEle.length; i++) {
		if (myEle[i].selected) valid = true
	}
	return this.process(valid, myEle, errStr)
}
// Works with: Checkbox, radio
function val_at_least_one_checked(myEle, errStr) {
	var valid = false
	myEle = (myEle.length) ? myEle : [myEle]
	for (var i = 0; i < myEle.length; i++) {
		if (myEle[i].checked) valid = true
	}
	return this.process(valid, myEle, errStr, { treat_as_array: true })
}
// Works with: Collections of checkbox or radio groups
function val_at_least_one_checked_multiple(myEles, errStr) {
	var valid = true
	for (j = 0; j < myEles.length; j++) {
		var this_valid = false
		myEle = myEles[j]
		for (var i = 0; i < myEle.length; i++) {
			if (myEle[i].checked) this_valid = true
		}
		if (!this_valid) valid = false
	}
	return this.process(valid, myEles, errStr, { treat_as_array: true })
}
// Works with: Text field
function val_length(myEle, min, max, errStr) {
	min_ok = myEle.value.length >= min
	max_ok = max ? (myEle.value.length <= max) : true
	return this.process((min_ok && max_ok), myEle, errStr)
}
// Works with: Text field
function val_format(myEle, format, errStr) {
	return this.process((-1 != myEle.value.search(format)), myEle, errStr)
}
// Works with: Date Selects (.day, .month, .year)
function val_real_date(myForm, stub, errStr) {
	var date = myForm[stub+"[day]"]
	var month = myForm[stub+"[month]"]
	var year = myForm[stub+"[year]"]
	var dd = parseInt(date[date.selectedIndex].text)
	var mm = parseInt(month[month.selectedIndex].value) - 1
	var yyyy = parseInt(year[year.selectedIndex].text)
	var selected_date = new Date(yyyy, mm, dd)
	var valid = (selected_date.getDate() == dd && selected_date.getMonth() == mm && selected_date.getFullYear() == yyyy)
	return this.process(valid, [date, month, year], errStr)
}
// Works with: Radio, Checkbox
function val_checked(myEle, errStr) {
	return this.process(myEle.checked, myEle, errStr)
}
// Works with: Text fields
function val_equal(ele1, ele2, errStr) {
	return this.process((ele1.value == ele2.value), [ele1, ele2], errStr, {treat_as_array: true})
}
// Works with: Text field
function val_luhn(ele, errStr) {
	return this.process((ele.value.is_luhn()), ele, errStr)
}
// Works with: 2 Selects
function val_cc_expiry_select(sel1, sel2, errStr) {
	var year = 2000 + parseInt(sel1[sel1.selectedIndex].value)
	var month = parseInt(sel2[sel2.selectedIndex].value)
	var now = new Date()
	var now_year = now.getFullYear()
	var now_month = now.getMonth() + 1
	var valid = ((year > now_year) || (year == now_year && month >= now_month))
	return this.process(valid, [sel1, sel2], errStr, { treat_as_array: true })
}
// Works with: Text field
function val_cif_nif_nie(ele, errStr) {
	var str = ele.value
	return this.process((str.is_cif() || str.is_nif() || str.is_nie()), ele, errStr)
}
// Works with: Text field
function val_phone(ele, errStr) {
	var str = ele.value
	return this.process(str.is_phone(), ele, errStr)
}

function val_cuenta_corriente(ele1, ele2, ele3, ele4, errStr) {
	var c1 = ele1.value
	var c2 = ele2.value
	var c3 = ele3.value
	var c4 = ele4.value
	var parte1, parte2, pesos, DC1, DC2

	parte1 = c1 + c2
	parte2 = c4
	pesos = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6]
	DC1 = 0
	DC2 = 0

	for (var i = 8; i > 0; i--) {
		digito = parte1.substr(i - 1, 1)
		DC1 = DC1 + (pesos[i + 2 - 1] * digito)
	}
	resto = DC1 % 11
	DC1 = 11 - resto
	if (DC1 == 10) DC1 = 1
	if (DC1 == 11) DC1 = 0

	for (var i = 10; i > 0; i--) {
		digito = parte2.substr(i - 1, 1);
		DC2 = DC2 + (pesos[i - 1] * digito)
	}

	resto = DC2 % 11
	DC2 = 11 - resto

	if (DC2 == 10) DC2 = 1
	if (DC2 == 11) DC2 = 0
	DC = DC1 + "" + DC2
	
	return this.process((DC == c3), [ele1, ele2, ele3, ele4], errStr)
}
