/**
 *	Reisplanner validator
 *	--------------------------
 */

function Validator(gui, form) {
	this.gui = gui;
}

Validator.prototype = {
	ATTR_REQUIRED:'ns:required',
	ATTR_COMPLETE:'ns:complete',
	ATTR_PATTERN:'ns:pattern',
	
	TYPE_TEXT:/text/i,
	TYPE_SELECT:/select/i,
	TYPE_RADIO:/radio/i,
	TYPE_CHECK:/check/i,

	TIME_COOLDOWN: 2000,

	submit:function(form, serverValidate) {
		// Step 1: prevent duplicate calls
		if(this.submitting(form)) return;

		// Step 2: check whether all required fields are filled out
		if(!this.validateRequired(form)) return;

		// Step 3: send values to server for pre-submit validation
		if(serverValidate) {
			var post = this.gui.getFormValues(form);
			var url = this.gui.getProperty('POST_VALIDATE', form);
			var self = this;
			XMLHttp.sendAndLoad(post, url, function(xml){
				self.validateServer(form, xml);
			});
		} else {
			ClassName.add(document.body, 'loading');
			form.submit();
		}
	},

	submitting:function(form) {
		if(!form._submitting) {
			form._submitting = true;
			setTimeout(function(){
				form._submitting = false;
			}, this.TIME_COOLDOWN);
			return false;
		}	return true;
	},

	validateRequired:function(form) {
		var elements = form.elements;
		var pattern = null;
		var required = null;
		var isValid = true;
		for (var el,i=0; i<elements.length; i++) {
			el = elements[i];
			pattern = el.getAttribute(this.ATTR_PATTERN);
			required = /true/i.test(el.getAttribute(this.ATTR_REQUIRED));

			if(el.offsetHeight > 0 && !el.disabled && (required || el.getAttribute(this.ATTR_COMPLETE))) {
				if(
					(this.TYPE_TEXT.test(el.type) && !el.value) || 
					(this.TYPE_SELECT.test(el.type) && el.selectedIndex < 1) ||
					(this.TYPE_CHECK.test(el.type) && !el.checked) ||
					(this.TYPE_RADIO.test(el.type) && !this.checkedOne(el))
				){
					try {
						this.gui.displayError(el, true);
						this.currentSection = el.parentNode;
						isValid = false;
					} catch (invisibleElementException) {
						// do nothing
						throw invisibleElementException
					}
				} else {
					if(isValid || this.currentSection != el.parentNode)
						this.gui.displayError(el, false);
				}
			}

			if(el.offsetHeight > 0 && !el.disabled && el.value && pattern) {
				var reg = new RegExp("^"+pattern+"$", "i");
				if(!reg.test(el.value)) {
					try {
						this.gui.displayError(el, true);
						if(required) isValid = false;
					} catch (invisibleElementException) {
						// do nothing
					}
				} else {
					this.gui.displayError(el, false);
				}
			}

		}
		if(isValid) {
			this.gui.displayErrorMessage(form, false);
		}
		return isValid;
	},

	validateServer:function(form, xml) {
		var root = xml.documentElement || xml.getElementsByTagName("validatie")[0];
		var errors = root? root.getElementsByTagName("error") : [];
		var isValid = true;

		var element, error, list = ''; 
		for (var e,i=0; i<errors.length; i++) {
			error = errors[i];
			element = form.elements[error.getAttribute('veld')];
			if(element) {
				isValid = false;
				this.gui.displayError(element, true);
				list += '<br />- ' + error.firstChild.nodeValue;
			}
		}

		this.gui.displayErrorMessage(form, list);

		if(isValid || /true/i.test(root.getAttribute('valid'))) {
			ClassName.add(document.body, 'loading');
			form.submit();
		}
	},

	checkedOne:function(radio) {
		var radios = radio.form.elements[radio.name];
		for (var i=0; i<radios.length; i++) {
			if(radios[i].checked) return true;
		}	return false;
	},

	scope:function(method) {
		var scope = this;
		return function() {
			return method.apply(scope, arguments);
		}
	}
}