AJAXFormValidator = function(formID, callbackInputOK, scriptURL, resetFormAfterSubmit) {
	this.debug = false;

	this.form = document.getElementById(formID);

	this.callbackOnSuccessfulSubmit = callbackInputOK;
	this.scriptURL = scriptURL;
	
	if (resetFormAfterSubmit == null) resetFormAfterSubmit = true;
	this.resetForm = resetFormAfterSubmit;

	YAHOO.util.Event.addListener(this.form, 'submit', this.startRequest, this);

	this.activeRequest = false; // prevent double submit

	this.fading = false; // toggle fading on / off

	this.activityIndicator = null; // dom object showing processing activity

	this.buttons = [];

	var buttons = this.form.getElementsByTagName('input');
	for (i=0; i<buttons.length; i++) {
		if (buttons[i].type == 'submit') this.buttons[this.buttons.length] = buttons[i];
	}

	var buttons = this.form.getElementsByTagName('button');
	for (i=0; i<buttons.length; i++) {
		if (buttons[i].type == 'submit') this.buttons[this.buttons.length] = buttons[i];
	}

}


AJAXFormValidator.prototype.setActivityIndicator = function(indicatorID) {
	this.activityIndicator = document.getElementById(indicatorID);
}

AJAXFormValidator.prototype.setFading = function(fadingConfig) {
	this.fading = true;
	this.fadingConfig = fadingConfig;
}


AJAXFormValidator.prototype.startRequest = function(e, validatorObj) {
	if (validatorObj.activeRequest) {
		return;
	}
	
	
	validatorObj.activeRequest = true;

	callback = { // callback of the ajax request
		success: function(o) {

			if (validatorObj.debug) {
				alert(o.responseText);
			}
			
			
			validatorObj.enableForm(validatorObj);

		
			try {
				//var response = YAHOO.lang.JSON.parse(o.responseText);
				var response = eval('('+o.responseText+')');
			}
			catch (e) {
				if (validatorObj.debug) {
					alert("Invalid response data\n------------------------------\n"+o.responseText);
				}
				return;
			}



			validatorObj.handleResponse(response, validatorObj);

			
			if (response.errors == false) { // all fields are valid
				if (validatorObj.resetForm) {
					validatorObj.form.reset();
				}
				validatorObj.callbackOnSuccessfulSubmit(response.result);
			}
			
			validatorObj.activeRequest = false;
		},

		failure: function(o) {
			if (validatorObj.debug) {
				alert(o.statusText+'\n'+o.status+'\n------------------------------\n'+o.responseText);
			}
			alert('There was an error while sending the data. Please try to resend it.');
			location.reload(true);
		},
		
		timeout: 30000
	}



	YAHOO.util.Connect.setForm(validatorObj.form);

	validatorObj.disableForm(validatorObj);

	var request = YAHOO.util.Connect.asyncRequest('POST', validatorObj.scriptURL, callback);
	if (!request) {
		alert('There was an error while loading the data.\n Please check your browser\'s security settings or your firewall.');
	}


	YAHOO.util.Event.stopEvent(e); // cancel form submit
}


AJAXFormValidator.prototype.handleResponse = function(response, validatorObj) {
	var element_selected = false;

	for (var i=0; i<response.data.length; ++i) {

		var item = response.data[i];

		element = document.getElementById(item.name);

		if (!element) {
			if (validatorObj.debug) {
				alert('unknown id: '+item.name);
			}
			continue;
		}

		validatorObj.setElementValue(element, item.value);

		if (item.ok == true) { // no error
			if (YAHOO.util.Dom.hasClass(element, 'AJAXFormValidator_error')) { // skip element if already ok
				validatorObj.removeErrorMessage(element);
				validatorObj.unmarkErrorField(element, validatorObj);
			}
		} else { // there is an error

			if (!element_selected && (element.tagName.toLowerCase() == 'input' || element.tagName.toLowerCase() == 'textarea')) {
				element.focus();
				element_selected = true;
			}

			validatorObj.removeErrorMessage(element);
			validatorObj.displayErrorMessage(element, item.message);

			if (!YAHOO.util.Dom.hasClass(element, 'AJAXFormValidator_error')) {
				validatorObj.markErrorField(element, validatorObj);
			}
		}
	}
}



AJAXFormValidator.prototype.markErrorField = function(element, validatorObj) {
	YAHOO.util.Dom.addClass(element, 'AJAXFormValidator_error');

	if (validatorObj.fading) {
		var attributes;

		if (element.tagName.toLowerCase() == 'input' || element.tagName.toLowerCase() == 'textarea') {
			attributes = validatorObj.fadingConfig.fadein.input;

		} else if (element.tagName.toLowerCase() == 'div') {
			attributes = validatorObj.fadingConfig.fadein.div;
		}

		element.animation = new YAHOO.util.ColorAnim(element, attributes, 0.5);
		element.animation.animate();
	}
}


AJAXFormValidator.prototype.unmarkErrorField = function(element, validatorObj) {
	YAHOO.util.Dom.removeClass(element, 'AJAXFormValidator_error');

	if (validatorObj.fading) {
		var attributes, conf = validatorObj.fadingConfig;

		if (element.tagName.toLowerCase() == 'input' || element.tagName.toLowerCase() == 'textarea') {
			attributes = validatorObj.fadingConfig.fadeout.input;
		} else if (element.tagName.toLowerCase() == 'div') {
			attributes = validatorObj.fadingConfig.fadeout.div;
		}
		element.animation = new YAHOO.util.ColorAnim(element, attributes, 0.5);
		element.animation.animate();
	}
}

AJAXFormValidator.prototype.setElementValue = function(element, value) {
	if (value == null) return;

	if (element.tagName.toLowerCase() == 'input' || element.tagName.toLowerCase() == 'textarea') {
		element.value = value;
	}
}

AJAXFormValidator.prototype.displayErrorMessage = function(element, message) {
	if (message == '') return;

	if (element.tagName.toLowerCase() == 'input' || element.tagName.toLowerCase() == 'textarea') {
		var span = document.createElement('span');
		span.innerHTML = ' '+message;
		span.AJAXFormValidatorError = true;
		element.parentNode.insertBefore(span, element.nextSibling);

	} else if (element.tagName.toLowerCase() == 'div') {
		var div = document.createElement('div');
		div.innerHTML = message;
		div.AJAXFormValidatorError = true;
		element.parentNode.insertBefore(div, element.nextSibling);
	}
}

AJAXFormValidator.prototype.enableForm = function(validatorObj) {
	validatorObj.enableSubmitButtons();
	
	//YAHOO.util.Dom.setStyle(validatorObj.form, 'opacity', 1.0);
	//validatorObj.form.animation = new YAHOO.util.Anim(validatorObj.form, { opacity: { to: 1 }} , 0.3);
	//validatorObj.form.animation.animate();
	validatorObj.formFadein(validatorObj);
	
	if (validatorObj.activityIndicator != null) {
		validatorObj.activityIndicator.style.visibility = 'hidden';
	}
}

AJAXFormValidator.prototype.disableForm = function(validatorObj) {
	validatorObj.disableSubmitButtons();
	
	validatorObj.formFadeout(validatorObj);
	
	if (validatorObj.activityIndicator != null) {
		validatorObj.activityIndicator.style.visibility = 'visible';
	}
}


AJAXFormValidator.prototype.formFadeout = function(validatorObj) {
	validatorObj.form.animation = new YAHOO.util.Anim(validatorObj.form, { opacity: { to: .4 }} , 0.3);
	validatorObj.form.animation.animate();
}

AJAXFormValidator.prototype.formFadein = function(validatorObj) {
	validatorObj.form.animation = new YAHOO.util.Anim(validatorObj.form, { opacity: { to: 1 }} , 0.3);
	validatorObj.form.animation.animate();
}


AJAXFormValidator.prototype.removeErrorMessage = function(element) {
	if (element.nextSibling && element.nextSibling.AJAXFormValidatorError) {
		element.parentNode.removeChild(element.nextSibling);
	}
}

AJAXFormValidator.prototype.disableSubmitButtons = function() {
	for (i=0; i<this.buttons.length; i++) {
		this.buttons[i].disabled = true;
	}
}

AJAXFormValidator.prototype.enableSubmitButtons = function() {
	for (i=0; i<this.buttons.length; i++) {
		this.buttons[i].disabled = false;
		if (this.buttons[i].blur) {
			this.buttons[i].blur();
		}
	}
}

