/* Form validation class */
function FormValidate (options) {
	options = $.extend({
		field_onvalid: null,		//Callback - when form field value becomes invalid
		field_onerror: null,		//Callback - when form field value becomes valid
		
		fields_rules: {}			//List of validation rules (associative object where key is the name of the field and value is the function)
	}, options);
	
	this.options = options;
	this.init();
	
	return this;
};

//Configuration options
FormValidate.prototype.options = {};

//For each fields value can be: -1 - "not yet validated", 0 - "invalid value", 1 - "valid value"
FormValidate.prototype.field_status = {};

//Form status: true - all fields valid, false - some field is invalid
FormValidate.prototype.form_valid = false;

/* Revalidates value */
FormValidate.prototype.revalidateValue = function (input_id, check_only) {
	/* Only fields with validation rules applied must be validated */
	if (this.field_status[input_id] === undefined) return true;
	check_only = check_only || false;
	
	var inp = $('#' + input_id);
	var value = new String(inp.val());
		value = value.trim();
	
	if (inp.attr('type') == 'checkbox' && inp[0])
	{
		value = (inp[0].checked ? 'true' : '');
	}
	
	/* Executes custom validation function */
	if (this.options.fields_rules[input_id] && !this.options.fields_rules[input_id](value))
	{
		if (check_only) return false;
		
		/* Validation function returned false */
		/* Changes are needed only if field was valid on last check */
		if (this.field_status[input_id])
		{
			if (this.options.field_onerror)
				this.options.field_onerror(input_id, this);
				
			this.field_status[input_id] = false;
		}
		
		return false;
	}
	
	if (check_only) return true;

	/* Changes are needed only if field was not valid on last check */
	if (!this.field_status[input_id])
	{
		/* Field value is valid, execute callback */
		if (this.options.field_onvalid)
		{
			this.options.field_onvalid(input_id, this);
		}
		
		this.field_status[input_id] = true;
	}
	
	return true;
};

/* Checks if all values are valid */
FormValidate.prototype.revalidateForm = function () {
	var state = true;
	for(i in this.field_status)
	{
		if (!this.revalidateValue(i)) state = false;
	}
	
	return state;
};

/* Constructor */
FormValidate.prototype.init = function () {
	var self = this;
	
	//Create list of fields with validation	
		for(var i in this.options.fields_rules)
		{
			if (this.options.fields_rules.hasOwnProperty(i))
			{
				//Validate form input value, but don't mark fields as errors
				this.field_status[i] = (this.revalidateValue(i, true) ? true : -1);
			}
		}
	
	//Assign event handlers
		for(var i in this.field_status)
		{
			var inp = $('#' + i);
			
			inp.change(function () { self.revalidateValue($(this).attr('id')); })
			   .blur(function () { self.revalidateValue($(this).attr('id')); })
			   
			if ($.browser.msie && inp.attr('type') == 'checkbox')
				inp.click(function () { self.revalidateValue($(this).attr('id')); });
		}
};