(function($) { 
$.fn.validate=function(options) {
 var validator=new $.validator(options,this);
 if(validator.settings.onsubmit) {
 this.submit(function(event) {
 if(validator.settings.debug) {
 event.preventDefault();
 }
 return validator.validateForm();
 });
}
 if(validator.settings.event) {
 validator.elements.bind(validator.settings.event,function() {
 validator.errorList= {};
 validator.hideElementErrors(this);
 validator.validateElement(this);
 validator.showErrors();
 });
}
 return validator;
};
var v= $.validator=function(options,form) {
 this.errorList= {};
 var settings=this.settings= $.extend({},v.defaults,options);

 this.elements= $(":input:not(:submit):not(:reset)",form);
 this.currentForm=form[0];
 this.errorContainer=settings.errorLabelContainer.length && settings.errorLabelContainer
 ||settings.errorContainer.length && settings.errorContainer
 || $([])
 this.errorContext=this.errorContainer.length && this.errorContainer||form;

 var instance=this;
 this.elements.focus(function() {
 instance.lastActive=this;
});
};

v.defaults= {
 errorClass: "error",
 focusInvalid:true,
 errorContainer: $([]),
 errorLabelContainer: $([]),
 onsubmit:true
};
v.prototype= {

 validateForm:function() {
 this.errorList= {};
 
 this.settings.errorLabelContainer.hide();
 this.settings.errorContainer.hide();
 var labels= $("label."+this.settings.errorClass,this.errorContext).hide();
 if(this.settings.errorWrapper) {
 labels.parents(this.settings.errorWrapper).hide();
 }
 var instance=this;
 this.elements.each(function() {
 instance.validateElement(this);
 });
 return this.isFormValid();
},

 validateElement:function(element) {
 $(element).removeClass(this.settings.errorClass);
 var rules=this.findRules(element);
 for(var i=0,rule;rule=rules[i];i++ ) {
 try{
 var method=v.methods[rule.name];
 if( !method)
 throw("validateElement() error: No method found with name "+rule.name);
 if( !method( $(element).val(),element,rule.parameters) ) {
 var id=this.findId(element);
 if(!id && this.settings.debug) {
 console.error("could not find id/name for element, please check the element %o",element);
 }
 var list=this.errorList[id] || (this.errorList[id] = []);
 list[list.length] =this.formatMessage(method,rule,id);
 }
 }catch(e) {
 if(this.settings.debug) {
 console.error("exception occured when checking element "+element.id
 + ", check the '"+rule.name+ "' method");
 }
 throw e;
 }
 }
},


 formatMessage:function(method,rule,elementID) {
 var m=this.settings.messages,
 param=rule.parameters,
 first=param.constructor==Array?param[0] :param;
 if(m && m[elementID])
 if(m[elementID].constructor==String)
 message=m[elementID];
 else
 message=m[elementID][rule.name];
 else
 message=method.message;
 return message && message.replace("{0}",first|| "").replace("{1}",param[1] || "");
},

 hideElementErrors:function(element) {
 var errorLabel= $("label."+this.settings.errorClass+ "[@for="+this.findId(element) + "]",this.errorContext).hide();
 if(this.settings.errorWrapper) {
 errorLabel.parent(this.settings.errorWrapper).hide();
 }
},

 isFormValid:function() {
 var count=0;
 for(var i in this.errorList) {
 count++;
 }
 if(count) {
 this.showErrors();
 return false;
 }else{
 if(this.settings.submitHandler) {
 this.settings.submitHandler(this.currentForm);
 return false;
 }
 return true;
 }
},

 showErrors:function() {
 this.settings.errorContainer.show();
 this.settings.errorLabelContainer.show();
 var first=true;
 for(var elementID in this.errorList) {
 if(first && this.settings.focusInvalid) {
 if(this.lastActive && this.errorList[this.lastActive.id])
 this.lastActive.focus();
 else{
 try{
 var element= $("#"+elementID);
 if(!element.length)
 element= $('[@name='+elementID+']',this.currentForm);
 element[0].focus();
 }catch(e) {if(this.settings.debug)console.error(e); }
 }
 first=false;
 }
 this.showError(elementID,this.errorList[elementID][0]);
 }
},

 showError:function(elementID,message) {
 var element= $("#"+elementID).addClass(this.settings.errorClass),
 message=element.attr('title') ||message|| "<strong>Warning: No message defined for "+elementID+ "</strong>",
 errorLabel= $("label."+this.settings.errorClass,this.errorContext).filter("[@for="+elementID+ "]"),
 wrapper=this.settings.errorWrapper;
 if(errorLabel.length) {
 if(errorLabel.attr("generated") ) {
 errorLabel.text(message);
 }
 errorLabel.show();
 if(wrapper) {
 errorLabel.parents(wrapper).show();
 }
 }else{
 var errorLabel= $("<label>").attr({"for":elementID,generated:true}).addClass("error").html(message);
 if(wrapper) {
 errorLabel=errorLabel.show().wrap("<"+wrapper+ "></"+wrapper+ ">").parent();
 }
 if(!this.errorContainer.append(errorLabel).length) 
 errorLabel.insertAfter(element);
 errorLabel.show();
 }
},

 findRules:function(element) {
 var data;
 if(this.settings.rules) {
 data=this.settings.rules[this.findId(element)];
 }else{
 data= $(element).data();
 var metaWrapper=this.settings.metaWrapper;
 if(metaWrapper)
 data=data[metaWrapper];
 }
 var rules= [];
 if(!data)
 return rules;
 $.each(data,function(key,value) {
 var rule=rules[rules.length] = {};
 rule.name=key;
 rule.parameters=value;
 });
 return rules;
},

 findId:function(element) {
 var id= ( /radio|checkbox/i.test(element.type) ) ?element.name:element.id;
 if(!id) {
 var formId=element.form.id,
 idcleanup= /[^a-zA-Z0-9\-_]/g;
 id=element.id= (formId?formId.replace(idcleanup, "") : "") +element.name.replace(idcleanup, "");
 }
 return id;
}

};
function getLength(value,element) {
 switch(element.nodeName.toLowerCase() ) {
 case'select':
 return $("option:selected",element).length;
 case'input':
 if( /radio|checkbox/i.test(element.type) )
 return $(element.form||document).find('[@name='+element.name+ ']:checked').length;
}
 return value.length;
};
v.methods= {

 required:function(value,element) {
 switch(element.nodeName.toLowerCase() ) {
 case'select':
 var options= $("option:selected",element);
 return options.length>0 &&  (element.type== "select-multiple"||options[0].value.length>0);
 case'input':
 switch(element.type.toLowerCase() ) {
 case'checkbox':
 case'radio':
 return getLength(value,element) >0;
 }
 default:
 return $.trim(value).length>0;
 }
},

 minLength:function(value,element,param) {
 var length=getLength(value,element);
 return !v.methods.required(value,element) ||length>=param;
},

 maxLength:function(value,element,param) {
 var length=getLength(value,element);
 return !v.methods.required(value,element) ||length<=param;
},


 rangeLength:function(value,element,param) {
 var length=getLength(value,element);
 return !v.methods.required(value,element) || (length>=param[0]  && length<=param[1] );
},

 minValue:function(value,element,param) {
 return !v.methods.required(value,element) ||value>=param;
},


 maxValue:function(value,element,param) {
 return !v.methods.required(value,element) ||value<=param;
},


 rangeValue:function(value,element,param) {
 return !v.methods.required(value,element) || (value>=param[0]  && value<=param[1] );
},


 email:function(value,element) {
 return !v.methods.required(value,element) || /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/i.test(value);
},

 url: function(value,element) {
 return !v.methods.required(value, element) || /^(https?|ftp):\/\/[A-Z0-9](\.?[A-Z0-9能謁[A-Z0-9_\-能謁*)*(\/([A-Z0-9能謁[A-Z0-9_\-\.能謁*)?)*(\?([A-Z0-9能謁[A-Z0-9_\-\.%\+=&能謁*)?)?$/i.test(value);
},

 date:function(value,element) {
 return !v.methods.required(value,element) || !/Invalid|NaN/.test(new Date(value));
},

 dateISO:function(value,element) {
 return !v.methods.required(value,element) || /^\d{4}[/-]\d{1,2}[/-]\d{1,2}$/.test(value);
},

 dateDE:function(value,element) {
 return !v.methods.required(value,element) || /^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
},

 number:function(value,element) {
 return !v.methods.required(value,element) || /^-?[,0-9]+(\.\d+)?$/.test(value); 
},

 numberDE:function(value,element) {
 return !v.methods.required(value,element) || /^-?[\.0-9]+(,\d+)?$/.test(value);
},

 digits:function(value,element) {
 return !v.methods.required(value,element) || /^\d+$/.test(value);
},


 equalTo:function(value,element,param) {
 return value== $(""+param).val();
}
};
var messages= {
 required: "This field is required.",
 maxLength: "Please enter a value no longer then {0} characters.",
 minLength: "Please enter a value of at least {0} characters.",
 rangeLength: "Please enter a value between {0} and {1} characters long.",
 email: "Please enter a valid email address.",
 url: "Please enter a valid URL.",
 date: "Please enter a valid date.",
 dateISO: "Please enter a valid date (ISO).",
 dateDE: "Bitte geben Sie ein g?tiges Datum ein.",
 number: "Please enter a valid number.",
 numberDE: "Bitte geben Sie eine Nummer ein.",
 digits: "Please enter only digits",
 equalTo: "Please enter the same value again.",
 rangeValue: "Please enter a value between {0} and {1}.",
 maxValue: "Please enter a value less than or equal to {0}.",
 minValue: "Please enter a value greater than or equal to {0}."
};
for(var key in messages) {
 v.methods[key].message=messages[key];
}
v.addMethod=function(name,method,message) {
(v.methods[name] =method).message=message;
};
})(jQuery);