function Formulario (form, init) {

	var self = {

			errores: Array (),
			form:    null,
			init: {action:   null,
						 async:    true,
						 cache:    false,
						 data:     {},
						 email:    false,
						 campos:   {},
						 dataType: 'text',
						 ok:       null,
						 type:     'POST'
				},

			asInteger: function (valor) {
					valor = parseInt (valor);
					return isNaN (valor) ? 0 : valor;
				},

			enviar: function () {
					$.ajax ({ async:    this.init.async,
									 	cache:    this.init.cache,
									 	data:     this.init.data,
									 	dataType: this.init.dataType,
									 	type:     this.init.type,
									 	url:      this.init.url,
									 	error:    function (jqXHR, textStatus) { alert ('Error en la petición: ' + self.init.url); },
									 	success:  function (respuesta)
									 						{
									 							if (respuesta.substr (0, 4).toLowerCase () == 'msg:') alert (respuesta.substr (4));
									 							else if (self.init.ok) self.init.ok ({'respuesta': respuesta});
									 						}
						   		});
					return this;
				},

			formulario: function () {
					$ ('INPUT,TEXTAREA,SELECT,:checkbox', this.form).each (function () { self.validar (this, this.name) });
					if (this.errores.length)
					{	alert (this.errores [0].msg);
						this.errores [0].element.focus ();
					}	else
					{ if (this.init.url) this.enviar ();
						else if (this.init.action)
						{	this.form.attr ('action', this.init.action);
							this.form.submit ();
						} else alert ('Tiene que indicar alguna de las siguientes propiedades: action, url.');
					}
				},

			validar: function (element, name) {
					if (element.type != 'button' && ! element.disabled)
					{	var mask     = element.getAttribute  ('mask');
						var msg      = element.getAttribute ('msg');
						var req      = element.getAttribute ('req');
						var label    = element.getAttribute ('label');
						var value    = element.value;
						var error    = null;

						if (! msg) msg = name;
						if (mask) mask = mask.toLowerCase ();
						req  = req != null ? true : false; // contemplar la opción de otros valores
						if (element.getAttribute ('trim') != null) value = $.trim (value);

						if (req)
						{	if (element.type == 'checkbox')
							{	if (! element.checked) error = {'element': element, 'msg': msg};
							} else if (!	$.trim(value)) error = {'element': element, 'msg': 'Tiene que indicar el siguiente valor: ' + msg};
						}
						if (error) this.errores.push (error);
						else
						{	if (mask == 'email') value = this.validarEmail (element, msg);
							else if (mask == 'fecha') value = this.validarFecha (element, msg);
							else if (mask == 'float') value = this.validarFloat (element, msg);
							else if (mask == 'int') value = this.validarInt (element, msg);
						}

						if (element.getAttribute ('noenviar') != null ? false : true) {
							if (element.type == 'checkbox' && ! element.checked) return;
							if (element.type == 'radio') {
								if (element.checked) {
									if (! this.init.email || name.substr (0,2) == '__') this.init.data [name] = value;
									else if (this.init.data [name]) this.init.data [name].value = value;
									else this.init.data [name] = {value: value, label: label};
									return;
								}
								if (this.init.email && label && name.substr (0,2) != '__') {
									if (this.init.data [name]) this.init.data [name].label = label;
									else this.init.data [name] = {value: '', label: label};
								}
								return;
							}
							if (! this.init.email || name.substr (0,2) == '__') {
								if (name == '__captcha' && ! value) this.init.data [name] = '111';
								else this.init.data [name] = value;
							} else this.init.data [name] = {value: value, label: label};
						}
					}
				},

			validarEmail: function (element, msg) {
					var expr  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;

					element.value = $.trim (element.value);
					if (! element.value) return '';
					if (! expr.test (element.value)) self.errores.push ({'element': element, 'msg': 'El dato ' + msg + ' no es correcto, tiene que ser un email.'});
					return element.value;
				},

			validarFecha: function (element, msg) {
					var sep  = /[\/\.\-]/;
					var expr = /^([0-9]{1,2})+[\/\.\-]+([0-9]{1,2})+[\/\.\-]+([0-9]{1,4})$/;
					var ok   = false;

					element.value = $.trim (element.value);
					if (! element.value) return '';
					if (expr.test (element.value))
					{	var fecha = element.value.split (sep);
						fecha [0] = self.asInteger (fecha [0].replace (/^0*/g, ''));
						fecha [1] = self.asInteger (fecha [1].replace (/^0*/g, ''));
						fecha [2] = self.asInteger (fecha [2].replace (/^0*/g, ''));
						if (fecha [2] > 0 && fecha [2] < 100) fecha [2] += 2000;
						if (fecha [0] > 0 && fecha [1] > 0 && fecha [1] <= 12 && fecha [2] > 0)
						{	if (fecha [1] == 2)
							{	if (fecha [0] <= 28) ok = true;
								else if (fecha [0] == 29 && fecha [2] % 4 == 0) ok = true;
							} else if (fecha [1] == 4 || fecha [1] == 6 || fecha [1] == 9 || fecha [1] == 11) ok = fecha [0] < 31;
							else ok = fecha [0] < 32;
						}
					}
					if (ok)
					{	element.value = (fecha [0] < 10 ? '0' : '') + fecha [0] + '/' + (fecha [1] < 10 ? '0' : '') + fecha [1] + '/' + fecha [2];
						return element.value;
					}
					self.errores.push ({'element': element, 'msg': 'El dato ' + msg + ' no es correcto, tiene que ser una fecha (dd/mm/aaaa).'});
					return element.value;
				},

			validarFloat: function (element, msg) {
					var expr = /^-?[0-9]+[\.|,]?[0-9]*$/;

					element.value = $.trim (element.value);
					if (! element.value) return '';
					if (expr.test (element.value))
					{	element.value = element.value.replace (',', '.');
						return parseFloat (element.value);
					}
					self.errores.push ({'element': element, 'msg': 'El dato ' + msg + ' no es correcto, tiene que ser un valor decimal.'});
					return element.value;
				},

			validarInt: function (element, msg) {
					var expr = /^-?[0-9]+$/;

					element.value = $.trim (element.value);
					if (! element.value) return '';
					if (expr.test (element.value)) return parseInt (element.value);
					self.errores.push ({'element': element, 'msg': 'El dato ' + msg + ' no es correcto, tiene que ser un valor entero.'});
					return element.value;
				}
		};

	if (typeof init == 'undefined') init = {};
	if (form)
	{	self.form = $ (form);
		$.extend (self.init, init);
		self.formulario ();
		return self;
	} else alert ('Tiene que indicar un formulario');
	return null;
}
