/*******************************************/
/* javascript by gonchuki - (c)soho - 2007 */
/*********************************************************************/
/* CEO Validator: based on code and documentation by Fernando Doglio */
/*********************************************************************/

var CEO = CEO || {};

CEO.Validator = {
	
	validations: [],
	field_regexp: /rq_([^_]+(_[^_]+)?)_([a-z]+)/,
	
	/* re-bind functions with external apis if available */
	init: function() {
		if (typeof $ == 'function') this.$ = $;
	},
	
	/* allows external extension of validations with extra checks/functions */
	/* the extending validation will receive the first validation result as a parameter */
	add_validation: function (key, validation, replace) {
		if ((typeof this.validations[key] == 'function') && !replace) {
			var function_to_extend = this.validations[key];
			this.validations[key] = function(field) {
				return validation(field, function_to_extend(field));
			}
		} else {
			this.validations[key] = validation;
		}
	},
	
	validate: function(form, no_jump, paint_field, no_error) {
		var vv = this.validations;
		var valid = true;
		var fields = form.elements;
		var matches = [];
		
		for (var i = 0; i < fields.length; i++) {
			var field = fields[i];
			if (field.getAttribute('id')) {
				if (matches = field.getAttribute('id').match(this.field_regexp)) {
					/* get the container */
					var container = this.$('contenedor_' + field.name) || this.$('contenedor_' + matches[1]);
					
					valid &= this.run_validation_on_field(field, matches[3], container, paint_field);
				}
			}
		}
		
		if (!valid) {
			if (!no_error && this.$('error')) this.$('error').style.display = 'block';
			if (!no_jump) window.location.href = window.location.href.split('#')[0] + '#error';
		} else {
			if (!no_error && this.$('error')) this.$('error').style.display = 'none';
		}
		
		return Boolean(valid);
	},
	
	run_validation_on_field: function(field, key, container, paint_field) {
		/* assume valid if no validation available for this field */
		if (!this.validations[key]) return true;
		/* check for optional and validate */
		var result = true;
		
		if ((this.has_attr(field, 'className', 'validates_optional') && this.validations['gen'](field)) ||
				!this.has_attr(field, 'className', 'validates_optional')) {
			result = this.validations[key](field);
		}
		
		if (container) {
			if (!result)
				this.mark_error(container, field);
			else
				this.clean_error(container, field);
		}
		
		if (paint_field) {
			if (!result)
				this.mark_error(field);
			else
				this.clean_error(field);
		}
		
		return result;
	},
	
	clone_validation: function(key) {
		return this.validations[key];
	},
	
	mark_error: function(container, field) {
		if (!this.has_attr(container, 'error_bucket', field.id )) {
			this.add_attr(container, 'className', 'error');
			this.add_attr(container, 'error_bucket', field.id);
		}
	},
	
	clean_error: function(container, field) {
		if (this.has_attr(container, 'error_bucket', field.id )) {
			this.remove_attr(container, 'error_bucket', field.id);
		}
		if (container['error_bucket'] === '') this.remove_attr(container, 'className', 'error');
	},
	
	has_attr: function(container, attr, value) {
		return (' ') ? (' ' + container[attr] + ' ').indexOf(' ' + value + ' ') > -1 : container[attr].indexOf(value) > -1;   
	},
	
	add_attr: function(container, attr, value) {
		if (!this.has_attr(container, attr, value)) container[attr] = ( (typeof container[attr] != 'undefined' ? container[attr] + ' ' : '' ) + value).replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
	},
	
	remove_attr: function(container, attr, value) {
		container[attr] = container[attr].replace(new RegExp('(^|\\s)' + value + '(?:\\s|$)'), '$1').replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
	},
	
	$: function(el) {
		return document.getElementById(el);
	}
	
};


/* -- standard validations -- */

/* gen: generic non-empty validation, any non-empty string validates */
CEO.Validator.add_validation('gen', function(field){ return(field.value.length > 0); });
/* str, txt: at least one letter from the alphabet */
CEO.Validator.add_validation('str', function(field){ return(/\w+/.test(field.value)); });
CEO.Validator.add_validation('txt', CEO.Validator.clone_validation('str'));
/* int: standard number */
CEO.Validator.add_validation('int', function(field){ return(/^\d+$/.test(field.value)); });
/* intc: complex number, allows dots and commas */
CEO.Validator.add_validation('intc', function(field){ return(/^\d[\d.,]*$/.test(field.value)); });
/* mail: email validation with full RFC 2822 compliance http://tools.ietf.org/html/rfc2822 */
CEO.Validator.add_validation('mail', function(field){ return(/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(field.value)); });
/* ci: cedula, format: 1234567-8  or two fields with '_guion' added to verification field */
CEO.Validator.add_validation('ci', function(field){ 
	if (field.form[field.name + '_guion']) {
		var ci = field.value;
		var dv = field.form[field.name + '_guion'].value;
		
		if (!/^\d{6,7}$/.test(field.value) || !/^\d$/.test(dv))  return false;
	} else {
		var regexp = /^(\d{6,7})[^\w]?-(\d)$/;
		
		if (!regexp.test(field.value)) return false;
		
		var matches = field.value.match(regexp);
		var ci = matches[1];
		var dv = matches[2];
	}
	
	var t1 = Math.abs(((
					 ((parseInt(ci[0], 10) * 2) % 10) +
					 ((parseInt(ci[1], 10) * 9) % 10) +
					 ((parseInt(ci[2], 10) * 8) % 10) +
					 ((parseInt(ci[3], 10) * 7) % 10) +
					 ((parseInt(ci[4], 10) * 6) % 10) +
					 ((parseInt(ci[5], 10) * 3) % 10) +
					 ((parseInt(ci[6], 10) * 4) % 10)) % 10) - 10) % 10;
		
	return (t1.toString() == dv);
});
/* sel: select control */
CEO.Validator.add_validation('sel', function(field){ return(field.selectedIndex !== 0); });
/* selm: select multiple control */
CEO.Validator.add_validation('selm', function(field){ return(field.length !== 0); });
/* radio, rad, chk: radio buttons and checkboxes, selection required */
CEO.Validator.add_validation('radio', function(field){ 
	var name = field.name;
	var type = field.type;
	var elems = field.form.getElementsByTagName('input');
	var valid = false;
	for(var i = 0; i < elems.length; i++) {
		if(elems[i].type == type && elems[i].name == name && elems[i].checked) {
			valid = true;
			break;
		}
	}
	return(valid);
});
CEO.Validator.add_validation('chk', CEO.Validator.clone_validation('radio'));
CEO.Validator.add_validation('rad', CEO.Validator.clone_validation('radio'));
/* confirm: confirmation fields for any field capabla of having value, 
					container and name of confirmation field must be declared as 'contenedor_#{name}_confirm' and '#{name}_confirm' */
CEO.Validator.add_validation('confirm', function(field){ 
	var field_name = field.name.match(/(\w+)_confirm/)[1];
	var field_to_confirm = field.form.elements[field_name];
	var confirm_key = field_to_confirm.getAttribute('id').match(/^\w+_(\w+)$/)[1];
	
	return ((CEO.Validator.has_attr(field_to_confirm, 'className', 'validates_optional') && !CEO.Validator.validations['gen'](field_to_confirm)) ||
				 ((field_to_confirm.value == field.value) && CEO.Validator.run_validation_on_field(field, confirm_key)));
});
/* day, month, year: only verified for range and type
									container is being taken with a fallback mechanism: instead of using the name, uses the id token */
CEO.Validator.add_validation('day', function(field){ return(CEO.Validator.run_validation_on_field(field, 'int') && parseInt(field.value, 10) >= 1 && parseInt(field.value, 10) <= 31  ); });
CEO.Validator.add_validation('month', function(field){ return(CEO.Validator.run_validation_on_field(field, 'int') && parseInt(field.value, 10) >= 1 && parseInt(field.value, 10) <= 12  ); });
CEO.Validator.add_validation('year', function(field){ return(CEO.Validator.run_validation_on_field(field, 'int') && parseInt(field.value, 10) >= 1000 && parseInt(field.value, 10) <= 2999 ); });
/* rut */
CEO.Validator.add_validation('rut', function(field){ 
	
	var vari = field.value;
	var dv = CEO.Validator.$('rut_guion').value;
	var suma = 0;
	var divi = 0;
	var rut = vari;
	var res = 1;
	var cont = 2;  
	
	if(!CEO.Validator.run_validation_on_field(field, 'int') || !CEO.Validator.run_validation_on_field(CEO.Validator.$('rut_guion'), 'str')) return false;
	
	for (var a = 1; a <= vari.length; a++){
		divi = (rut % 10);
		rut = rut - divi;
		rut = Math.ceil(rut / 10);
		res = divi * cont;
		suma = suma + res;
		cont++;
		if(cont == 8) cont = 2;
	}
	
	suma = 11 - (suma % 11);
	
	if (suma == 11) {
		suma = 0;
	} else if (suma == 10) {
		suma = "k";
	}
	
	return (dv == suma);
});

CEO.Validator.init();

/* compatibility layer to the old validator */
function validaForm(form, no_jump, paint_field, no_error) { return CEO.Validator.validate(form, no_jump, paint_field, no_error); }
