Validator = {
	setForm: function(metadata){
		var $form = $('form:last')
			.submit(function(e){
				if (this.metadata)
					Validator.parseMetadata(this);

				this.errorList = null;
				$('div.error-list, p.error-note', this)
					.remove();
				$('.error',this)
					.removeClass('error');

				for (var i=0, el=this.elements.length; i<el; i++) {
					var elem = this.elements[i];
					if (elem.validate) {
						var msg = elem.validate();
						if (msg)
							Validator.addError(elem, msg);
					}
				}

				if (this.errorList) {
					Validator.focusFirst(this);
					e.preventDefault();
				}

				this.errorList = null;
			});
		var form = $form[0];
		form.metadata = metadata;
		$(function(){
			form.errorList = $('div.error-list ul', form);
			if (form.errorList.size())
				Validator.focusFirst(form);
		});
	},
	focusFirst: function(form) {
		var ids = ',';
		$('a', form.errorList).each(function(){
			ids += this.href.split('#')[1] +',';
		});
		for (var i=0, el=form.elements.length; i<el; i++)
			if (ids.indexOf(','+ form.elements[i].id +',') >= 0) {
				form.elements[i].focus();
				form.elements[i].select();
				break;
			}
	},
	addError: function(elem, msg) {
		if (!elem.form.errorList) {
			elem.form.errorList = $(elem.form)
				.prepend('<div class="box error-list"><h2 class="title">'+ elem.form.errorListTitle +'</h2><ul></ul></div>')
				.find('ul');
		}
		$(elem).parent()
			.prepend('<p class="error-note">'+ msg +'</p>');
		$(elem).parent()
			.addClass('error');
		elem.form.errorList
			.append('<li><a href="'+ htmlentities(document.location.href.split('#')[0] +'#'+ elem.id) +'" onclick="return Validator.focus(this);">'+ msg +'</a></li>');
	},
	focus: function(link){
		var e = $('#'+ link.href.split('#')[1])[0];
		if (e.focus) e.focus();
		if (e.select) e.select();
		return false;
	},
	parseMetadata: function(form) {
		var data = form.metadata;
		form.errorListTitle = data.errorListTitle;
		data.errorListTitle = undefined;
		for (var model in data) {
			for (var field in data[model]) {
				var elem = form.elements['data['+ model +']['+ field +']'];
				if (elem) this.setValidation(elem, data[model][field]);
			}
		}
		form.metadata = undefined;
	},
	setValidation: function(elem, data) {
		elem.validate = function(){
			for (var i in data) {
				if (Validator.methods[data[i].method]) {
					if (!Validator.methods[data[i].method](this.value))
						return data[i].message;
				} else if (!data[i].method.indexOf('/')) {
					if (!eval(data[i].method.replace(/\\A|\\z/g, "")).test(this.value))
						return data[i].message;
				}
			}
		};
	},
	methods: {
		isFileValid: function(value){
			return value;
		}
	}
};
function htmlentities(string) {
	var chars = htmlentities.chars;
	var entities = htmlentities.entities;
	for (var i = 0; i < chars.length; i++)
	{
		myRegExp = new RegExp();
		myRegExp.compile(chars[i],'g')
		string = string.replace (myRegExp, '&' + entities[i] + ';');
	}
	return string;
}
htmlentities.chars = '&àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ€\"ß<>¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾'.split('');
htmlentities.entities = 'amp,agrave,aacute,acirc,atilde,auml,aring,aelig,ccedil,egrave,eacute,ecirc,euml,igrave,iacute,icirc,iuml,eth,ntilde,ograve,oacute,ocirc,otilde,ouml,oslash,ugrave,uacute,ucirc,uuml,yacute,thorn,yuml,Agrave,Aacute,Acirc,Atilde,Auml,Aring,AElig,Ccedil,Egrave,Eacute,Ecirc,Euml,Igrave,Iacute,Icirc,Iuml,ETH,Ntilde,Ograve,Oacute,Ocirc,Otilde,Ouml,Oslash,Ugrave,Uacute,Ucirc,Uuml,Yacute,THORN,euro,quot,szlig,lt,gt,cent,pound,curren,yen,brvbar,sect,uml,copy,ordf,laquo,not,shy,reg,macr,deg,plusmn,sup2,sup3,acute,micro,para,middot,cedil,sup1,ordm,raquo,frac14,frac12,frac34'.split(',');


