/*
	FormValidation
	Requires Mootool 1.2 Core 
	Requires lib.ok.utils.RequireUtils
	Ok!nteractif
*/

///	Imports	//////////////////////////////////////////////////////////////////////////////////////////////////////////

var formErrorsLib = 	'lib.ok.ui.form.FormErrors';
var formErrorsDisplay = 'lib.ok.ui.form.FormErrorsDisplay';

if(RequireUtils.checkForAttribute('FormValidation', 'template')){
	formErrorsDisplay = RequireUtils.getAttribute('FormValidation', 'template');
}
if(RequireUtils.checkForAttribute('FormValidation', 'messages')){
	formErrorsLib = RequireUtils.getAttribute('FormValidation', 'messages');
}

RequireUtils.require([
	formErrorsLib,
	formErrorsDisplay,
	'lib.ok.utils.StringUtils'
]);

///	Constants	//////////////////////////////////////////////////////////////////////////////////////////////////////
var FORM_ERRORS_DISPLAY =	'LocalFormErrorsDisplay';
var FORM_ERRORS_LIB =		'LocalFormErrors;';

var VALIDATION_EXP 	= {
	whiteSpace		: RegExp(/^[\s]+$/),
	email			: RegExp(/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/),
	url				: RegExp(/^http\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,4}(\/\S*)?$/),
	specialChars	: RegExp(/^[A-Za-z0-9!@#$%_\^\&amp;\*\-\.\?]*$/),
	postalCode		: RegExp(/^((\d{5}-\d{4})|(\d{5})|([AaBbCcEeGgHhJjKkLlMmNnPpRrSsTtVvXxYy]\d[A-Za-z]\s?\d[A-Za-z]\d))$/)
};

var FIELD_TYPES		= {
	text			: 'txt_',
	textarea		: 'txta_',
	list			: 'li_',
	checkBox		: 'cbox_',
	radio			: 'rad_',
	image			: 'img_'
};

var VALIDATION_TYPES = {
	required		: '_ob_',
	specialChars	: '_spe_',
	date			: '_dat_',
	dateAfter		: '_dat+_',
	dateBefore		: '_dat-_',
	dateAfterToday	: '_datdp_',
	dateBeforeToday : '_datnp_',
	telephone		: '_tel_',
	postalCode		: '_cp_',
	password		: '_pw_',
	passwordConfirm	: '_pwconfirm_',
	email			: '_cou_',
	url				: '_url_',
	devise			: '_arg_'
};

var DATE_SUFFIXES = {
	day				: '_day',
	month			: '_month',
	year			: '_year',
	hour			: '_hour',
	minute			: '_minute',
	second			: '_second'
};

var PHONE_SUFFIXES = {
	area			: '_area',
	start			: '_start',
	end				: '_end'
};

var REPEATING_TYPES = {
	field : [
		FIELD_TYPES.checkBox,
		FIELD_TYPES.radio
	],
	validation : [
		VALIDATION_TYPES.date,
		VALIDATION_TYPES.telephone
	]
};

///	Class	//////////////////////////////////////////////////////////////////////////////////////////////////////////
var FormValidation = 
{
	
	error				: false,
	errorMessage		: null,
	form				: null,
	passwordHasSpecChars : true,
	
	validate			: function(formElement)
	{
		this.initValidation(formElement);
		var aValidation = this.getFieldsToValidate();

		for (var i = 0; i < aValidation.length; i++){
			var s = aValidation[i];
			switch(s.getPrefix()){
				case "cbox":
					if (this.$form(s).length == undefined){
						if(!this.$form(s).checked && s.isRequired()) this.addError(s, FORM_ERRORS_LIB.error.checkBox);
					}else{
						var boxGroup = this.$form(s);
						for(var j = 0; j < boxGroup.length; j++){
							if(boxGroup[j].checked) break;
							if(j == boxGroup.length - 1 && s.isRequired()) this.addError(s, FORM_ERRORS_LIB.error.checkBox);
						}
					}
					break;
					
				case "rad":
					var radioGroup = this.$form(s);
					if (radioGroup.length == undefined){
						if(!this.$form(s).checked) this.addError(s, FORM_ERRORS_LIB.error.radio);
					}else{
						for(var j = 0; j < radioGroup.length; j++){
							if(radioGroup[j].checked) break;
							if(j == radioGroup.length - 1 && s.isRequired()) this.addError(s, FORM_ERRORS_LIB.error.radio);
						}
					}
					break;
					
				default:
					if(s.isText() || s.isTextarea()) this.$form(s).value = this.$form(s).value.trim();
					
					if(s.isRequired())
					{
						if(s.isDate())
						{
							var objDate = this.getObjDate(s);
							if(!objDate || objDate.day.isEmpty() || isNaN(objDate.day) || objDate.year.isEmpty() || isNaN(objDate.year) || objDate.month.isEmpty() || isNaN(objDate.month)) this.addError(s, FORM_ERRORS_LIB.error.text);
						}
						else if(s.isTelephone())
						{
							var objTelephone = this.getObjTelephone(s);
							if(!objTelephone || (objTelephone.area.isEmpty() && objTelephone.start.isEmpty() && objTelephone.end.isEmpty())) this.addError(s, FORM_ERRORS_LIB.error.text);
						}
						else if(s.isList())
						{
							if(this.$form(s).value.isEmpty() || this.$form(s).value == '--' || this.$form(s).value == '--;false') this.addError(s, FORM_ERRORS_LIB.error.text);
						}
						else if(this.$form(s).value.isEmpty()) this.addError(s, FORM_ERRORS_LIB.error.text);

					}
					
					if(s.isTelephone())
					{
						var objTelephone = this.getObjTelephone(s);
						if(objTelephone && (!objTelephone.area.isEmpty() && !objTelephone.start.isEmpty() && !objTelephone.end.isEmpty()))
							if(!this.validTelephone(objTelephone)) this.addError(s, FORM_ERRORS_LIB.error.telephone);
						
					}
					
					if(s.isDate())
					{
						var objDate = this.getObjDate(s);
						if(objDate && (!objDate.day.isEmpty() && !isNaN(objDate.day) && !objDate.year.isEmpty() && !isNaN(objDate.year) && !objDate.month.isEmpty() && !isNaN(objDate.month))){
							var fct = (objDate.hour != '' && objDate.minute != '') ? this.validFullDate : this.validDate;
							if(!fct(objDate)) this.addError(s, FORM_ERRORS_LIB.error.date);
							else{
								if(s.isDateBeforeToday())	if(!this.validDateBeforeToday(objDate))	this.addError(s, FORM_ERRORS_LIB.error.dateBeforeToday);
								if(s.isDateAfterToday())	if(!this.validDateAfterToday(objDate))	this.addError(s, FORM_ERRORS_LIB.error.dateAfterToday);
								if(s.isDateAfter())			if(!this.validDateAfter(s, aValidation[i-1])) this.addError(s, FORM_ERRORS_LIB.error.dateAfter);
								if(s.isDateBefore())		if(!this.validDateBefore(s, aValidation[i-1])) this.addError(s, FORM_ERRORS_LIB.error.dateBefore);
							}
						}
					}
					
					if(s.isEmail())
					{
						if(!this.$form(s).value.isEmpty()){
							if(!VALIDATION_EXP.email.test(this.$form(s).value)) this.addError(s, FORM_ERRORS_LIB.error.email);
						}
					}
					
					if(s.isUrl())
					{
						if(!this.$form(s).value.isEmpty()){
							if(!VALIDATION_EXP.url.test(this.$form(s).value)) this.addError(s, FORM_ERRORS_LIB.error.url);
						}
					}
					
					if(s.isPostalCode())
					{
						if(!this.$form(s).value.isEmpty()){
							if(!VALIDATION_EXP.postalCode.test(this.$form(s).value)) this.addError(s, FORM_ERRORS_LIB.error.postalCode);
						}
					}
					
					if(s.isSpecialChars())
					{
						if(!this.$form(s).value.isEmpty()){
							if(!VALIDATION_EXP.specialChars.test(this.$form(s).value)) this.addError(s, FORM_ERRORS_LIB.error.specialChars);
						}
					}
					
					if(s.isPassword())
					{
						if(!this.$form(s).value.isEmpty()){
							if(!this.passwordHasSpecChars) if(!VALIDATION_EXP.specialChars.test(this.$form(s).value)) this.addError(s, FORM_ERRORS_LIB.error.specialChars);
						}
					}
					
					if(s.isPasswordConfirm())
					{
						if(!this.passwordHasSpecChars) if(!VALIDATION_EXP.specialChars.test(this.$form(s).value)) this.addError(s, FORM_ERRORS_LIB.error.specialChars);
						var $password = this.$form(s.replace(VALIDATION_TYPES.passwordConfirm, VALIDATION_TYPES.password));
						if($password.value != this.$form(s).value) this.addError(s, FORM_ERRORS_LIB.error.password);																							
					}
					
					if(s.isDevise())
					{
						if(!this.$form(s).value.isEmpty()){
							if(isNaN(this.$form(s).value)) this.addError(s, FORM_ERRORS_LIB.error.devise);
						}
					}
					
					break;
			}
		}
		
		(this.error)
			? FORM_ERRORS_DISPLAY.showErrors(this.errorMessage)
			: this.form.submit();
	},
	
	initValidation		: function(formElement)
	{
		FORM_ERRORS_LIB = 		eval(FORM_ERRORS_LIB);
		FORM_ERRORS_DISPLAY = 	eval(FORM_ERRORS_DISPLAY);
		
		this.error = 			false;
		this.form = 			formElement;
		this.errorMessage = 	FORM_ERRORS_LIB.start;
	},
	
	addError			: function(id, type)
	{
		var tempErrorMsg = FORM_ERRORS_DISPLAY.ERROR_PLACEHOLDER.substitute({formId:this.form.id, fieldId:id, formTitle:this.$form(id).title});
		this.errorMessage += type.substitute({title: tempErrorMsg});
		this.error = true;
	},
	
///	Helpers	//////////////////////////////////////////////////////////////////////////////////////////////////////////
	setTemplate			: function(templateLib)
	{
		FORM_ERRORS_DISPLAY = templateLib;
	},
	
	setMessages			: function(messagesLib)
	{
		FORM_ERRORS_LIB = messagesLib;
	},
	
	$form				: function(fieldId)
	{
		return this.form[fieldId];
	},
	
	getFieldsToValidate	: function()
	{
		var a = [];
		var f;
		for(var i = 0; i < this.form.length; i++){
			f = this.form.elements[i];
			if(f.type.match(/submit|button|hidden/)) continue;
			
			if(this.isRepeatingType(f.id) && i > 0){
				if(!this.isSameType(f.id, a[a.length - 1])) a[i] = f.id;
			}else a[i] = f.id;
		}
		
		return a;
	},
	
	isSameType			: function(fieldA, fieldB)
	{
		return fieldA.substring(0, fieldA.lastIndexOf("_")) == fieldB.substring(0, fieldB.lastIndexOf("_")) ? true : false;
	},
	
	isRepeatingType		: function(fieldId)
	{
		var i;
		
		for(i = 0; i < REPEATING_TYPES.field.length; i++)
			if(fieldId.isType(REPEATING_TYPES.field[i])) return true;
		
		for(i = 0; i < REPEATING_TYPES.validation.length; i++)
			if(fieldId.isType(REPEATING_TYPES.validation[i])) return true;
			
		return false;
	},
	
	getObjDate			: function(id)
	{
		var id = 		id.substring(0, id.lastIndexOf('_'));
		var day = 		$(id + DATE_SUFFIXES.day);
		var month = 	$(id + DATE_SUFFIXES.month);
		var year = 		$(id + DATE_SUFFIXES.year);
		var hour = 		$(id + DATE_SUFFIXES.hour);
		var minute = 	$(id + DATE_SUFFIXES.minute);
		
		if(!day || !month || !year) return false;
		else{
			returnedObj = {
				day		:	day.value.replace(/JJ/, ''),
				month	:	month.value,
				year	:	year.value.replace(/AAAA/, ''),
				hour	:	'',
				minute	:	''
			};
			
			if(hour) 	returnedObj.hour = hour.value.replace(/HH/, '');
			if(minute)	returnedObj.minute = minute.value.replace(/MM/, '');
			
			return returnedObj;
		}
	},
	
	getObjTelephone		: function(id)
	{
		var id = 		id.substring(0,id.lastIndexOf('_'));
		var area = 		$(id + PHONE_SUFFIXES.area);
		var start = 	$(id + PHONE_SUFFIXES.start);
		var end = 		$(id + PHONE_SUFFIXES.end);
		if(!area || !start || !end) return false;
		else return {
			area	:	area.value,
			start	:	start.value,
			end		: 	end.value
		};
	},
	
	validTelephone		: function(objTelephone)
	{
		return (
			isNaN(objTelephone.area)	|| 
			isNaN(objTelephone.start)	|| 
			isNaN(objTelephone.end)		||
			objTelephone.area.length 	!= 3 || 
			objTelephone.start.length 	!= 3 || 
			objTelephone.end.length 	!= 4
		) ? false : true;
	},
	
	validDate			: function(objDate)
	{
		return (
		   isNaN(objDate.day)		||
		   isNaN(objDate.month)		||
		   isNaN(objDate.year)		||
		   objDate.day < 1			||
		   objDate.day > 31			||
		   objDate.month < 1		||
		   objDate.month > 12		
		) ? false : true;
	},
	
	validFullDate			: function(objDate)
	{
		var isDateValid = validDate(objDate);
		var isFullDateValid = (
		   objDate.hour.isEmpty()	|| 
		   objDate.minute.isEmpty()	||
		   isNaN(objDate.hour)		||
		   isNaN(objDate.minute)	||
		   objDate.hour < 0			||
		   objDate.hour > 23		||
		   objDate.minute < 0		||
		   objDate.minute > 59
		) ? false : true;
		return (!isDateValid || !isFullDateValid) ? false : true;
	},
	
	validDateBeforeToday	: function(objDate)
	{
		return (this.dateToString(objDate) < this.todayToString()) ? true : false;
	},
	
	validDateAfterToday		: function(objDate)
	{
		return (this.dateToString(objDate) > this.todayToString()) ? true : false;
	},
	
	validDateAfter			: function(currentDate, previousDate){
		var aStrDates = this.getCompareDatesString(currentDate, previousDate);
		return (aStrDates[0] < aStrDates[1]) ? false : true;
	},
	
	validDateBefore			: function(currentDate, previousDate){
		var aStrDates = this.getCompareDatesString(currentDate, previousDate);
		return (aStrDates[0] > aStrDates[1]) ? false : true;
	},
	
	getCompareDatesString	: function(dateA, dateB)
	{
		return [this.fullDateToString(this.getObjDate(dateA)), this.fullDateToString(this.getObjDate(dateB))];
	},
	
	todayToString			: function()
	{
		var today =	new Date();
		return today.getFullYear().toString() + today.getMonth().toString() + today.getDate().toString();
	},
	
	fullDateToString		: function(objDate)
	{
		var strDate = this.dateToString(objDate);
		if (!objDate.hour.isEmpty() && !objDate.minute.isEmpty()) strDate += this.hourToString(objDate);
		return strDate;
	},
	
	dateToString			: function(objDate)
	{
		return objDate.year.toString() + objDate.month.toString() + objDate.day.toString();
	},
	
	hourToString			: function(objDate)
	{
		return objDate.hour.toString() + objDate.minute.toString();
	}
	
};

///	String.prototype to make code more readable	//////////////////////////////////////////////////////////////////////
String.prototype.getPrefix = 		function()		{ return this.substring(0, this.indexOf("_")); }
String.prototype.isEmpty =			function()		{ return (this.clean() == '') ? true : false; }
String.prototype.isType = 			function(type)	{ return this.escapeRegExp().match(type.escapeRegExp()); }

///	FIELD_TYPES
String.prototype.isText =			function() 	{ return this.isType(FIELD_TYPES.text); }
String.prototype.isTextarea =		function() 	{ return this.isType(FIELD_TYPES.textarea); }
String.prototype.isList =			function() 	{ return this.isType(FIELD_TYPES.list); }
String.prototype.isCheckBox =		function() 	{ return this.isType(FIELD_TYPES.checkBox); }
String.prototype.isRadio =			function() 	{ return this.isType(FIELD_TYPES.radio); }
String.prototype.isImage =			function() 	{ return this.isType(FIELD_TYPES.image); }

///	VALIDATION_TYPES
String.prototype.isRequired = 		function() 	{ return this.isType(VALIDATION_TYPES.required); }
String.prototype.isSpecialChars = 	function() 	{ return this.isType(VALIDATION_TYPES.specialChars); }
String.prototype.isDate = 			function() 	{ return this.isType(VALIDATION_TYPES.date); }
String.prototype.isDateAfter = 		function() 	{ return this.isType(VALIDATION_TYPES.dateAfter); }
String.prototype.isDateBefore = 	function() 	{ return this.isType(VALIDATION_TYPES.dateBefore); }
String.prototype.isDateAfterToday = function() 	{ return this.isType(VALIDATION_TYPES.dateAfterToday); }
String.prototype.isDateBeforeToday = function() { return this.isType(VALIDATION_TYPES.dateBeforeToday); }
String.prototype.isTelephone = 		function() 	{ return this.isType(VALIDATION_TYPES.telephone); }
String.prototype.isPostalCode = 	function() 	{ return this.isType(VALIDATION_TYPES.postalCode); }
String.prototype.isPassword = 		function() 	{ return this.isType(VALIDATION_TYPES.password); }
String.prototype.isPasswordConfirm = function() { return this.isType(VALIDATION_TYPES.passwordConfirm); }
String.prototype.isEmail = 			function() 	{ return this.isType(VALIDATION_TYPES.email); }
String.prototype.isUrl = 			function() 	{ return this.isType(VALIDATION_TYPES.url); }
String.prototype.isDevise = 		function() 	{ return this.isType(VALIDATION_TYPES.devise); }
