var ERROR_CLASS = 'error';
var ERROR_MESSAGE_CLASS = 'error-message';
var REQUIRED_CLASS = 'required';
var EMAIL_VALIDATION_CLASS = 'email';
var DIGITAL_VALIDATION_CLASS = 'digital';
var PHONE_VALIDATION_CLASS = 'phone';

/**
 * Mark required fields in the form by adding <span>*</span> at the end of the fields' label
 *
 * @param   event     jQuery event object
 */
function markRequiredFields(event) {
  $(event.target).find('.' + REQUIRED_CLASS).each(function(){
    id = $(this).attr('id');
    label = $(event.target).find('label[for="' + id + '"]');
    label.html(label.html() + '<span>*</span>');
  });
}

/**
 * Display the error message and highlight the field
 *
 * @param   field     jQuery object containing the field
 * @param   message   error message to be displayed
 */
function showError(field, message) {
  $(field).parent().append('<div class="' + ERROR_MESSAGE_CLASS + '">' + message + '</div>');
  $(field).addClass(ERROR_CLASS);
}

/**
 * Remove all previously found errors
 */
function resetErrors() {
  $('.' + ERROR_MESSAGE_CLASS).remove();
  $('.' + ERROR_CLASS).removeClass(ERROR_CLASS);
}

/**
 * Validate form fields. The following rules are supported:
 *  - field must be non-empty. Applied as a class of a field container (example: <p class='required'><input /></p>)
 *  - field must be a valid email. Applied as a class of a field itself (example: <p><input class='email' /></p>)
 *  - field must contain digits only. Applied as a class of a field itself (example: <p><input class='digital' /></p>)
 *  - field must be a valid phone number. Applied as a class of a field itself (example: <p><input class='phone' /></p>)
 *
 * @param   field   jQuery object containing the field that needs to be validated
 * @return  the amount of found errors
 */
function isFieldValid(field) {
  var errorsFound = 0;

  $(field).each(function(){
    // Find all required fields of specified type
    // 'Required' in this case means 'Must not be empty'
    if($(this).hasClass(REQUIRED_CLASS)) {
      if ($(this).val() == '') {          // If the field is empty
        showError(this, 'This field cannot be empty');
        errorsFound++;
      }
    }

    // If the field is not empty and marked as email
    if ($(this).hasClass(EMAIL_VALIDATION_CLASS)) {
      var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
      var email = $(this).val();
      if (email != '' && !reg.test(email)) {
        showError(this, 'This email address seems incorrect');
        errorsFound++;
      }
    }

    // If the field is not empty and marked as 'numbers only'
    if ($(this).hasClass(DIGITAL_VALIDATION_CLASS)) {
      n = $(this).val();
      if (n != '' && n != parseInt(n)) {
        showError(this, 'This field can only contain digits');
        errorsFound++;
      }
    }
    // If the field is not empty and marked as phone
    if ($(this).hasClass(PHONE_VALIDATION_CLASS)) {
      var reg = /^(1\s*[-\/\.]?)?(\((\d{3})\)|(\d{3}))\s*[-\/\.]?\s*(\d{3})\s*[-\/\.]?\s*(\d{4})\s*(([xX]|[eE][xX][tT])\.?\s*(\d+))*$/;
      var phone = $(this).val();
      if (phone != '' && !reg.test(phone)) {
        showError(this, 'This phone number seems incorrect');
        errorsFound++;
      }
    }
  })

  return errorsFound;
}

/**
 * Validate a form
 *
 * @param   form      jQuery object containing the form that needs to be validated
 * @return  if there is no errors on the form, false - otherwise
 */
function isFormValid(form) {
  var errorsFound = 0;

  errorsFound += isFieldValid(form.find('input'));
  errorsFound += isFieldValid(form.find('textarea'));
  errorsFound += isFieldValid(form.find('select'));

  return errorsFound == 0;
}

/**
 * Add validation to submit event of the form. Form needs to have 'validate' class as shown:
 * <form class="validate">
 */
$(document).ready(function(){
  $('.validate').live('formLoaded', markRequiredFields);
  $('.validate').trigger('formLoaded');

  $('form.validate').live('submit', function(){
    resetErrors();
    return isFormValid($(this));
  });
});

