// jQuery form validation

var Validators = {
  presenceOf:function(input){
    return !/^\s*$/.test($(input).val());
  },
  formatOf:function(input,opts){
    // Options:
    // - format:regex (e.g., /^[0-9]+$/) (required)
    if ($.trim($(input).val()) === ''){ return true; }
    return $(input).val().match(opts.format) === null ? false : true;
  },
  lengthOf:function(input,opts){
    // Options:
    // - minimum:integer
    // - maximum:integer
    // - is:integer

    // Obvious constraints (e.g., min < max) are intentionally not tested here
    // to save processing time.
    var len = $(input).val().length;
    if(!opts.is&&!opts.min&&!opts.max){ return true; }
    if(opts.is&&len!=opts.is || opts.min&&len<opts.min || opts.max&&len>opts.max){ return false; }
    return true;
  },
  acceptanceOf:function(input){
    return $(input)[0].checked;
  },
  confirmationOf:function(confirmationInput){
    // Usage:
    // 1. Add HTML: <input type="password" name="user[password]" />
    //              <input type="password" name="user[password_confirmation]" />
    //                <!-- Names should match except for suffix "_confirmation" -->
    //                // NOTE: Contrary to what you may expect, the validator
    //                // should be applied to the confirmation input, not the
    //                // main input.
    var confirmation = $(confirmationInput);
    confirmationName = confirmation.attr('name');
    var input = confirmation.parents('form').find('input[name="'+confirmationName.replace(/_confirmation/,'')+'"]');
    return input.val() == confirmation.val();
  }
};

var Formats = {
  numeric:/^[0-9]+$/,
  alphanumericWithUnderscores:/^[a-z0-9_]+$/i,
  email:/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
};

function ValidatedField(input,validators){
  this.input = $(input);
  this.validators = validators;
  this.valid = null;
  this.error = this.input.next('span.error');
  if (this.error.length < 1){
    this.error = $('<span class="error" style="display:none;"></span>');
    this.input.parent().append(this.error);
  }
  var _this = this;
  this.input.blur(function(){
    return _this.validate();
  });
}

ValidatedField.prototype.addValidation = function(validator,opts){
  this.validators.push({validator:Validators[validator], opts:opts});
};
ValidatedField.prototype.validate = function(){
  var i;
  var len = this.validators.length;
  var results = [];
  for (i=0;i<len;i++){
    results[i] = this.validators[i].validator(this.input,this.validators[i].opts);
  }
  var valid = true;
  var errorMessage = '';
  for (i=0;i<len;i++){
    if (!results[i]){
      errorMessage = errorMessage === '' ? this.validators[i].opts.message : errorMessage + '<br />' + this.validators[i].opts.message;
      valid = false;
    }
  }
  this.valid = valid;
  this.updateWarning(errorMessage);
  return this.valid;
};
ValidatedField.prototype.updateWarning = function(message){
  if (message!=='') { this.error.html(message); }
  if (this.valid){ this.error.fadeOut(); }
  else { this.error.fadeIn(); }
};

function ValidatedForm(formSelector){
  this.form = $(formSelector);
  this.submit = this.form.find('div.submit input');
  this.inputValidations={};
  var _this = this;
  this.form.submit(function(){
    _this.submit.attr("disabled","disabled").addClass("disabled");
    var res = _this.validateAll();
    if(!res){ _this.submit.removeAttr("disabled").removeClass("disabled"); }
    return res;
  });
}

ValidatedForm.prototype.validates = function(validator, selector, options){
  var input = $(selector);
  if(!this.inputValidations[input[0].id]){
    this.inputValidations[input[0].id] = new ValidatedField(selector,[]);
  }
  this.inputValidations[input[0].id].addValidation(validator,options);
};
ValidatedForm.prototype.validateAll = function(){
  var noErrors = true;
  $.each(this.inputValidations,function(){
    if(!this.validate()){
      noErrors = false;
    }
  });
  return noErrors;
};