(function($) { 

formBuilder = function() {
  this.init();
}

$.extend(formBuilder.prototype, {
  /*
   * Version Number.
   *
   * @alias FormBuilder.version
   * @property {String}
   */
  version: '0.1',

  options: {
    fade_out_ms: 5000
  },

  validators: {},
  
  errors_message: {
    'separator': '<br />',
    'email': '{label} is not formatted as an email',
    'integer': '{label} has to be an integer',
    'checked': '{label} has to be checked',
    'filled': '{label} is required',
    'equal_to': '{label1} is not equal to {label2}'
  },

  regex_library: {
    'integer': /^-?\d+$/,
    'email': /^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i
  },
  
  init: function() {
    this.setDefaultValidators();
    this.activateFlash();
  },

  run: function() {
    var self = this;
    
    // Generic form builder validtor (CSV)
    $('.form_fb').each(function(i){
      
      // Form id
      var id = $(this).attr('id');

      // Get validations JSON string
      var json = eval('(' + $("input[id='"+ id +"_csv']").val() + ')');

      // On submit click
      $("form").submit(function(){
        // Init flash errors and add header sentence
        var flash = new Array();

        // Loop on fields
        if (json == null || json.validations == null)
        {
          return true;
        }
        $.each(json.validations, function(key, value){
          var field = value.field;
          var label = value.label;
          var validations = value.validations.split('|');
          var find_error = false;
          var field_value = '';

          // Get value from form element
          if ($("input[id='"+ id +"_"+ field +"']").length > 0) {
            field_value = $("input[id='"+ id +"_"+ field +"']").val();
          }else if ($("textarea[id='"+ id +"_"+ field +"']").length > 0) {
            field_value = $("textarea[id='"+ id +"_"+ field +"']").val();
          }else if ($("select[id='"+ id +"_"+ field +"']").length > 0) {
            field_value = $("select[id='"+ id +"_"+ field +"']").val();
          }

          // Loop on validations
          $.each(validations, function(key, validation){
             if (find_error) return;

             switch (validation){
               case 'email':
                 if (!self.regex_library.email.test(field_value)) {
                   flash.push(self.errors_message.email.replace('{label}', label));
                   find_error = true;
                 }
                 break;
               case 'filled':
                 if (!Boolean(field_value)) {
                   flash.push(self.errors_message.filled.replace('{label}', label));
                   find_error = true;
                 }
                 break;
               case 'integer':
                 if (!self.regex_library.integer.test(field_value)) {
                   flash.push(self.errors_message.integer.replace('{label}', label));
                   find_error = true;
                 }
                 break;
               case 'checked':
                 $('#'+ field).find('input').each(function(){
                   if ($(this).attr('checked')) {
                     field_value = $(this).val();
                   }
                 });
                 if (!Boolean(field_value)) {
                   flash.push(self.errors_message.checked.replace('{label}', label));
                   find_error = true;
                 }
                 break;
             }
          });
        });

        // Loop on validators
        $.each(json.validators, function(key, value){
          var func = self.validators[value.alias];
          var params = value.params;

          if (eval('typeof(' + func + ')') == 'function') {
            var message = func(id, params);
            if (Boolean(message))
              flash.push(message);
          } else {
            // It's not a function'
          }
        });
        
        // Loop on fields which has to match an other one
        if (flash.length == 0) {
          $.each(json.equals, function(key, value){
            if ($('#'+ id +"_"+ value['field']).val() != $('#'+ id +'_'+ value['field_to_match']).val())
              if (value['field'] == 'password') 
                flash.push("Passwords do not match");              
              else
                flash.push(self.errors_message.equal_to.replace('{label1}', value['field']).replace('{label2}', value['field_to_match']));
          });
        }

        // Display errors if there is more than 0
        if (flash.length > 0) {
          $('#'+ json.flash_id +' .flash_error').html('').html('<p>' + flash.join(self.errors_message.separator) + '</p>');
          self.onError(json.flash_id);
          return false;
        }
      });

      // Add more fields on multi field
      $(this).find('.text_field_multi_fb').each(function(){
        $(this).keydown(function(){
          return false;
        });
        $(this).click(function(){
          group = $(this).parent();
          elements_number = parseInt(group.attr('title'));
          clone = group.prev().clone();
          clone.val('').attr('id', clone.attr('id') +'_'+ elements_number);
          if (elements_number > 1) {
            $(this).before(clone);
            group.attr('title', elements_number - 1);
          }
        });
      });
    });
  },
  
  validator: function(name, func) {
    if (typeof(func) == 'function')
      this.validators[name] = func;
  },

  setDefaultValidators: function() {
    this.validator('one_of_two_fields_required', oneOfTwoFieldsRequired);
    this.validator('min_max_length', minMaxLengtValidator);
  },
  
  onError: function(flash_id){
    // Form error fade in event
    $('#'+ flash_id +' .flash_error').fadeIn();
  },

  activateFlash: function() {
    var self = this;
    
    // Form notice fade in event
    $('.flash_notice').each(function(){
      var el = $(this);
      if (Boolean(el.find('p').text())) {
        el.fadeIn();
        setTimeout(function() { el.fadeOut(); }, self.options.fade_out_ms);
      }
    });

    // Form error fade in event
    $('.flash_error').each(function(){
      var el = $(this);
      p_element = el.find('p');
      if (Boolean($.trim(p_element.text()))) {
        el.fadeIn();
      }
    });
  }
});

/*
 * Default validators library
 */

function oneOfTwoFieldsRequired(form_id, params) {
  var params = params.split('|');
  
  if (!Boolean($("input[id='"+ form_id +"_"+ params[0] +"']").val()) && !Boolean($("input[id='"+ form_id +"_"+ params[1] +"']").val()))
    return params[2];
  else
    return '';
}

function minMaxLengtValidator(form_id, params) {
    params = params.split('|');
    
    var val = $('#' + form_id + '_' + params[0]).val();
    if (params[1] != 'null' && val.length < params[1]) return params[3] + ' should be at least ' + params[1] + ' characters';
    if (params[2] != 'null' && val.length > params[2]) return params[3] + ' should no be longer then ' + params[2] + ' characters';
    return '';
}

})(jQuery);