/*
 * Generic Form Validator
 *
 * Version: 1.00
 * Autor: Alexander Concha Abarca <alex@buayacorp.com>
 * URI: http://www.buayacorp.com/
 * 
 * If you wish to use this script, you must keep these credits.
 * For any change and/or modifications please let me know so I can make the respective improvements...
 *
 * This script is protected under the Creative Commons license
 * http://creativecommons.org/licenses/by/2.0/
 *
 * TODO: To increase the elements to validate, at the moment supports:
 *  input 'text'
 *	textarea
 *	input 'password'
 *	select 'select-one'
 *	select 'select-multiple'
 */

/* 
	Funciones Personalizadas, deberian ir en otro script para mantener un orden
	Deben devolver verdadero o falso.
*/
isNumber = function (n) {	
	return isNaN(n) ? false : true;
}
checkEmail = function (s) {
	return s.search(/^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/gi) ? false : true;
}
/******************************************************************************************/

// Funciones comunes
getElement = function (id) {
	return document.getElementById(id);
}
getEvent = function (evt) {
	return (!evt) ? event : evt;
}
getEventSource = function (evt) {
	return evt.srcElement ?  evt.srcElement : evt.target;
}
/* Based on the script: http://www.scottandrew.com/weblog/articles/cbs-events
*/
addEvent = function (obj, evType, fn){
	if (typeof obj == 'string') obj = this.getElement(obj);
	if (!obj) return;
	obj['on' + evType] = fn;
	/*
	if (obj.addEventListener){
		obj.addEventListener(evType, fn, true); 
	   return true;
 	} 
	else if (obj.attachEvent){ 
	   var r = obj.attachEvent("on"+evType, fn); 
	   return r; 
	} 
	else { 
  		return false; 
	}*/
}
// Stores and creates the instances of the validator
var instances = []
function getInstance(frmid) {
	instances [frmid] = new Validator();
	instances[frmid].form = frmid;
	return instances [frmid];	
}
// Based on the work of JavierB: http://www.forosdelweb.com [Foro Javascript]
testPattern = function (evt, pattern) {
	evt = getEvent (evt);
	tecla = (document.all) ? evt.keyCode : evt.which;
	if (tecla==8) return true;
	if (!pattern) pattern = '\\d';
	pattern = new RegExp(pattern);
	return pattern.test(String.fromCharCode(tecla)); 
}

Validator = function () {}
/* 
	TODO: Refine the attributes
*/	
//	Defines as they are going away to show the found errors
Validator.prototype.showSummary = true;
Validator.prototype.summaryId = 'summary'; 
Validator.prototype.summaryDiv;
Validator.prototype.showMessageBox = false;
Validator.prototype.summaryText;
Validator.prototype.title = 'Please correct the following field(s)';
// Debugging for the Validator
Validator.prototype.DEBUG = true;
Validator.prototype.debugId = 'debug';
Validator.prototype.debugField;
// Used if not using CSS
Validator.prototype.bgcolor = '#CC0000';
Validator.prototype.color = '#FFFFFF';
// If using CSS
Validator.prototype.useCss = true;
Validator.prototype.cssClass = 'required';
Validator.prototype.classNames = [];
// Validation controls
Validator.prototype.controls = [];
Validator.prototype.patterns = [];
Validator.prototype.form;
Validator.prototype.functions = [];
// It stores the customized functions for the validation

// Adds a validation message
Validator.prototype.addDebugMsg = function (msg) {
	try {
		if (this.DEBUG && this.debugField) {
			this.debugField.value += (msg + '\n\n');
		}
	}
	catch (ex) {
		alert('this.addDebugMsg -> Validation Failed. \n' + ex) //Validation Failed
	}
}
// It adds an error message
Validator.prototype.addErrorMsg = function (id, msg) {
	try {
		if (!id || !msg) return;
		if (this.showMessageBox) this.summaryText += (' » ' + msg + '\n');
		else this.summaryText += ('<li class="error"><a href="#'+ id +'" onclick="document.getElementById(\'' + id + '\').focus()">' + msg + '</a></li>\n');
	}
	catch (ex) {
		this.addDebugMsg('this.addErrorMsg -> The error message cannot be added: ' + id + '\n' + ex);
	}
}
/* 
	Adds an event to an element using a regular expression
	TODO: Hto cause that this function can be initialized before the declaration of the element
*/
Validator.prototype.addRegExpEvent = function (id, evType, pattern){
	try {
		if (!id || !evType || !pattern) return;
		control = getElement(id);
		if (!control) return;
		this.patterns [id] = pattern;
		var tempInst = instances [this.form];
		fn = function (evt){
			instance = eval(tempInst);
			pattern = instance.patterns[ getEventSource(getEvent(evt)).id ];			
			return testPattern(evt, pattern);
		}
		addEvent(control, evType, fn);
	}
	catch (ex) {
		this.addDebugMsg('this.addRegExpEvent -> Onkeypress to the control could not be assigned to the event: ' + id + '\n' + ex); //Onkeypress to the control could not be assigned to the event
	}
}
// Adds customized functions
Validator.prototype.addCustomFunction = function (id, fn) {
	if (!fn) return;
	this.functions[id] = fn;
}
// Executes the function
Validator.prototype.evalCustomFunction = function (ctrl) {
	try {
		if (typeof ctrl == 'string') ctrl = this.getElement(ctrl);
		if (!ctrl) return;
		fn = this.functions[ctrl.id];
		if (!fn) return true;
		// TODO: To find a better form to evaluate the functions
		return eval(fn+'(\'' + ctrl.value + '\')');
	}
	catch (ex) {
		this.addDebugMsg('this.evalCustomFunction -> The customized function for the control could not be executed: ' + ctrl.id + '\n' + ex); //The customized function for the control could not be executed
		return true;
	}
}
// Determines if an element has a value or not
Validator.prototype.isValid = function (ctrl, default_val){
	try {
		if (!ctrl) return;
		if (default_val == null) default_val = '';
		if (typeof ctrl == 'string') ctrl = getElement(ctrl);	// To try to obtain the element

		// To validate if the title attribute  is set
		if	(ctrl.title != '' && 
			(ctrl.value == default_val || !this.evalCustomFunction(ctrl))) {
			if (!this.useCss || this.cssClass == '') {
				ctrl.style.backgroundColor = this.bgcolor;
				ctrl.style.color = this.color;
			}
			else {
				if ( ctrl.className != '' )	this.classNames [ ctrl.id ] =  this.ctrl.className ;
				ctrl.className = this.cssClass;
			}			
			if(!this.showSummary){
				alert(ctrl.title);
				ctrl.focus();
			}
			else{
				this.addErrorMsg(ctrl.id, ctrl.title);
			}
			return false;
		}	
		return true;
	}
	catch (ex) {
		this.addDebugMsg('this.isValid -> The control "' + ctrl.id + '" could not be validated: \n' + ex); //The control could not be validated
	}
}
// Initialize the validation
Validator.prototype.init = function (frm) {		
	try {
		if (typeof frm == 'string') frm=getElement(frm);
		if (!frm) return;
		this.form = frm;

		if (this.DEBUG) {
			this.debugField = getElement(this.debugId);
			if (!this.debugField) {
				alert('You need a "textarea" with an id of "' + this.debugId + '" in order to pass validation.')
				this.DEBUG = false;
			}
		}
		if (this.showSummary && !this.showMessageBox) {
			this.summaryDiv = getElement(this.summaryId);
			if (!this.summaryDiv) {
				alert('You need a "div" with an id of "' + this.summaryId + '" in order to be able to show the messages.')
				this.showSummary = false;
			}
		}
		for(i=0; i < frm.elements.length; i++){
			if (frm.elements[i].title != ''){
				switch( frm.elements[i].type ){
					case 'text':
					case 'textarea':
					case 'password':
					case 'select-one':
					case 'select-multiple':
						if ( frm.elements[i].id == '' )	frm.elements[i].id = frm.elements[i].name;
						this.controls[frm.elements[i].id] = frm.elements[i];
						var tempInst_ = instances [frm.id];
						fn = function (evt) {
							instance = eval(tempInst_);
							ctrl = getEventSource(getEvent(evt));
							if ( instance.isValid (ctrl.id) ) {				
								if (!instance.useCss) {
									ctrl.style.backgroundColor = '';
									ctrl.style.color = '';
								}
								else {
									ctrl.className = ! instance.classNames [ ctrl.id ] || instance.classNames [ ctrl.id ] == '' ? '' : instance.classNames [ ctrl.id ] ;
								}
							}
						}
						addEvent(frm.elements[i], 'blur', fn);
						break;
				}
			}
		}	
	}
	catch (ex) {
		this.addDebugMsg ('prepare -> No se pudo recuperar los elementos para la validaci&oacute;n: ' + frm.id + '\n' + ex);
		return true;
	}
}
// Clean the values of previous validations
Validator.prototype.clearValidation = function () {
	this.controls = new Array ();
	this.custom = new Array ();
}
// If the form was submitted ??? invoked of preference 
Validator.prototype.validate = function (frm) {
	if (typeof frm == 'string') frm = getElement(frm);
	if (!frm || typeof frm.elements == 'undefined') return;
	
	this.summaryText = '';
	
	if (!this.form || this.form.id != frm.id) {			
		this.clearValidation();
		this.init(frm);
	}

	var valid = true;
	var tmp;
	for (i in this.controls) {		
		tmp = this.isValid(this.controls[i]);
		if (!this.showSummary && !tmp) return false;
		valid &= tmp;
	}
	if (this.summaryText != null){
		if (this.showMessageBox){
			alert(this.title + '\n' + this.summaryText)
		}
		else{
			this.summaryDiv.innerHTML = '<div id="error"><h2 class="summary">' + this.title + '</h2>\n<ul>\n' + this.summaryText + '</ul></div>';
		}
	}
	else if (this.summaryDiv)
		this.summaryDiv.innerHTML = '';
		
	return valid == 0 ? false : true;
}