function fbkFormValidator (_form_name, _error_display_handler)
{
	this.FormName = _form_name;
	this.Rules = new Array();
	this.Errors = new Array();
	this.ErrorKeys = new Array();
	this.Validated = false;
	
	if (_error_display_handler != null) {
		this.ErrorDisplayHandler = _error_display_handler;
	} else {
		this.ErrorDisplayHandler = 'fbkFormErrorDisplayHandler';
	}
	
	this.addRule = fbkFormValidatorAddRule;
	this.getRules = fbkFormValidatorGetRules;
	this.addError = fbkFormValidatorAddError;
	this.addErrorKey = fbkFormValidatorAddErrorKey;
	this.setValidated = fbkFormValidatorSetValidated;
	this.getValidated = fbkFormValidatorGetValidated;
	this.validate = fbkFormValidatorValidate;
}
	
	
function fbkFormValidatorAddRule (_rule)
{
	this.Rules[this.Rules.length] = _rule;
}


function fbkFormValidatorGetRules ()
{
	return this.Rules;
}

function fbkFormValidatorAddError (_error_msg)
{
	this.Errors[this.Errors.length] = _error_msg;
}

function fbkFormValidatorAddErrorKey (_key)
{
	this.ErrorKeys[this.ErrorKeys.length] = _key;
}

function fbkFormValidatorSetValidated (_validated)
{
	this.Validated = _validated;
}

function fbkFormValidatorGetValidated ()
{
	return this.Validated;
}

function fbkFormValidatorValidate ()
{
	if (this.getValidated())  {
		return true;
	}
	
	var rules = this.getRules();
	var valid = true;
	
	this.Errors = new Array();
	this.ErrorKeys = new Array();
		
	for (var i = 0; i < rules.length; i++) {
		var rule = rules[i];
		var result = rule.valid();
		
		if (result != null) {
			this.addError(result[0]);
			this.addErrorKey(result[1]);	
			
			valid = false;
		}
	}
	
	if (!valid) {
		// form is invalid, invoke error display handler
		try {
			eval(this.ErrorDisplayHandler)(this);
		} catch (e) {
			fbkFormErrorDisplayHandler(this);
		}
	}
	
	return valid;
}

function fbkFormRule (_rule_name, _elements, _parameters, _required, _message, _reference_key, _rules)
{
	this.Name = _rule_name;
	this.Elements = _elements;
	this.Parameters = _parameters;
	this.Required = _required;
	this.Message = _message;
	this.ReferenceKey = _reference_key;
	this.Rules = _rules;
	
	this.valid = fbkFormRuleValid;
	this.getAllReferenceKeys = fbkFormRuleGetAllReferenceKeys;
}

function fbkFormRuleValid ()
{
	var valid = false;
	
	try {
		valid = eval(this.Name)(this.Elements, this.Parameters, this.Required);
	} catch (e1) {
		try {
			var rule_name = 'fbkFormValidationRule' + this.Name;
			
			valid = eval(rule_name)(this.Elements, this.Parameters, this.Required);
		} catch (e2) {
		}
	}
	
	if (valid) {
		// rule is valid, check child rules
		for (var i = 0; i < this.Rules.length; i++) {
			var rule = this.Rules[i];
			var result = rule.valid();
			
			if (result != null) {
				return result;
			}
		}
		
		return null;
	} else {
		// rule is invalid, return error message and reference key as array
		var result = new Array(this.Message, this.ReferenceKey);
		return result;
	}
}

function fbkFormRuleGetAllReferenceKeys ()
{
	var reference_keys = new Array();
	
	if (this.ReferenceKey != null && this.ReferenceKey != '') {
		reference_keys[reference_keys.length] = this.ReferenceKey;
	}
	
	for (var i = 0; i < this.Rules.length; i++) {
		var keys = this.Rules[i].getAllReferenceKeys();
		
		for (var j=0; j < keys.length; j++) {
			if (keys[j] != null && keys[j] != '') {
				reference_keys[reference_keys.length] = keys[j];
			}
		}
	}
	
	return reference_keys;
}

function fbkFormErrorDisplayHandler (_validator)
{
	// change classes
	// get all reference keys for all rules
	var reference_keys = new Array();
	
	for (var i = 0; i < _validator.Rules.length; i++) {
		var keys = _validator.Rules[i].getAllReferenceKeys();
		
		for (var j=0; j < keys.length; j++) {
			reference_keys[reference_keys.length] = keys[j];
		}
	}
	
	// make sure there are no duplicates
	var clean_keys = new Array();
	
	for (var i = 0; i < reference_keys.length; i++) {
		var found = false;
		
		for (var j = 0; j < clean_keys.length; j++) {
			if (reference_keys[i] == clean_keys[j]) {
				found = true;
			}
		}
		
		if (!found) {
			clean_keys[clean_keys.length] = reference_keys[i];
		}
	}
	
	// reset class name to empty
	for (var i = 0; i < clean_keys.length; i++) {
		var element = fbkGetElement('formError_' + clean_keys[i]);
		
		if (element) {
			element.className = '';
		}
	}
	
	// hide any errors
	for (var i = 0; i < clean_keys.length; i++) {
		var element = fbkGetElement('formError_' + clean_keys[i] + '_hide');
		
		if (element) {
			element.style.display = 'none';
		}
	}
	
	// set class name to error
	for (var i = 0; i < _validator.ErrorKeys.length; i++) {
		var element = fbkGetElement('formError_' + _validator.ErrorKeys[i]);
		
		if (element) {
			element.className = 'error';
		}
	}
	
	// show any errors
	for (var i = 0; i < _validator.ErrorKeys.length; i++) {
		var element = fbkGetElement('formError_' + _validator.ErrorKeys[i] + '_hide');
		
		if (element) {
			element.style.display = 'inline';
		}
	}
	
	// display error message
	var error_message = "Please fix the following errors:\n\n";
	
	for (var i = 0; i < _validator.Errors.length; i++) {
		error_message += '* '  + _validator.Errors[i] + '\n';
	}
	
	alert(error_message);
}
