/**
 * @author DemonCcC
 * Date: 07-04-2007
 * Version: 0.8z
 *
 * <<<< Class for validate forms >>>>
 * 
 * 
 */

function elementVz(id)
{
	this.elementId = id;
	this.element;
	this.returnChangedValue = false;
	this.validations = new Array();
	this.returnFunction = false;
	this.className = '';
	this.changedValue = true;
	
	this.init = function()
	{
		if (this.element = document.getElementById(this.elementId))
			this.className = this.element.className;
	}
	
	this.addValidation = function (validatorFunction, message, parameter)
	{
		var key = this.validations.length;
		if (!parameter) parameter = '';
		this.validations[key] = new Array();
		this.validations[key]['function'] = validatorFunction;
		this.validations[key]['message'] = message;
		this.validations[key]['parameter'] = parameter;
	}
}

function validatorZ (id, load)
{
	
	var validatorZ = this;
	this.idForm = id;  
	this.form;
	this.elements = new Array();
	this.errorMessage = new Array();
	/**
     * error message's head.
     *
     * @var string
     * @default null
     */
	this.headErrorMessage = '';
	/**
     * error message's foot.
     *
     * @var string
     * @default null
     */
	this.footErrorMessage = '';
	/**
     * class of error (when the input is'nt correct).
     *
     * @var string
     * @default false
     */
	this.classError = false;
	/**
     * If it's false the form doesnt reset the values after the validation.
     *
     * @var bool
     * @default true
     */
	this.reset = true;
	/**
     * If it's false the form doesnt submit after the validation.
     *
     * @var bool
     * @default true
     */
	this.submit = true;
	/**
     * If it's false the form doesnt show alert message.
     *
     * @var bool
     * @default true
     */
	this.alert = true;
	/**
     * The function that is called after the validation. <br>
     * It receceive a array with the error messages as parameter.
     * @var bool
     * @default null
     */
	this.messageCustomFunction;
	/**
     * The function that is called after the validation. <br>
     * If it return true the form submits, else if return false <br>
     * the form does'nt submit
     * @var function
     * @default: none
     */
	this.submitCustomFunction;
	
	if (load != false)
	{
		if (typeof window.onload != 'function') 
		{
    		window.onload = function() 
			{
				validatorZ.setForm();
    		}
  		} 
		else 
		{
			oldOnLoad = window.onload;
		
    		window.onload = function() 
			{
      			oldOnLoad();
				validatorZ.setForm();
    		}
		}
	}

	this.setForm = function()
	{
		this.form = document.getElementById(this.idForm);
		this.form.onsubmit = function ()
		{
			return validatorZ.validate();	
		}
		
		for (var element in this.elements)
			this.elements[element].init();
	}
	
	/**
	 * ValidatorZ
	 *
	 * Type:     function<br>
	 * Purpose:  Submit the form.<br>
	 */
	
	this.submitForm = function ()
	{
		this.form.submit();
	}

	this.addElement = function(id)
	{
		this.elements[id] = new elementVz(id);
	}
	
	this.emptyElements = function()
	{
		this.elements = new Array();
	}

	/**
	 * ValidatorZ
	 *
	 * Type:     function<br>
	 * Purpose:  Add validation to form.<br>
	 * @param id
	 * @param validation function
	 * @param error message
	 * @param parameter
	 */
	
	this.addValidation = function (id, validatorFunction, message, parameter)
	{
		if (!this.elements[id]) this.addElement(id);
		this.elements[id].addValidation(validatorFunction, message, parameter);
	}
	
	/**
	 * ValidatorZ
	 *
	 * Type:     function<br>
	 * Purpose:  Enable the change value for this element when the form submits.<br>
	 * @param id
	 */
	
	this.returnChangedValue = function (id)
	{
		if (!this.elements[id]) this.addElement(id);
		this.elements[id].returnChangedValue = true;
	}
	
	/**
	 * ValidatorZ
	 *
	 * Type:     function<br>
	 * Purpose:  Add return function to this element when the form submits (for extra validation).<br>
	 * 			 The function must to be: function (element), where element is the form element.	
	 * @param id
	 * @param return validation
	 */
	
	this.addReturnFunction = function (id, returnFunction)
	{
		if (!this.elements[id]) this.addElement(id);
			this.elements[id].returnFunction = returnFunction;
	}
	
	this.validate = function()
	{
		for (var element in this.elements)
			for (var j = 0; j < this.elements[element].validations.length && this.elements[element].changedValue != false; j++)
			{
				if (this.elements[element].element)
				{
					this.elements[element].changedValue = this.elements[element].element.value;
					this.elements[element].changedValue = this.elements[element].validations[j]['function'](this.elements[element].changedValue, this.elements[element].validations[j]['message'], this.elements[element].validations[j]['parameter']);
					if (this.elements[element].changedValue) this.elements[element].element.className = this.elements[element].className
					else if (this.classError) this.elements[element].element.className = this.classError;
				}
			}
		if (!this.errorMessage.length)
		{
			for (var element in this.elements)
			{
				if (this.elements[element].returnChangedValue) this.elements[element].element.value = this.elements[element].changedValue;
				if (this.elements[element].returnFunction) this.elements[element].returnFunction(this.elements[element].element);
			}
			if (this.submit) return true;
			if (this.submitCustomFunction) return this.submitCustomFunction(this.form);
			if (this.reset) this.form.reset();
		}
		else 
		{
			for (var element in this.elements)
				this.elements[element].changedValue = true;
			if (this.alert) 
			{
				var stringMessageError = '';
				for (var i=0; i < validatorZ.errorMessage.length; i++)
					stringMessageError += validatorZ.errorMessage[i] + ' \n';
				alert(this.headErrorMessage + stringMessageError + this.footErrorMessage);				
			}
			else this.messageCustomFunction(this.errorMessage);
			this.errorMessage = new Array();	
		}
		return false;
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate value's length (must to be equal)<br>
	 * @param value for validate
	 * @param error message
 	 * @param lenght that must to be the value
 	 * @return the value
	 */
		
	this.checkLength = function (value, message, length)
	{
		if (value.length != length)
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return value;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate value's length (must to be max)<br>
	 * @param value for validate
	 * @param error message
 	 * @param lenght that must to be the value
 	 * @return the value
	 */
	
	this.checkMinLength = function (value, message, min)
	{
		if (value.length < min)
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return value;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate value's length (must to be minor)<br>
	 * @param value for validate
	 * @param error message
 	 * @param lenght that must to be the value
 	 * @return the value
	 */
	
	this.checkMaxLength = function (value, message, max)
	{
		if (value.length > max)
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return value;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate if value's a number<br>
	 * @param value for validate
	 * @param error message
 	 * @return the value
	 */
	
	this.checkNumber = function (value, message)
	{
		if (validatorZ.isNull(value)) return '';
		re = /^\d+$/;
	
		if (!re.test(value))
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return value;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate if value content numbers and signs<br>
	 * @param value for validate
	 * @param error message
 	 * @return the value without the signs
	 */
	
	this.checkNumberSigns = function (value, message)
	{
		re = /^[^A-Za-z]+$/;
		var number = value.replace(/[^0-9]/g, '');
	
		if (!re.test(value))
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return number;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate if value's a valid email<br>
	 * @param value for validate
	 * @param error message
 	 * @return the value
	 */
		
	this.checkEmail = function (value, message)
	{
		if (validatorZ.isNull(value)) return '';
		var re = /(^[0-9a-zA-Z]+(?:[._][0-9a-zA-Z]+)*)@([0-9a-zA-Z]+(?:[._-][0-9a-zA-Z]+)*\.[0-9a-zA-Z]{2,3})$/;
	
		if (!re.test(value)) 
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
	
		return value;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose: Evaluate if value fulfills with a mask<br>
	 * @param value for validate
	 * @param error message
 	 * @param objet that contain the masks and charsmask.<br>
 	 * 		  The objet must content:<br>
 	 * 		  <b>formats:</b> Array with the masks for validate<br>
 	 * 		  <b>maskChars:</b> Array with the mask chars<br>
 	 * 		  ex: {formats: ['XXX-XXX-XXXX'], maskChars: ['X']}
 	 * 
 	 * ex: {
 	 * @return an array that content the values separate for the mask chars.
	 */
		
	this.checkMask = function(value, message, parameters)
	{
		var chars = new Array();
		var error = true;
		for (var i = 0; i < parameters.formats.length && error; i++)
		{
			if (parameters.formats[i].length != value.length) continue;
			for (var j = 0; j < parameters.maskChars.length; j++)
				chars[j] = '';
			error = false;
			for	(var j = 0; j < parameters.formats[i].length && !error; j++)
			{
				if (parameters.formats[i].substr(j,1) != value.substr(j,1)) error = true;
				for (var k = 0; k < parameters.maskChars.length && error; k++)
				{
					if (parameters.formats[i].substr(j,1) == parameters.maskChars[k])
					{
						chars[k] += value.substr(j,1);
						error = false;
					}
				}
			}
		}
		if (error)
		{
			if (message != false) 
				validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return chars;
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate if value's a valid date<br>
	 * @param value for validate
	 * @param error message
 	 * @param Custom date format. Is an array that content the custom date format<br>
 	 *        for validate. ex: ['M/D/YYYY', 'MM-DD-YY']<br>
 	 *        (For default de function include generic formats) 
 	 * @return an array that content the month, day and year. 
	 */
	
	this.checkDate = function(value, message, format)
	{
		if (!format) var format = new Array('MM/DD/YY', 'M/DD/YY', 'M/D/YY','MM/D/YY',
									'MM/DD/YYYY', 'M/DD/YYYY', 'M/D/YYYY','MM/D/YYYY');
		var month_days = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
		var date = new Array();
		var parameters = new Array();
		
		parameters['formats'] = format;
		parameters['maskChars'] = new Array('M','D','Y');

		var date = validatorZ.checkMask(value, false, parameters);
		
		if (date)
		{
			for (i = 0; i < date.length; i++)
				date[i] = date[i].replace(/^0/g, ''); //BUG FIREFOX
							
			month = parseInt(date[0]);
			day = parseInt(date[1]);
			year = parseInt(date[2]);
			
			if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) month_days[1] = 29; 		
		
			if (month > 0 && month < 13)
				if (day > 0 && day <=  month_days[month - 1])
					return date;  	
		}
		validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
		return false;
	}
	
	
	this.checkDateCondition = function(value, message, condition)
	{
		var date = value.split('/') ;
		date = new Date (date[2], date[0] - 1, date[1]);
		if (eval(date.getTime() + ' ' + condition)) return value;
		else
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
	}

	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate if value content letters and minus sign<br>
	 * @param value for validate
	 * @param error message
 	 * @return the value
	 */
	
	this.checkIsNotSigns = function (value, message)
	{
		re = /^[A-Za-z\d\s_-]*$/;
	
		if (!re.test(value))
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return value;  	
	}
	
	this.checkLetters = function (value, message)
	{
		re = /^[A-Za-z\s-]+$/;
	
		if (!re.test(value))
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return value;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate if value is null<br>
	 * @param value for validate
	 * @param error message
 	 * @return the value
	 */
	
	this.checkNull = function (value, message)
	{
		re = /[^\s]/;
	
		if (!re.test(value))
		{
			validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
			return false;
		}
		return value;  	
	}
	
	/**
	 * Type:     function<br>
	 * Purpose:  Evaluate if value is equal to field's value<br>
	 * @param value for validate
	 * @param error message
	 * @param field for validate
 	 * @return the value
	 */

	this.checkField = function (value, message, field)
	{
		field = document.getElementById(field);
		if (field)
		{
			if (value != field.value)
			{
				validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
				return false;
			}
		}
		return value;  	
	}
	
	this.checkDistinctField = function (value, message, field)
	{
		field = document.getElementById(field);
		if (field)
		{
			if (value == field.value)
			{
				validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
				return false;
			}
		}
		return value;  	
	}
	
	this.checkSelect = function (value, message, notValue)
	{
		if (value != notValue) return value;
		
		validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
		return false;
	}
	
	this.checkChecked = function (value, message, id)
	{
		value = document.getElementById(id).checked;

		if (value) return value;
		
		validatorZ.errorMessage[validatorZ.errorMessage.length] =  message;
		return false;
	}
	
	this.isNull = function(value)
	{
		re = /[^\s]/;
		if (!re.test(value))
			return true;
		return false;
	}
}