if(VVF === undefined) {
	var VVF = {};
}

(function(namespace) {
	namespace = namespace || window;
	var $ = jQuery;
	
	// Configuration
	var config = {
		tpl: {
			header: '<p id="%id%ERROR" class="headerError">%msg%</p>',
			label: '<em id="%id%ERROR" class="%cls%">%msg%</em>'
		},
		cls: {
			error: 'error'
		}
	};
	
	// Access error message target
	function getErrorTarget(field) {
		var p = field, target;
		if(field.type == 'radio') {
			while((p = p.parentNode) && !$(p).hasClass('box'));
			if(p.nodeName == 'DIV') {
				target = $(p.getElementsByTagName('span')[0]);
			} else {
				while((p = p.parentNode) && p.nodeName != 'FIELDSET');
				if(p.nodeName == 'FIELDSET') {
					target = $(p.getElementsByTagName('span')[0] || p.getElementsByTagName('legend')[0]);
				}
			}
		} else if(field.type == 'text' && (p = field.parentNode)) {
			if(/day|month|year/.test(p.className)) {
				while(p = p.parentNode) {
				    if(p.nodeName == 'FIELDSET' || p.className == 'date') {break;}
				}
				if(p.nodeName == 'FIELDSET') {
					var tmp1 = p.getElementsByTagName('legend')[0] || p.getElementsByTagName('span')[0],
						tmp2;
					if(tmp1.nodeName == 'LEGEND' && (tmp2 = tmp1.getElementsByTagName('span')[0])) {
						target = $(tmp2);
					} else {
						target = $(tmp1);
					}
					tmp1 = tmp2 = null;
				} else if(p.className == 'date') {
				    target = $(p.getElementsByTagName('span')[0]);
				}
			} else {
				target = $('label[for=' + field.id + ']');
			}
		} else {
			target = $('label[for=' + field.id + ']');
		}
		if(target.hasClass('hide')) {
			target.wrapInner('<span class="hide"></span>').removeClass('hide');
		}
		return target;
	}
	
	// Radio ID/Name mapping
	var cacheRadioID = {};
	
	// Check radio group
	function checkRadioGroup(r) {
		if(r.nodeName) {return true;}
		var i = -1, c = false;
		while(r[++i]) {
			if(r[i].checked) {
				c = true;
				break;
			}
		}
		return c;
	}
	
	// Validator constructor
	var Validator = function(submit, form, datas) {
		if(!(this instanceof Validator)) {
			return new Validator(submit, form, datas);
		}
		
		this.initialize(submit, form, datas);
	};
	namespace.extend(Validator, {
		initialize: function(submit, form, datas) {
			var that = this;
			
			this.datas =      datas || {};
			this.submit =     submit;
			this.form =       form;
			this.problems =   0;
			
			$.each(datas, function(k, v) {
				if(k != 'header') {
					var o = document.forms[0].elements[k];
					if(o) {
					    if(o.length && o[0].type == 'radio') {
						    $(o).each(function() {
							    $(this).click(function() {
								    that.check(this);
							    });
						    });
					    } else {
						    var evt = (o.type.indexOf('select') > -1) ? 'change' : 'blur';
						    $(o)[evt](function() {
							    that.check(this);
						    });
					    }
					}
				}
			});
			
			$(document).mousedown(function(e) {
			    var t = e.target;
			    if(t.nodeName != 'INPUT') {
			        while(t.nodeName != 'A' && (t = t.parentNode));
			    }
			    if(t && t == submit) {
			        that.problems = 0;
				    $.each(datas, function(k, v) {
					    if(k != 'header' && document.forms[0].elements[k]) {
						    that.check(document.forms[0].elements[k], true);
					    }
				    });
				    /*if (!that.action) {
				        that.action = $(t).attr('href').replace('javascript:', '').replace(/\(\);?/, '');
				        $(t).attr('href', 'javascript:void(0);');
				    }*/
				    if(that.problems > 0) {
					    if(datas.header) {
						    that.addHeader();
					    }
				    } else {
				        window[that.action];
				        //eval('(' + that.action + ')');  
				    }
				    return false;
			    }
			});
		},
		
		check: function(field, submit) {
		    var id = field.name, c, r = false, rule;
		    if(field.type == 'radio' || (field.length && field[0].type == 'radio')) {
			    r = true;
			    c = !checkRadioGroup(field);
		    } else {
			    if(!id) {return;}
			    rule = this.datas[id].rule;
			    if(rule.constructor == Function) {
			        c = rule(field.value);
			    } else {
			        c = !rule.test(field.value);
			    }
		    }
		    if(c && (field.parentNode && field.parentNode.parentNode.className=="date")){
		        this.addError(document.getElementById("fBirthDay"), r, submit);
		        this.addError(document.getElementById("fBirthMonth"), r, submit);
		        this.addError(document.getElementById("fBirthYear"), r, submit);
		    }
		    else if(!c && (field.parentNode && field.parentNode.parentNode.className=="date")){
		        var fBirthDay = document.getElementById("fBirthDay");
		        var fBirthMonth = document.getElementById("fBirthMonth");
		        var fBirthYear = document.getElementById("fBirthYear");
		        if(this.datas["CustomerBirthDay"].rule.test(fBirthDay.value) && this.datas["CustomerBirthMonth"].rule.test(fBirthMonth.value) && this.datas["CustomerBirthYear"].rule.test(fBirthYear.value)){
		            this.removeError(fBirthDay, r, submit);
		            this.removeError(fBirthMonth, r, submit);
		            this.removeError(fBirthYear, r, submit);
		        }
		        else{
		            this.addError(fBirthDay, r, submit);
		            this.addError(fBirthMonth, r, submit);
		            this.addError(fBirthYear, r, submit);
		        }
		    }
		    else{
		        c ? this.addError(field, r, submit) : this.removeError(field, r, submit);
		    }
		},
		
		addError: function(field, r, submit) {
			if(r) {
				field = field[0] || field;
				cacheRadioID[field.name] = field.name;
			}
			var id = field.name, n = field.name, increment = false, target, el;
			if(!document.getElementById(id + 'ERROR')) {
				target = getErrorTarget(field);
				if(!target.length || ($('em.error', target).length && field.parentNode.parentNode.className!="date")) {return;}
				el = config.tpl.label.replace('%id%', id).replace('%cls%', config.cls.error).replace('%msg%', this.datas[n].msg);
				if(!$('em.error', target).length) target.append(el);
				$(field).addClass(config.cls.error);
				$('#' + id + 'REP').addClass(config.cls.error);
				this.problems++;
				increment = true;
			}
			if(submit && !increment) {this.problems++;}
		},
		 
		removeError: function(field, r, submit) {
	        if(r) {field = field[0] || field;}
		    var id = field.name;
		    if(cacheRadioID[field.name]) {
			    id = cacheRadioID[field.name];
		    }
		    if(document.getElementById(id + 'ERROR') || field.parentNode.parentNode.className=="date") {		
		        $('#' + id + 'REP').removeClass(config.cls.error);
		        $('#' + id + 'ERROR').remove();
		        $(field).removeClass(config.cls.error);     
		        this.problems--   
		    }
		    if(this.problems == 0) {
			    this.removeHeader();
		    }
		},
		
		addHeader: function() {
			var id = this.form.id, el;
			if(document.getElementById(id + 'ERROR')) {return;}
			el = config.tpl.header.replace('%id%', id).replace('%msg%', this.datas.header);
			$(el).prependTo(this.form).attr('tabindex', -1).focus();
		},
		
		removeHeader: function() {
			$('#' + this.form.id + 'ERROR').remove();
		}
	});
	
	if(!namespace.Validator) {
		namespace.Validator = Validator;
	}
})(VVF);