  var validatorFactory = {
    
      /**
       * Object that handles the submitting of the validated form
       */      
      submitHandler : {
          fields : [],
          messages: {
              'MISSING' : {},
              'INVALID_FORMAT' : {},
              'MISMATCH' : {},
              'TOO_SMALL': {},
              'TOO_BIG': {},
              'WRONG_OLD_PASSWORD' : {},
              'ALREADY_IN_USE': {},
              'INVALID_FORMAT': {},
              'CUSTOM' : {}
          },
          success : null,
          type : 'feedbackform',
          url : '',
        
          /**
           * Prepares the data in the form fields to be passed through the ajax request
           *
           * @return a name/value pairs string
           */
          getFormData : function() {
              var form_data = [];
        
              for( var i=0; i< this.fields.length; i++ ) {
                  var field = this.fields[i];
  
                  if( field.callback ) {
                      if( value = field.callback(field.id) ) {
                          form_data.push(value);
                      }
                  } else {
                      var fieldJq = $('#' + field);
                      
                      if( fieldJq.attr('type') === 'checkbox' ) {
                          if( fieldJq.is(':checked') ) {
                              var value = fieldJq.val();
                          }
                      } else {
                          var value = fieldJq.val()
                      }
                    
                      if( value ) {
                          form_data.push(field + '=' + encodeURI(value));
                      }
                  }
              }  
            
              return form_data.join('&');  
          },
                
          /**
           * Returns the actual function that handles the form submission
           *
           * @return the handler function
           */          
          getHandler : function() {
              var obj = this;
            
              var handler = function(form) {            
                  $.ajax({
                      url: obj.url,
                      type: 'POST',
                      data: obj.getFormData(),
                      async: true,
                      cache: false,
                      dataType: "xml",
               
                      success: function(data){
                          var outcome, other_err = false, errors = {};                        
                  
                          $(data).find(obj.type).each(function() {
                              outcome = $(this).attr('success');   
                              return false;             
                          });
                
                          if( outcome == 'false' ) {
                              $(data).find('validationErrors > field').each(function() {
                                  var code  = $(this).attr('errorCode');
                                  
                                  //Could be that the fields ids don't use "." as the word separator
                                  if( $('#' + $(this).attr('name')).length == 0 ) {
                                      var field = $(this).attr('name').replace('.', '_'); 
                                  } else {
                                      var field = $(this).attr('name'); 
                                  }
                                
                                  switch( code ) {                            
                                      case 'MISSING': 
                                      case 'INVALID_FORMAT':
                                      case 'MISMATCH':
                                      case 'TOO_SMALL':
                                      case 'TOO_BIG':
                                          //One error per field
                                          if( !errors[field] ) {
                                              errors[field] = obj.messages[code][field];
                                          }  
                                          break;
                                      case 'WRONG_OLD_PASSWORD': errors[field] = "The current password is not correct";
                                                                 break;    
                                      case "ALREADY_IN_USE":
                                         errors[field] = "The username/email is already in use by another user of the same single sign on group";
                                         break;
                                      case "INVALID_FORMAT":
                                         errors[field]= "The field does not comply with the allowed format";
                                         break;
                                      default: other_err = true;
                                  }                                                   
                              });
                              $.data(form, 'validator').showErrors(validatorFactory.processMessages(errors));
                    
                              if( other_err ) {
                                  alert('Some unexpected error occured, please try again. We are sorry for inconvinience');
                              }
                          } else {
                              if( obj.success ) {
                                  obj.success();
                              } else {
                                  $('#process-success').remove();
                                  $(form).before('<p id="process-success">Your data has been succesfully submitted</p>');
                              }
                          }
                      }
                  });        
              }
          
              return handler;
          }
      },
    
      /**
       * Return the submitHandler object
       *
       * @param string url - The url to which the data has to be submitted
       * @param string type - The type of the form (feedbackForm, updatedetails, ecc)
       * @param mixed fields - The fields whose values has to be submitted
       * @param Function success_fn - The function to call when the submit is successful
       * @return the submitHandler object
       */
      getSubmitHandler : function(url, type, fields, success_fn) {
            this.submitHandler.url = url;            
            this.submitHandler.fields = fields;
            
            if( type ) {
                this.submitHandler.type = type;
            }
        
            if( success_fn ) {
                this.submitHandler.success = success_fn;
            }

            return this.submitHandler;
        },
        
      
      /**
       * Instantiates and return the validator object
       *
       * @param string id - The css ID of the form to validate
       * @param json rules - The rules to apply to the form fields
       * @param json messages - The messages to display in case of errors  
       * @param Function submitHandler - The function to call when submitting the form
       * @param otherOptions - object for aditional validate parameters
       * @return the validator object
       */    
      getValidator: function(id, rules, messages, submitHandler, otherOptions) {                  
          var options = {
              rules : rules,
              messages : this.processMessages(messages),
              errorPlacement : this.errorPlacement,
              success: this.success,
              submitHandler : submitHandler
          }
              
          options.extend = $.fn.extend;
          options.extend(( this.otherOptions || {} ));
          options.extend(( otherOptions || {} ));
          
          //Implement the live validation on all the input fields marked with the relative "trigger" class
          $(id + ' input.validate-live').each(function() {
              $(this).change(function() {
                  if( $(this).valid() ) {
                      $(this).parent().addClass('valid').removeClass('error');
                  } else {
                      $(this).parent().addClass('error').removeClass('valid');
                  }
      
                  $(id + " label.error[for='" + $(this).attr('id') + "']").click(function(event) {
                      event.preventDefault();  
                  });
              });
          });       
        
          return $(id).validate(options);  
      },     
    
      /**
       * Sets the position of the error messages inside the form markup    
       */      
      errorPlacement: function(error, element) { 
          $(error).appendTo(element.parent().addClass('error'));
      },
    
      /**
       * Other validate options
       */
      otherOptions: {
        
      },
      
      /**
       * Add html markup to the error message so that they can be styled via css and add the messages to the submitHandler object
       *  It can be called recursively by adding a second parameter which is the  name of the field whose messages in the argument "messages" are for
       *
       * @param json messages - The error messages
       * @return the list of messages with the additional markup  
       */  
      processMessages: function(messages) {              
          var obj = this, aux = {}, parent_field = arguments[1];
          
          $.each(messages, function(key, val) {
              if( typeof val == 'object' ) {
                  aux[key] = obj.processMessages(val, key);
              } else { 
                  aux[key] = '<div class="message">' + val + '</div>';
                  
                  //If we're inside a recursion...
                  if( parent_field ) {                  
                      switch( key ) {
                          case 'required'  : var msg_key = 'MISSING';
                                             break;
                          case 'email'     : var msg_key = 'INVALID_FORMAT'; 
                                             break;
                          case 'equalTo'   : var msg_key = 'MISMATCH';
                                             break;
                          case 'minlength' : var msg_key = 'TOO_SMALL';
                                             break;
                          case 'maxlength' : var msg_key = 'TOO_BIG';
                                             break;
                          default: var msg_key = 'CUSTOM';                       
                      }  
                    
                      obj.submitHandler.messages[msg_key][parent_field] = val;
                  } else {
                      obj.submitHandler.messages['MISSING'][key] = val;
                  }
              }
          });         
          
          return aux;
      },
    
      /**
       * Adds the desired markup to the form elements that pass validation
       */
      success: function(label) {
          // set &nbsp; as text for IE
          label.addClass("valid");
          label.parent().addClass('verified');
      }
  }
