(function($) {
    
    $.fn.formvalidate = function(o) {
        
        var opts = {
            duration: 500,
            errorMessage: 'Bitte f&uuml;llen Sie alle erforderlichen Felder korrekt aus!',
            offsetTop: 50
        }
        
        if (o != null)
            $.extend(opts, o);

        return this.each(function() {
            
            $(this).submit(function(e) {
                var errors = new Array();
                
                $('input.error, label.error').removeClass('error');
                $('input[type=checkbox]').each(function() {
                    if ($(this).parent().is('span') && $(this).parent().hasClass('error')) {
                        var cnt = $(this).parent().contents()
                        $(this).parent().replaceWith(cnt);
                    }
                });

                $(this).find('input.required[type=text], textarea.required, select.required').each(function() {
                    if ($(this).val() == '') {
                        errors.push($(this));
                    }
                    else if ($(this).hasClass('mail')) {
                        var reg = new RegExp('([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})');
                        result = reg.exec($(this).val());
                        if (result == null) 
                            errors.push($(this));
                    }
                });

                $(this).find('input.required[type=checkbox], input.required[type=radio]').each(function() {
                    if(!$(this).is(':checked'))
                        errors.push($(this));
                });

                $(this).find('input.mail:not(.required)').each(function() {
                    if ($.trim($(this).val()) != '') {
                        var reg = new RegExp('([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})');
                        result = reg.exec($(this).val());
                        if (result == null)
                        	errors.push($(this));
                    }
                });
                
                $(this).find('.required:not(input.required, textarea.required, select.required)').each(function() {
                    if($(this).find('input').length == 0)
                        return;
                        
                    var filled = 0;
                    
                    $(this).find('input[type=text], textarea, select').each(function() {
                        if($.trim($(this).val()) != '')
                            filled++;
                    });
                    
                    $(this).find('input[type=checkbox], input[type=radio]').each(function() {
                        if($(this).is(':checked'))
                            filled++;
                    });
                    
                    if (filled == 0)
                        errors.push($(this));
                });

                if (errors.length > 0) {
                    
                    $(this).find('.errorList').remove();
                    
                    var errDiv = $('<div class="errorList">' + opts.errorMessage + '</div>');
                    
                    $(this).prepend(errDiv);
                    
                    for (var i = 0; i < errors.length; i++) {
                        if (errors[i].is('[type=checkbox]') && errors[i].parent('span[class*=error]').length == 0) {
                            var span = $('<span></span>');
                            span.attr('class', errors[i].attr('class'));
                            span.addClass('error');
                            errors[i].wrap(span);
                        }
                            
                        errors[i].addClass('error');
                        if (errors[i].attr('id') != '')
                        	$('label[for=' + errors[i].attr('id') + ']').addClass('error');
                    }
                    
                    $('html,body').animate({ scrollTop: errDiv.offset().top - opts.offsetTop }, opts.duration);
                    
                    e.preventDefault();
                    return false;
                }

            })
            
        });
        
    }
    
})(jQuery)



