Validator = Class.create();
Validator.prototype = {
		
	initialize: function(form) {
		if( !form )
			return;		
		this.form = $(form);
		this.form.validator = this;		
		this.valid = false;
		this.onValidated = false;
		this.beforeValidated = false;
		this.rules = new Array();
		this.ajaxChecks = new Array();
		if(this.form.onsubmit)
			this.onValidated = this.form.onsubmit;
		this.form.onsubmit = function() { return this.validator.validate() };
	},
	
	onsubmit: function(evt) {
	},
	
	addRule: function(element, rule, message, container ) {
		var type = rule.match(/^[a-zA-Z]+/);
		type = type ? type[0] : false;
		var param = rule.match(/^[a-zA-Z]+=(.+)/);
		param = param ? param[1] : false;
		switch(type) {
			case "username"		:
			case "alpha"		:
			case "numeric"		:
			case "alphanumeric"	:
			case "email"		:
			case "emailList"	:
			case "url"			:
			case "required"		:
			case "equal"		:
			case "min"			:
			case "max"			:
			case "tags"			:
			case "imagefile"	:
			case "audiofile"	:
			case "uniqueUser"	: // TODO
			case "uniqueEmail"	: // TODO
			case "uniqueBand"	: // TODO								
			case "regex"		: this.rules.push( { element: this.form.elements[element], type: type, param: param, message: message, container: $(container), valid: false } ); break;
			default				: alert("Invalid validator rule: " + type);
		}
	},
	
	validate: function() {
		if(this.beforeValidated && this.beforeValidated() == false)
			return false;
		this.valid = true;
		this.first = false;
		this.elements = Form.getElements(this.form);		
		this.elements.each( function(e) { if(e.length && e.tagName!='SELECT') e[0].errors = new Array(); else e.errors = new Array(); } );
		this.rules.each( function(e) { if ( e.container ) e.container.errors = Array() } );
		for(var i=0; i<this.rules.length; i++)
			this.ruleCheck(this.rules[i]);	
		for(var i=0; i<this.elements.length; i++)
			this.displayErrors(this.elements[i]);	
		if( this.first )
		{
			if( this.first.length)
				Field.focus(this.first[0]);
			else
				Field.focus(this.first);
		}
			
		if( this.valid && (!this.onValidated || this.onValidated() != false) )
			return true;
		return false;
	},
	
	ruleCheck: function(rule) {
		var element = rule.element;
		if( element && element.disabled )
		{
			rule.valid = true;
			return;
		}
		
		switch(rule.type)
		{
			case "required"		: 
							if( !element ) {rule.valid = false; break;}
							if( element.tagName == 'SELECT' )
								rule.valid = element.value.length > 0 && element.value != 0 /*&& element.value != ""*/;
							else if( element.length ) // Array of radio buttons
								rule.valid = $A(element).any(function(e) {return e.checked;});
							else if(element.getAttribute('type') == 'checkbox')
								rule.valid = element.checked;
							else
								rule.valid = element.value.length ? true : false; break;
			case "username"		: rule.valid = (element.value == '' || element.value.match(/^[a-z0-9]{4,16}$/i)) ? true : false; break;
			case "alpha"		: rule.valid = element.value.match(/^[a-z]*$/i) ? true : false; break;
			case "numeric"		: rule.valid = element.value.match(/^[0-9]*$/i) ? true : false; break;
			case "alphanumeric"	: rule.valid = element.value.match(/^[a-z0-9]*$/i) ? true : false; break;
			case "email"		: rule.valid = element.value.length == 0 || element.value.trim().match(/^[a-z0-9\-\.\_]+@([a-z0-9\-\_]+\.)+[a-z]{2,4}$/i) ? true : false; break;
			case "emailList"	: rule.valid = element.value.length == 0 || element.value.match(/^[\s\r\n]*[a-z0-9\-\.\_]+@([a-z0-9\-\_]+\.)+[a-z]{2,4}[\s\r\n]*(,[\s\r\n]*[a-z0-9\-\.\_]+@([a-z0-9\-\_]+\.)+[a-z]{2,4}[\s\r\n]*)*$/i) ? true : false; break;
			case "url"			: rule.valid = element.value.length == 0 || element.value.match(/^https?:\/\/([a-z0-9][a-z0-9\-]*\.)+[a-z]{2,4}(\/.*)?$/i) ? true : false; break;
			case "min"			: rule.valid = (element.value.length == 0 || element.value.length >= rule.param) ? true : false; break;
			case "max"			: rule.valid = element.value.length <= rule.param ? true : false; break;
			case "equal"		: rule.valid = element.value == this.form.elements[rule.param].value; break;
			case "uniqueUser"	: 
			case "uniqueEmail"	: rule.valid = true; break;
			case "tags"			: rule.valid = !element.value.match(/[\`\~\!\@\#\$\%\^\&\*\(\)\_\+\-\=\[\]\{\}\;\'\\\:\"\|\,\.\/\<\>\?]/); break;
			case "imagefile"	: rule.valid = element.value.length == 0 || element.value.match(/\.gif$|\.jpg$|\.png$|\.jpeg$|\.bmp$/i); break;
			case "audiofile"	: rule.valid = element.value.length == 0 || element.value.match(/\.mp3$/i); break;
			case "regex"		: var r = new RegExp(rule.param, "i");
									rule.valid = r.test(element.value); break;
		}

		if( rule.container )
			element.container = rule.container
		
		if( !rule.valid && rule.element )
		{
			if(!this.first)
				this.first = element;
			if( rule.message.length )
			{
				if(element.length && element.tagName != 'SELECT')
					element[0].errors.push(rule.message);					
				else
					element.errors.push(rule.message);
			}
			
			this.valid = false;
		}
	},
	
	displayErrors: function(element, errors) {
		if( typeof(element) == 'string' )
			if( this.form.elements[element] )
				element = this.form.elements[element]
			else
				element = $(element);
		if( !element )
			return;
			
		if( typeof(errors) == 'string' )
			errors = [errors];
		if( element.container )
		{
			element.container.errors = element.errors;
			element = element.container;
		}
			
		var node = element.previousSibling;	
		if( node && node.className == 'errorContainer')
			node.parentNode.removeChild(node);
		if( errors )
			element.errors = errors;
		if( element.errors && element.errors.length > 0 )
		{				
			this.appendErrors(element, element.errors);
		}
	},
	
	appendErrors: function(element, errors) {
		if( typeof(element) == 'string' )
			if( this.form && this.form.elements[element] )
				element = this.form.elements[element]
			else
				element = $(element);
		if( !element )
			return;
			
		if( typeof(errors) == 'string' )
			errors = [errors];
		var node = element.previousSibling;	
		if( errors && errors.length > 0 )
		{	
			if( !node || node.className != 'errorContainer') {
				node = document.createElement("DIV");
				node.className = "errorContainer";
				node.style.cssText = "font-size: 10px; font-family: Verdana; font-weight: bold; color: #FF0000; margin-bottom: 2px;";
				element.parentNode.insertBefore(node, element);
			}
			new Insertion.Bottom(node, '<div>' + errors.join("</div><div>") + '</div>');
		}
	},
	
	clearErrors: function() {
		$(this.form).getElementsByClassName('errorContainer').each(function(el) {
			Element.remove(el);
		});
	}
}

validator = new Validator();