/**
 * Luiz Paulo dos Prazeres Junior
 * 
 * @class FormValidator 
 * 
 * Generic class to valid form fields
 * 
 */
var message = message != undefined ? message : {Verify_this_field: "Verifique este campo"};
var lang = (lang == undefined) ? "en" : lang;
var FormValidator = {
	lastError: [],
	lang: lang,
	dateFormat: {
		en		: "mm/dd/YYYY",
		enPos	: { y: 2, m: 0, d: 1 },
		pt		: "dd/mm/YYYY",
		ptPos	: { y: 2, m: 1, d: 0 },
		es		: "mm/dd/YYYY",
		esPos	: { y: 2, m: 1, d: 0 }
	}
};

jQuery.extend(FormValidator, {
	validateForm: function(fieldsJSonList) {
		
		var result = false;
		if(fieldsJSonList != undefined) {
			result = this.validFieldList(fieldsJSonList);
		} else {
			alert("JSON field list is NULL!");
		}
		
		return result;
	},//Method validateForm
	
	validFieldList: function (fieldList) {
		
		//Format error message to undefined field
		if(fieldList == undefined) {
			this.onError([{ message: "Form fields is not defined." }]);
			return false;
		}
		
		var invalidFields = new Array();
		for(var i = 0; i < fieldList.length; i++) {
			var field = fieldList[i];
			
			//Format error message to undefined field
			if(field.field == undefined) continue;
			
			if(field.message == undefined) { field.message = this.getMessage(field); }
			
			var isValidField = false;
			if(field.field.length == undefined || typeof field.field.tagName != "undefined" || this.composedValidation(field.type)) {
				
				if(jQuery(field.field).parents(".ignoreValidation").length > 0) {
					isValidField = true;
				} else {
					isValidField = this.getValid(field);
				}
			} else {
				//Confirm field valid
				if(field.type == this.CONFIRM && !this.validMethods[this.CONFIRM](field)) {
					
					var unitField = jQuery.extend({}, field);
					unitField.field = field.field[1];
					invalidFields.push(unitField);
					unitField.message = unitField.field.title;
					invalidFields.push(unitField);
					continue;
				}
				
				for(var j = 0; j < field.field.length; j++) {
					
					if(jQuery(field.field[j]).parents(".ignoreValidation").length > 0) {
						isValidField = true;
					} else {
						var unitField = jQuery.extend({}, field);
						unitField.field = field.field[j];
						if(!this.getValid(unitField)) invalidFields.push(unitField); //else the field is valid
					}	
				}
				continue;
			}
			if(!isValidField) invalidFields.push(field); //else the field is valid
		}
		
		if(invalidFields.length == 0) return true;
		
		this.onError(invalidFields);
		return false;
		
	},//Method validFieldList
	
	composedValidation: function (fieldType) {
		return (fieldType == this.UNIQUE_VALUES);
	},
	
	getValid: function (field) {
		
		//Required valid
		if(!this.validMethods.validRequired(field)) return false;
		
		//Unique field valid
		if(field.type == this.UNIQUE_VALUES && !this.validMethods[this.UNIQUE_VALUES](field)) return false;
		
		//Global valid
		if(field.type != undefined && this.validMethods[field.type] != undefined) {
			return this.validMethods.test(field);
		}
		
		//This field is valid
		return true;
	},//Method getValid
	 
	getMessage: function (fieldJson) {
		var fieldError = (fieldJson.errorFocus != undefined) ? 
			fieldJson.errorFocus : fieldJson.field;
		
		var field = (fieldError.tagName == undefined && fieldError.length != undefined) ? 
			fieldError[0] : fieldError;
		
		if(field.title != undefined && field.title != "") {
			return field.title
		} else {
			return message.Verify_this_field;
		}
	},//Method getMessage
	
	MAIL:		"validMail",
	NUMBER:		"validNumber",
	INTEGER:	"validInteger",
	IP:			"validIp",
	CEP:		"validCep",
	CPF:		"validCpf",
	PHONE:		"validPhone",
	DATE:		"validDate",
	DATE_YMD:	"validDateYMMDD",
	REQUIRED:	"validRequired",
	CONFIRM :	"validConfirm",
	FILE:		"validFile",
	FUNCTION:   "validFunction",
	UNIQUE_VALUES: "validUniqueValues",
	
	types: function () {
		
		return ''
			+ "\n" + 'FormValidator.MAIL'
			+ "\n" + 'FormValidator.NUMBER'
			+ "\n" + 'FormValidator.INTEGER'
			+ "\n" + 'FormValidator.IP'
			+ "\n" + 'FormValidator.CEP'
			+ "\n" + 'FormValidator.CPF'
			+ "\n" + 'FormValidator.PHONE'
			+ "\n" + 'FormValidator.DATE'
			+ "\n" + 'FormValidator.DATE_YMD'
			+ "\n" + 'FormValidator.REQUIRED'
			+ "\n" + 'FormValidator.CONFIRM'
			+ "\n" + 'FormValidator.FILE'
			+ "\n" + 'FormValidator.FUNCTION'
			+ "\n" + 'FormValidator.UNIQUE_VALUES';
	},
	
	onError: function (invalidFields) {
		this.lastError = invalidFields;
		this.log(invalidFields);
		alert(invalidFields.length + " error");
	},
	
	log: function (messageLog) {
		try { window.console.log(messageLog) } catch(e) { alert(e); };
	}
});

/**
 * Validation methods
 */
FormValidator.validMethods = {
	
	validMail: function (fieldJson) {
		var value = fieldJson.field.value;
		var regExp = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; //mail@mail.com | mail@mail.com.br | etc
		return regExp.test(value);
	},
	// alias (validMail -> validEmail)
	validEmail: function (fieldJson) { return this.validMail(fieldJson); }, 
	validNumber: function (fieldJson) {
		var value  = fieldJson.field.value;
		var regExp = /^-?\d+((\.\d+)|(\,\d+))?$/; //1234567890 132.123 132,123
		return regExp.test(value);
	},
	validInteger: function (fieldJson) {
		var value  = fieldJson.field.value;
		var regExp = /^-?\d+?$/; //1234567890
		return regExp.test(value);
	},
	validIp: function (fieldJson) {
		var value  = fieldJson.field.value;
		var regExp = /\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/; // 255.255.255.255
		return regExp.test(value);
	},
	validCep: function (fieldJson) {
		var value  = fieldJson.field.value;
		var regExp = /(^\d{5}$)|(^\d{5}(-?)\d{3,4}$)/; //99999-999 | 99999 | 99999-9999
		return regExp.test(value);
	},
	validCpf: function (fieldJson) {
		var value  = fieldJson.field.value;
		var regExp = /^\d{3}(\.?)\d{3}(\.?)\d{3}(\-?)\d{2}(\.?)$/; //000.000.000-00 | 00000000000
		return regExp.test(value);
	},
	validPhone: function (fieldJson) {
		var value  = fieldJson.field.value;
		//339-4248, 339-4248, 339-42-48, 339 42 48, 339 4248, 3394248, (095) #phone#, 
		//(095)#phone#, +7 (095) #phone#, +7 (095)#phone#, +7(095) #phone#, +55(095)#phone#
		var regExp = /^(\+\d{1,3})*\s*(\(\d{2,3}\)\s*)*\d{3,4}(-{0,1}|\s{0,1})\d{2}(-{0,1}|\s{0,1})\d{2}$/;
		return regExp.test(value);
	},
	validDate: function (fieldJson) {
		var value  = fieldJson.field.value;
		var regExp = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/; //DD/MM/YYYY | MM/DD/YYYY
		if(!regExp.test(value)) return false;
		
		var date = value.indexOf("-") > -1 ? value.split("-") : value.indexOf("/") > -1 ? value.split("/") : value.split(".");
		return this.validDateContent(
				date[FormValidator.dateFormat[lang + "Pos"].y], 
				date[FormValidator.dateFormat[lang + "Pos"].m], 
				date[FormValidator.dateFormat[lang + "Pos"].d]
			);
	},
	validDateYMMDD: function (fieldJson) {
		var value  = fieldJson.field.value;
		var regExp = /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/; //YYYY/MM/DD
		if(!regExp.test(value)) return false;
		
		var date = value.indexOf("-") > -1 ? value.split("-") : value.indexOf("/") > -1 ? value.split("/") : value.split(".");
		return this.validDateContent(date[0], date[1], date[2]);
	},
	validDateContent: function (Y, M, D) {
		return (D <= 31 && M <= 12 && Y.length == 4);
	},
	validFile: function (fieldJson) {
		var value = fieldJson.field.value;
		var extensions = fieldJson.extensions;
		//extension string ex "jpg"
		if(typeof extensions == "string") {
			return extensions.toUpperCase() == value.toUpperCase().substr(value.length - extensions.length, value.length);
		} else {
			//extension array ex ['jpg', 'gif']
			for(var i = 0; i < extensions.length; i++) {
				var extension = extensions[i];
				if(extension.toUpperCase() == value.toUpperCase().substr(value.length - extension.length, value.length)) return true;
			}
			return false;
		}
	},
	validFunction: function (fieldJson) {
		var value = fieldJson.field.value;
		if(fieldJson.exec != undefined) return fieldJson.exec(value);
		return false;
	},
	validUniqueValues: function (fieldJson) {
		var fields = fieldJson.field;
		
		if(fields.length == undefined) return true;
		for(var i = 0; i < fields.length; i++) {
			for(var ii = 0; ii < fields.length; ii++) {
				if(fields[i].value == fields[ii].value && i != ii) {
					return false;
				}
			}
		}
		return true;
	},
	
	/**
	 * Global validation tests
	 */
	test: function(fieldJson) {
		var field	= fieldJson.field;
		var type	 = fieldJson.type;
		var required = fieldJson.required || false;
		
		//Valid only text fields
		if(!this.isText(field)) {
			return true;
		}
		
		var value = field.value;//this.getValue(fieldJSon.field);
		if((!required && value == "") || this[type](fieldJson)) 
			return true;
		
		return false;
		
	},//Method test
	
	validConfirm: function (fieldJson) {
		
		var field = fieldJson.field;
		if(field.length == undefined && field.length < 2) {
			return false;
		} else {
			for(var i = 1; i < field.length; i++) {
				if(field[0].value != field[i].value) return false;
			}
		}
		return true;
		
	},//Method validConfirm
	
	validRequired: function (fieldJson) {
		
		var field    = fieldJson.field;
		var required = fieldJson.required || false;

		//Field is not Required
		if(!required) return true;

		//List of fields --> defined on fieldJson object
		if(field.type == undefined && field.length > 0) {
			
			for(var ii = 0; ii < field.length; ii++) {
				var lastField = {
						field: field[ii],
						required: fieldJson.required
					};
				
				if(this.validRequired(lastField))
					return true;
			}
			return false;
			
		//Field check
		} else if(field.type == "checkbox" || field.type == "radio") {
			return (required && field.checked);
			
		//Multiple select field
		} else if(field.type == "select-multiple") {
			return (required && field.selectedIndex > -1);
			
		//Field value
		} else {
			var value = field.value;
			return required && (value != null && value != "");
		}
		
	},//Method validRequired
	
	isText: function (field) {
		
		if(field.tagName == undefined) return false;
		
		var tagName = field.tagName.toLowerCase();
		var type	= field.type.toLowerCase();
		
		return ((tagName == "input" && (type == "text" || type == "password" || type == "hidden" || type == "file")) || 
				tagName == "textarea");
		
	}//Method isText
};