/*
Autor: Cruz Rosales
Última modificación: 20100920-1422
Contacto: crosalesc@gmail.com
~by__ _  __  |^|_  __  _ __ _ __  _   _ _ __   __
 / _ ` | _  \  __| _  \ '__| '_  \ | | | '_  \´  \
| (_)  | __ /  |_| ___/ |  | | | | |_| | | | | | |
 \ __,_|\___|\___|\___|_|  |_| |_|\___/|_| |_| |_|crc<>
*/
function fis_email(e) {
	return /^([a-z_][a-z_\d\-\.]*\@[a-z\d_][a-z_\d\-]*(\.[a-z_][a-z_\d\-]*)+)$/i.test(e);
}

function fis_date(val) {
	if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(val))
		return {is_date:false,error:-1,desc:'Formato de fecha no válido\nLa fecha debe estar en formato aaaa-mm-dd'};//Formato no válido
	var amd = val.split('-');
	if (amd[1]< 1 || amd[1] > 12)
		return {is_date:false,error:-2,desc:'Mes no válido'};
	var days_of_month = new Date(amd[0], amd[1], 0).getDate();
	if (amd[2] < 1 || amd[2] > days_of_month)
		return {is_date:false,error:-3,desc:'Días del mes no válido'};
	return {is_date:true,error:0,desc:'Ok'};
}

function fis_time(val) {
	var t = /(\d{1,2}):(\d{1,2})/.exec(val)
	return $.isArray(t) && 23 >= parseInt(t[1]) && 59 >= parseInt(t[2]) ? true : false
}

function fis_float(v) {
	return parseFloat(v) == v;
}

function fis_int(v) {
	if(!isNaN(parseInt(v)))
		return (parseInt(v) == v * 1);
	return false;
}

function fconsola($consola, mensaje) {
	$consola.append('<li>' + mensaje + '</li>')
}

$(function() {
	$('form.auto-validate').submit(function(e) {
		e.preventDefault()
		var $consola = $('<ul/>').appendTo($('.consola',this).empty())
		//required
		$('.required',this).each (function (i) {
			switch (this.nodeName.toLowerCase()) {
				case 'input':
					var val = $(this).val()
					var typ = $(this).attr('type').toLowerCase()
					var klass = $(this).attr('class')
					//radio
					if ('radio' == typ) {
						if (1 > $('[name=' + $(this).attr('name') + ']:checked', this.form).size()) {
							fconsola($consola, 'Se esperaba la selección de un elemento para el campo: ' + $(this).attr('title'))
							break
						}
					}
					//checkbox
					if ('checkbox' == typ) {
						if (1 > $('[name=' + $(this).attr('name').replace('[','\[').replace(']','\]') + ']:checked', this.form).size()) {
							fconsola($consola, 'Se esperaba la selección de al menos un elemento para el campo: ' + $(this).attr('title'))
							break
						}
					}
					//archivos
					if ('file' == typ) {
						var matrix = /types:(\w+)/.exec(klass)
						if ($.isArray(matrix) && false == new RegExp('\.' + matrix[1].split('_').join('|\.') + '$', 'i').test(val)) {
							fconsola($consola, 'Se esperaba un archivo: ' + matrix[1].replace(/_/g, ', ') + ' para el campo: ' + $(this).attr('title'))
							break
						}
					}
					//contraseñas
					if ('password' == typ) {
						//longitud
						var matrix = /min-length:([0-9]+)/.exec(klass)
						if ($.isArray(matrix) && parseInt(matrix[1]) > val.length) {
							fconsola($consola, 'La longitud mínima para el campo: ' + $(this).attr('title') + ' es de: ' + matrix[1])
							break
						}
						//empatar con
						var matrix = /match-with:(\w+)/.exec(klass)
						if ($.isArray(matrix) && $(':password[name=' + matrix[1] + ']', this.form).val() != val) {
							fconsola($consola, 'La contraseña para: ' + $(this).attr('title') + ' y su confirmación no coinciden')
							break
						}
					}
					//entradas texto
					if ('text' == typ) {
						//fecha
						if ($(this).hasClass('date') && !fis_date(val).is_date) {
							fconsola($consola, 'Se esperaba una fecha para el campo: ' + $(this).attr('title') + ' (aaaa-mm-dd)')
							break
						}
						//hora
						if ($(this).hasClass('time') && !fis_time(val)) {
							fconsola($consola, 'Se esperaba una hora para el campo: ' + $(this).attr('title') + ' (hh:mm)')
							break
						}
						//correos
						if ($(this).hasClass('email') && !fis_email(val)) {
							fconsola($consola, 'Se esperaba un correo para el campo: ' + $(this).attr('title'))
							break
						}
						//enteros
						if ($(this).hasClass('integer')) {
							//entero
							if (!fis_int(val)) {
								fconsola($consola, 'Se esperaba un número entero para el campo: ' + $(this).attr('title'))
								break
							}
							//rango
							var matrix = /range:(-?[0-9]+)to(-?[0-9]+)/.exec(klass)
							if ($.isArray(matrix) && (parseInt(matrix[1]) > parseInt(val) || parseInt(matrix[2]) < parseInt(val))) {
								fconsola($consola, 'Se esperaba un número entero para el campo: ' + $(this).attr('title') + ' y en un rango de ' + matrix[1] + ' a ' + matrix[2])
								break
							}
							//menor que
							matrix = /lower-than:(-?[0-9]+)/.exec(klass)
							if ($.isArray(matrix) && parseInt(matrix[1]) < parseInt(val)) {
								fconsola($consola, 'Se esperaba un número entero para el campo: ' + $(this).attr('title') + ' y menor que ' + matrix[1])
								break
							}
							//mayor que
							matrix = /greater-than:(-?[0-9]+)/.exec(klass)
							if ($.isArray(matrix) && parseInt(matrix[1]) > parseInt(val)) {
								fconsola($consola, 'Se esperaba un número entero para el campo: ' + $(this).attr('title') + ' y mayor que ' + matrix[1])
								break
							}
						}
						//decimales
						if ($(this).hasClass('decimal')) {
							//decimal
							if (!fis_float(val)) {
								fconsola($consola, 'Se esperaba un número decimal para el campo: ' + $(this).attr('title'))
								break
							}
							//rango
							var matrix = /range:(-?[0-9]+\.?[0-9]*)to(-?[0-9]+\.?[0-9]*)/.exec(klass)
							if ($.isArray(matrix) && (parseFloat(matrix[1]) > parseFloat(val) || parseFloat(matrix[2]) < parseFloat(val))) {
								fconsola($consola, 'Se esperaba un número decimal para el campo: ' + $(this).attr('title') + ' y en un rango de ' + matrix[1] + ' a ' + matrix[2])
								break
							}
							//menor que
							matrix = /lower-than:(-?[0-9]+\.?[0-9]*)/.exec(klass)
							if ($.isArray(matrix) && parseFloat(matrix[1]) < parseFloat(val)) {
								fconsola($consola, 'Se esperaba un número decimal para el campo: ' + $(this).attr('title') + ' y menor que ' + matrix[1])
								break
							}
							//mayor que
							matrix = /greater-than:(-?[0-9]+\.?[0-9]*)/.exec(klass)
							if ($.isArray(matrix) && parseFloat(matrix[1]) > parseFloat(val)) {
								fconsola($consola, 'Se esperaba un número decimal para el campo: ' + $(this).attr('title') + ' y mayor que ' + matrix[1])
								break
							}
						}
					}
					//simplemente un valor
					if ('' == val) {
						fconsola($consola, 'Se esperaba un valor para el campo: ' + $(this).attr('title'))
						break
					}
					break
				case 'select':
					if (1 > this.selectedIndex) {
						fconsola($consola, 'Se esperaba la selección de un valor para el campo: ' + $(this).attr('title'))
						break
					}
					break
				case 'textarea':
					if ('' == $(this).val()) {
						fconsola($consola, 'Se esperaba un valor para el campo: ' + $(this).attr('title'))
						break
					}
					break
				default:
			}
		})
		//if present files
		$(':file.if-present', this).each(function(){
			var val = $(this).val()
			var klass = $(this).attr('class')
			var matrix = /types:(\w+)/.exec(klass)
			if ('' != val && $.isArray(matrix) && false == new RegExp('\.' + matrix[1].split('_').join('|\.') + '$', 'i').test(val)) {
				fconsola($consola, 'Se esperaba un archivo: ' + matrix[1].replace(/_/g, ', ') + ' para el campo: ' + $(this).attr('title'))
			}
		})
		//todo ok?
		if(1 > $consola.children().size()) {
			var matrix = /if-ok-call\:(\w+)/.exec($(this).attr('class'))
			if ($.isArray(matrix)) {
				var call_back = eval(matrix[1])
				if('function' == typeof(call_back)) {
					call_back(this)
				} else {
					alert('Error inesparado, se esperaba una función')
				}
			} else {
				this.submit()
			}
		}
	})
})
