(function($){

  function validate ( e ) {
    var form = $( this );

    var inputs = form.find(':input[name].required, .required :input[name]');
    inputs.closest( '.required' ).removeClass( 'formerror-missing' );
    var valid = true;

    // pass 1 - serialize
    var serial = {};
    inputs.each(function(){
      var inp = jQuery( this );
      var val = inp.val();
      var data = serial[ this.name ] || [];
      if ( inp.is( ':checkbox, :radio' ) ) {
        if ( inp.attr( 'checked' ) ) {
          data.push( val );
        }
      }
      else if ( /\S/.test( val ) ) {
        data.push( val );
      }
      serial[ this.name ] = data;
    });

    // pass 2 - are there any empty arrays in serial?
    var missing = [];
    for ( var name in serial ) {
      if ( serial[ name ].length === 0 ) {
        // this form is invalid
        valid = false;
        var ips = inputs.filter( '[name=' + name + ']' );
        var ctrl = ips.closest( '.required' ).addClass( 'formerror-missing' );

        // create a human readable error message from 
        var err = '', head = '';
        if ( ips.length == 1 ) {
          if ( ips.attr( 'id' ) )
            err = form.find( 'label[for=' + this.id + ']' ).text();
          if ( !err )
            err = ctrl.find( 'label' ).text();
          if ( !err )
            err = ips.attr( 'title' ) || ctrl.attr( 'title' );
          err = err.replace(/^[\s\*]*|^[\s\*]*/, '') || 'Ótitlaður reitur';
          head = ips.eq(0).closest( 'fieldset' ).find( ':heading:first' )
                    .text().replace(/^[\s\*]*|^[\s\*]*/, '');
          if ( head )
            head = '[' + head + ']';
        }
        else {
          err = '';
          var fs = $.unique( ips.closest( 'fieldset' ) );
          var hd = $( fs ).find( ':header' ).map(function () {
            return $( this ).text().replace(/^[\s\*]*|^[\s\*]*/, '');
          });
          err = hd.get().join( ' / ' );
        }
        missing.push( err + ' ' + head  );
      }
    }

    // report errors
    if ( !valid ) {

      alert( 'Eftirfarandi gildi þarf að fylla út:\n' +
             '\n* ' + missing.join( '\n* ' )  );
      ips.eq(0).focus();

    }

    return valid;
  }


  $.fn.autovalidate = function ( conf ) {
    this.filter('form').each(function () {
      $( this ).bind( 'submit', validate );
    });
    return this;
  }
  
})(jQuery);