Validation = {};

Validation._forms  = {};
Validation._errors = {};
Validation._erronousFields = {};
Validation._tooltip = new Tooltip('validation_tooltip');
Validation._tooltipPosition = 'top';

/*REGISTRATION*/
Validation.registerForm = function(form, validators, prevent)
{	
	var v = {};

	for (var i in validators)
	{
		v[Validation._getFieldName(i)] = validators[i];
	}
	
	Validation._forms[form.name] = v;
	Validation._erronousFields[form.name] = {};
	
	if (prevent !== false)
	{
		DOM.addEvent(form, 'submit', (function(event){
			try
			{
				if (!Validation.validateForm(this, true)) 
				{
					DOM.stopEvent(event);
				}
				else 
				{
					Validation._tooltip.hide();
				}
			}
			catch (e)
			{
				DOM.stopEvent(event);
				var message = '';
				for (var i in e)
				{
					message += '\n' + e[i];
				}
				alert('Validation routine threw : ' + message);
			}
		}).bindAsEventListener(form));
	}
		
		
	log(form.name + ' is registered to Validation');
};

Validation.registerField = function(field, validators)
{
	var fieldName = Validation._getFieldName(field.name);
	Validation._forms[field.form.name][fieldName] = validators;
};

Validation.unregisterField = function(field)
{
	if (Validation._forms[field.form.name])
	{
		var field_name = Validation._getFieldName(field.name);
		delete Validation._forms[field.form.name][field_name];
	}
	else throw new Error('Form:' + field.form.name + ' has no registered validation');
};

Validation.registerErrors = function(errors)
{
	for (var error in errors)
	{
		Validation._errors[error] = errors[error];
	}
};

/*VALIDATION*/

Validation.validateForm = function(form, display_errors, by_pass_fields)
{
	var validators = Validation._forms[form.name];
	by_pass_fields = typeof by_pass_fields == 'undefined' ? [] : by_pass_fields;
	
	if (typeof validators != 'undefined')
	{
		var valid = true;
		
		for (var i = 0; i < form.elements.length; i++)
		{
			if (by_pass_fields.indexOf(form.elements[i]) != -1) 
			{
				Validation.hideError(form.elements[i]);
				continue;
			}
			
			if (!Validation.validateField(form.elements[i], display_errors) && valid)
			{
				if (form.elements[i].type == 'textarea' && typeof tinyMCE != 'undefined' && tinyMCE.get(form.elements[i].name))
				{
					var offset = DOM.cumulativeOffset(DOM.next(form.elements[i]));
					window.scrollTo(offset.left, offset.top);
					try {tinyMCE.get(form.elements[i].id).focus()}catch(e){};
				}
				else
				{
					var offset = DOM.cumulativeOffset(form.elements[i].parentNode);
					window.scrollTo(offset.left, offset.top);
					form.elements[i].focus();
				}
				
				valid = false;
			}
		}
		
		return valid;
	}
	else throw new Error('Form:' + form.name + ' has no registered validation');
};

Validation.validateField = function(field, display_error)
{
	Validation.hideError(field);
	
	if (field.disabled) return true;
	
	if (Validation._forms[field.form.name])
	{
		if (field.type == 'textarea' && typeof tinyMCE != 'undefined' && tinyMCE.get(field.name))
		{
			try
			{
				var content = tinyMCE.get(field.name).getContent();
				field.value = content;
				field.innerHTML = content;
			}
			catch(e){}
		}
		
		var field_name = Validation._getFieldName(field.name);
		var validators = Validation._forms[field.form.name][field_name] || [], validator, type;
		var empty = Validators.empty(field);
		
		for (var i = 0; i < validators.length; i++)
		{
			type = validators[i].type;
			
			//Required specific validator
			if (type[0] == '!')
			{
				if (!Validators.required(field))
				{
					if (display_error) Validation.showError(field, 'required', []);
					
					return false;
				}
				else type = type.substring(1);
			}
			else if (empty && type != 'required') continue;

			if (validator = Validators[type])
			{
				//Concat method is used to clone the parameters array
				//otherwise calling unshift on the parameters reference variable
				//would unshift validators[i].parameters too
				var parameters = (validators[i].parameters || []).concat();
				parameters.unshift(field);
				
				if (!validator.apply(field, parameters))
				{

					if (display_error) Validation.showError(field, type, parameters);
					
					return false;
				}
			}
		}
		
		return true;
	}
	else throw new Error('Form:' + form.name + ' has no registered validation');
};

Validators = {
	
	empty : function (field)
	{
		return Validation._getFieldValue(field) == '';
	},
	
	required : function (field)
	{
		if (field.type == 'radio')
		{
			var collection = field.form[field.name];
			
			for (var i = 0; i < collection.length; i++)
			{
				if (collection[i].checked == true) return true;
			}
			
			return false;
		}
		
		var value = Validation._getFieldValue(field);
		
		if (field.type == 'select-one') return value != 0;
		
		return !/^\s*$/.test(value);
	},
	
	timeRange : function(fields)
	{
		if (fields[0].value == '' ^ fields[1].value == '')
		{
			return false;
		}
	
		return Validators.time(fields[0]) && Validators.time(fields[1]);
	},
	
	time : function(field)
	{
		time = field.value.split(':');
		
		if (time.length != 2)
		{
			return false;
		}
		
		hours = Number(time[0]);
		mins  = Number(time[1]);
		
		if (isNaN(hours) || isNaN(mins))
		{
			return false;
		}
		else
		{
			if (hours > 23 || mins > 59)
			{
				return false;
			}
			
			newTime = "";
			
			if (hours < 10)
			{
				newTime = "0" + hours;
			}
			else
			{
				newTime = hours;
			}
			
			newTime = newTime + ":";
			
			if (mins < 10)
			{
				newTime = newTime + "0" + mins;
			}
			else
			{
				newTime = newTime + mins;
			}
			
			field.value = newTime;
			
			return true;
		}
	},
	
	select : function(field)
	{
		return field.options[field.selectedIndex].value != 0;
	},
	
	optionalSelect : function(field)
	{
		if (field.value != '')
		{
			return field.options[field.selectedIndex].value != 0;
		}
		else
		{
			return true;
		}
	},
	
	email : function (field)
	{
		return /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(field.value);
	},
	
	password : function (field)
	{
		return true;
	},
	
	confirm : function (field)
	{
		return (field.value == field.form[field.name + '_confirm'].value);
	},
	
	date : function(field)
	{
		try
		{
			var format = field.className.match(/ format-([^\s]*) /)[1].split(/[\.\/\s\-]/);
			var value = field.value.split(/[\.\/\s\-]/);
			var oDate = {};
			
			for (var i = 0; i < format.length; i++)
			{
				if (!/^\d+$/.test(value[i])) return false;
				
				switch (format[i])
				{
					case 'y':
						oDate.year = value[i]
						break;
						
					case 'm':
						oDate.month = value[i];
						break;
						
					case 'd':
						oDate.date = value[i];
						break;
				}
			}
			
			var date = new Date(oDate.year, oDate.month - 1, oDate.date);
			return (oDate.date == date.getDate() && 
					oDate.month == date.getMonth() + 1 && 
					oDate.year == date.getFullYear());
		}
		catch (e)
		{
			return false;
		}
	},
	
	dynamic : function(field, module, action, id, subid)
	{
		var result = false;
		var url = Request.get('basepath') + '/' + module + '/' + 'api_' + action;
		var params = ['value=' + field.value, 'id=' + id];
		
		if (typeof(subid) != "undefined")
		{
			params.push('subid=' + subid);
		}
		
		var request = new AJAX.Request(url, {
			method : 'POST',
			parameters : params,
			json: true,
			asynchronous: false
		});
		
		if (request.response.responseJSON.message) Validation._errors.dynamic = request.response.responseJSON.message;
		
		return request.response.responseJSON.result;
	},
	
	distinct : function(field)
	{
		var value = Validation._getFieldValue(field);
		//IE doesn't automatically update the form hash to contain
		//elements dynamically added to DOM
		//Lets help him a bit :) 
		if (Browser.isIE()) 
		{
			var fields = field.form.elements, collection = [];
			for (var i = 0; i < fields.length; i++) 
			{
				if (fields[i].name == field.name) collection.push(fields[i]);
			}
			if (fields[0] == field) return true;
		}
		else 
		{
			var collection = field.form[field.name];
			if (collection == field) return true;
		}
		
		for (var f = 0; f < collection.length; f++)
		{
			if (collection[f] != field && Validation._getFieldValue(collection[f]) == value) return false;
		}
		
		return true;
	},
	
	number : function (field)
	{
		var value = Validation._getFieldValue(field);
		return (Number(value) == value);
	},
	
	integer : function (field)
	{
		var value = Validation._getFieldValue(field);
		return (parseInt(value) == value);
	},
	
	min : function (field, min)
	{
		return Number(Validation._getFieldValue(field)) >= Number(min);
	},
	
	max : function (field, max)
	{
		return Number(Validation._getFieldValue(field)) <= Number(max);
	},
	
	length : function (field, length)
	{
		return String(Validation._getFieldValue(field)).length == parseInt(length);
	},
	
	minLength : function (field, min)
	{
		return String(Validation._getFieldValue(field)).length >= parseInt(min);
	},
	
	maxLength : function (field, max)
	{
		return String(Validation._getFieldValue(field)).length <= parseInt(max);
	},
	
	regexp : function (field, pattern, flags)
	{
		return new RegExp(pattern, flags || '').test(Validation._getFieldValue(field));
	},
	
	url : function (field)
	{
		return /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/.test(Validation._getFieldValue(field));
	}
};

Validation.hideError = function(field)
{
	delete Validation._erronousFields[field.form.name][field.name];
	
	if (field.type == 'textarea' && typeof tinyMCE != 'undefined' && tinyMCE.get(field.name)) 
	{
		with ($(field.name + '_tbl'))
		{
			style.borderColor = '';
			rows[0].cells[0].style.borderColor = '';
			rows[1].cells[0].style.borderColor = '';
		}
		
		with (tinyMCE.get(field.name))
		{
			contentDocument.body.style.backgroundColor = '';
			onActivate.remove(Validation._focusErronousField);
			onDeactivate.remove(Validation._blurErronousField);
		}
	}
	else 
	{
		DOM.removeEvent(field, 'focus', Validation._focusErronousField);
		DOM.removeEvent(field, 'blur', Validation._blurErronousField);
		
		if (field.type == 'file')
		{
			DOM.removeClassName(DOM.previous(field, 2), 'validation-error');
		}
		else 
		{
			DOM.removeClassName(field, 'validation-error');
		}
	}
};

Validation.showError = function(field, type, parameters)
{
	Validation._erronousFields[field.form.name][field.name] = {
		type : type,
		parameters : parameters
	};

	if (field.type == 'textarea' && typeof tinyMCE != 'undefined' && tinyMCE.get(field.name)) 
	{
		with ($(field.name + '_tbl'))
		{
			style.borderColor = 'red';
			rows[0].cells[0].style.borderColor = 'red';
			rows[1].cells[0].style.borderColor = 'red';
		}
		
		with (tinyMCE.get(field.name))
		{
			contentDocument.body.style.backgroundColor = '#fcf8ca';
			onActivate.add(Validation._focusErronousField);
			onDeactivate.add(Validation._blurErronousField);
		}
	}
	else
	{
		DOM.addEvent(field, 'focus', Validation._focusErronousField);
		DOM.addEvent(field, 'blur', Validation._blurErronousField);

		if (field.type == 'file')
		{
			DOM.addClassName(DOM.previous(field, 2), 'validation-error');
		}
		else
		{
			DOM.addClassName(field, 'validation-error');
		}
	}
};

Validation._getFieldName = function(field_name)
{
	var match = field_name.match(/([^\[]*)\[[^\]]*\]$/);
	return match ? match[1] + '[]' : field_name;
};

Validation._getFieldValue = function(field)
{
	switch (field.type)
	{
		case 'select-one':
			return field.options[field.selectedIndex].value;
			break;
			
		default:
			return field.value;
			break;
	}
};

Validation._focusErronousField = function (event)
{
	var field, target, error_details, message;
	
	if ('editorId' in event)
	{
		field = $(event.editorId);
		target = $(event.editorId + '_tbl');
	}
	else
	{
		field = DOM.eventTarget(event);
		target = field.type == 'file' ? DOM.previous(field, 2) : field;
	}

	if (error_details = Validation._erronousFields[field.form.name][field.name])
	{
		if (message = Validation._errors[error_details.type])
		{
			var message_parameters = error_details.parameters.concat();
			message_parameters.shift();
			message = message.fill(message_parameters);
			
			Validation._tooltip.show(target, message, Validation._tooltipPosition);
		}
		
	}
	
};

Validation._blurErronousField = function (event)
{
	var field = 'editorId' in event ? $(event.editorId) : DOM.eventTarget(event);
	
	Validation.validateField(field, true);
	Validation._tooltip.hide();
};


Validation.is_email = function (email)
{
	if(email.length == 0)
	{
		return true;	
	}
	
	var reg_email = /^[.a-zA-Z0-9_-]+@[a-zA-Z0-9-]{2,}[.][a-zA-Z]{2,3}$/
	return (reg_email.exec(email) != null)
}

Validation.is_filled = function (text_value,nb_chars)
{
	if(nb_chars == null)
	{
		nb_chars = 0;
	}
	else
	{
		nb_chars--;
	}

	if(typeof(text_value) == 'number' || typeof(text_value) == 'string' || typeof(text_value) == 'boolean')
	{
		return (text_value.length > nb_chars);
	}
	return false;
}
		
