﻿// JavaScript Document

// 2009/07/22

var VALIDATION_TEST = false;


var Validator = Class.create({
	initialize: function(form){
		this.form = $(form);
		this.controls = $A(arguments).slice(1);
		this.form.observe('submit', this.validate.bindAsEventListener(this));
	},
	
	validate: function(e){
		if(VALIDATION_TEST) 
			e.stop();
			
		var context = { items : {} };
		context.values = Form.serialize(this.form, true);
		var messages = new Array();
		var sources = new Array();
		
		context.messages = messages;
		context.sources = sources;
		
		this.controls.each(function(control){
			var local = {};
			if(!control.validate(context, local)){
				sources.push(control.getErrorSource(context, local));
				messages.push(control.getMessage(context, local));
			}
		}, this);
		
		messages = messages.compact();
		sources = sources.compact();
		
		if(messages.length){
			e.stop();
			alert(messages.join('\n'));
			var name = sources.first();
			this.form.getElements().each(function(element){
				if(element.name && element.name == name){
					element.focus();
					throw $break;
				}
			});
		}
	}
});

Validator.getUnique = function(){
	var counter = 0;
	return function () { return counter++; }
}();

var Constraints = {};

Constraints.AbstractConstraint = Class.create({
	initialize:function(name, message){
		this.name = name;
		this.message = message;
		this.uniqueIdentity = Validator.getUnique();
	},
	
	getName: function(){
		return this.name;	
	},
	
	getValue: function(context){
		return context.values[this.name];
	},
	
	getMessage: function(context){
		return this.message;
	},
	
	getErrorSource:function(context, local){
		return this.name;
	},
	
	validate: function(context){ return true; }
});

Constraints.Complex = Class.create(Constraints.AbstractConstraint, {
	initialize: function($super, name, message){
		$super(name, message);
		this.restrictions = $A(arguments).slice(3);
	},
	
	getMessage: function($super, context, local){
		return local.messages.first() || $super(context, local);	
	},
	
	getErrorSource: function($super, context, local){
		return local.sources.first() || $super(context, local);
	},
	
	validate : function(context, local){
		var messages = new Array();
		var sources = new Array();
		
		this.restrictions.each(function(restriction){
			var local = {};
			if(!restriction.validate(context, local)) {
				messages.push(restriction.getMessage(context, local));
				sources.push(restriction.getErrorSource(context, local));
			}
		});
		local.messages = messages;
		local.sources = sources;
		return !messages.length;
	}
});
/*
Constraints.Complex.prototype.initialize = function(name, message){
	Constraints.AbstractConstraint.prototype.initialize.apply(this, arguments);
	this.restrictions = $A(arguments).slice(2);
	console.log(this);
}*/

Constraints.All = Class.create(Constraints.Complex, {
	validate: function($super, context, local){
		$super(context, local);
		if(local.messages.length) {
			/*context.messages.push(
				local.messages.first() ? local.messages.first() : this.getMessage());
			
			context.sources.push(
				local.sources.first() ? local.sources.first() : this.getErrorSource());
			*/
			return false;
		}
		return local.messages.length != this.restrictions.length;
	}
});

Constraints.Any = Class.create(Constraints.Complex, {
	
	validate: function($super, context, local){
		$super(context, local);
		return local.messages.length != this.restrictions.length;
	}
});

Constraints.Exclude = Class.create(Constraints.AbstractConstraint, {
	initialize: function($super, name, message, exclusive){
		$super(name, message);
		this.exclusive = exclusive;
	},
	
	validate: function(context){
		if(this.getValue(context) == this.exclusive)
			return false;
		return true;
	}
});

Constraints.Match = Class.create(Constraints.AbstractConstraint, {
	initialize: function($super, name, message, pattern){
		$super(name, message);
		this.pattern = new RegExp(pattern, 'g');
	},
	
	validate: function(context){
		if(this.getValue(context) == undefined || !this.getValue(context).match(this.pattern))
			return false;
		return true;
	}
});

Constraints.EMail = Class.create(Constraints.AbstractConstraint, {
	validate: function(context){
		var value = this.getValue(context);
		return value.match(/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+\.([a-zA-Z0-9\._-]+)+$/) && !value.match(/\.{2,}/);
	}
});

Constraints.Number = Class.create(Constraints.Match, {
	initialize: function($super, name, message){
		$super(name, message, '^[0-9]+$');
	}
});

Constraints.Empty = Class.create(Constraints.AbstractConstraint, {
	validate : function(context){
		return !this.getValue(context).length;
	}
});

Constraints.Require = Class.create(Constraints.AbstractConstraint, {
	validate : function(context){
		return typeof this.getValue(context) !== 'undefined';
	}
});

Constraints.Custom = Class.create(Constraints.AbstractConstraint, {
	initialize: function($super, name, message, func){
		$super(name, message);
		if(!(func instanceof Function))
			throw {message : 'func is not Function.'};
		this.func = func;
	},
	
	validate : function(context){
		return this.func(context, this.getValue(context));
	}
});

Constraints.Length = Class.create(Constraints.AbstractConstraint, {
	initialize: function($super, name, message, min, max){
		$super(name, message);
		this.min = typeof min != 'number' ? -1 : min;
		this.max = typeof max != 'number' ? -1 : max;
	},
	
	validate : function(context){
		var value = this.getValue(context);
		return (this.min < 0 || value.length >= this.min) &&
			(this.max < 0 || value.length <= this.max);
	}
});



