/**
 * Client-side validation
 *
 * @copyright  BliXem Internet Services
 *
 * @package    Core
 * @subpackage Controller
 * @filesource
 */

// Make sure the prototype library is loaded
if (typeof Prototype == 'undefined') {
	throw('Validation requires the Prototype JavaScript framework');
}

/**
 * This object enables easy client-side validation of form input fields. It 
 * searches the HTML for <form> elements. For each <form> element is checks
 * if the form has a "title" attribute specified. If so we assume this is the
 * URL where the validation checks of this form can be retrieved. An AJAX
 * request is then sent using the form's "title" attribute as URL. After 
 * receiving a response from the server the returned validations are dynamically
 * added as checks for input field in the found form.
 */
var Validation = {

	/**
	 * Initialize the Validation object. This function should be called right 
	 * after the Validation object is created.
	 */
	init: function() 
	{
		// When the onload event of the window fires, call the apply function
		Event.observe(window, 'load', Validation.apply);
	},
		
	/**
	 * Apply the validation information to each form.
	 */	
	apply: function()
	{
		// Find all form elements and feed them to the get function
		$$('form').each(function(form) {
			Validation.get(form);
		});
	},
	
	/**
	 * Get the validation information for a form.
	 *
	 * @param HTMLFormElement form The form element.
	 */
	get: function(form) 
	{
		// We use the form title as our URL to get the validation error so if no
		// title is specified immediately return
		
		var formtitle = form.getAttribute('title');
		
		if (typeof formtitle == 'undefined') {
			return;
		}
		
		// Extract & remove title
		var url = formtitle;
		form.title = '';

		// Check if URL is a string (sometimes shit happens and it returns an object)
		if (typeof url != 'string') {
			return;
		}

		// Send an AJAX request to the defined URL
		new Ajax.Request(url, {
			onSuccess: function(xml) {
				// Evaluate the returned response (it should be JSON code)
				var validations = eval ('(' + xml.responseText + ')');

				// Add the validation to the found fieldname
				for (fieldname in validations) {
					Validation.attach(form, fieldname, validations[fieldname]);
				}
			}
		});
	},

	/**
	 * Attach checks to a field in a form.
	 *
	 * @param HTMLFormElement form
	 * @param string fieldname
	 * @param array 
	 */
	attach: function(form, fieldname, checks)
	{
		// Find the input field
		var inputfield = $A(form.elements).findAll(function(element) {
			return element.name == fieldname;
		}).first();

		// Find the indicator
		inputfield.indicator = $A(inputfield.parentNode.childNodes).findAll(function(sibling) {
			if (typeof sibling.className == 'undefined') {
				return false;
			}
			return (sibling.className.indexOf('indicator') != -1);
		}).first();

		// Add check definitions to the field
		inputfield.checks = checks;

		// Add event handlers
		Event.observe(inputfield, 'keyup',  Validation.perform.bind(inputfield));
		Event.observe(inputfield, 'change', Validation.perform.bind(inputfield));
		Event.observe(inputfield, 'blur', Validation.perform.bind(inputfield));

		// First check
		Validation.perform(inputfield);
	},

	/**
	 * When the value of an input field with validation checks changes, this 
	 * function is called and it validates the value.
	 *
	 * @param HTMLElement inputfield The inputfield which value is checked.
	 */
	perform: function(inputfield)
	{
		// Make sure the inputfield has checks defined
		if (typeof inputfield == 'undefined' || typeof inputfield.checks == 'undefined') {
			inputfield = this;
		}

		var errors = 0;

		// Loop through all checks of the input field
		$A(inputfield.checks).each(function(check) {
			eval('var regex = '+ check.expression + ';');

			// Check the value of the inputfield with the found regex
			if (!regex.test(this.value)) { 
				errors++;
			};
		}.bind(inputfield));

		// Set the classnames of the inputfield according to the fact if any errors
		// were found or not
		if (errors > 0) {
			Element.removeClassName(inputfield, 'valid');
			Element.addClassName(inputfield, 'error');

			if (typeof inputfield.indicator != 'undefined') {
				Element.removeClassName(inputfield.indicator, 'valid');
				Element.addClassName(inputfield.indicator, 'error');
			}
		} else {
			Element.removeClassName(inputfield, 'error');
			Element.addClassName(inputfield, 'valid');

			if (typeof inputfield.indicator != 'undefined') {
				Element.removeClassName(inputfield.indicator, 'error');
				Element.addClassName(inputfield.indicator, 'valid');
			}
		}
	}
};

// Initialize the Validation object
Validation.init();