
/**
 * Retourne le nombre d'éléments d'objet Javascript
 * @param obj {object} L'objet dont on veut connaître la taille
 * @returns {number} Le nombre d'éléments de l'objet
 */
function arraySize(obj) {
  var len = obj.length ? --obj.length : 0;
  for(var k in obj) {
    if(k != "in_array" && k != "length" && k != "indexOf") {
      len++;
    }
  }
  return len;
}

/**
 * Fonction de validation de formulaires avec javascript
 * @param form_id {string} attribut id du formulaire à tester
 * @param error_div_id {string} attribut id du div qui contiendra les erreurs
 * @param options {json} structure pour les options de validation du formulaire
 * @returns {bool} true si le formulaire est bien validé
 */
function validateForm(form_id, error_div_id, options) {

  var errorList = new Array();

  // On verifie les champs obligatoires
  for(index in options.mandatory) {
    var el = $('#' + form_id + ' [name="' + index + '"]');
    if(!$.trim(el.val())) {
      errorList[index] = options.mandatory[index];
    }
  }

  resetFieldErrors(form_id, options.mandatory, options.errorFieldClass, options.errorFieldDivId);
  errorList = testConditions(form_id, errorList, options.errorMessages, options.conditions);
  buildErrorMessages(form_id, error_div_id, errorList, options.errorDivClass, options.errorMessages);
  assignErrorToFields(form_id, error_div_id, errorList, options.errorFieldClass, options.errorFieldDivId);

  return (arraySize(errorList) <= 0);
}

/**
 * Teste les différentes conditions spécifiées
 */
function testConditions(form_id, error_list, error_messages, conditions) {
  for(i in conditions) {
    if(!isNaN(i)) {
      if(conditions[i].field != '') {
        // Condition sur type prédéfini
        var testResult = false;
        switch(conditions[i].type) {
          case 'string': testResult = testString(form_id, conditions[i]); break;
          case 'number': testResult = testNumber(form_id, conditions[i]); break;
          case 'shortFrenchDate': testResult = testShortDate(form_id, conditions[i], 'french'); break;
          case 'shortEnglishDate': testResult = testShortDate(form_id, conditions[i], 'english'); break;
          case 'compareFields': testResult = compareFields(form_id, conditions[i]); break;
          default: break;
        }
        if(!testResult) {
          error_list[conditions[i].field] = conditions[i].ifnot;
        }
      } else {
        // Condition par fonction personnalisée
        testResult = conditions[i]['function'](form_id, conditions);
        if(!testResult) {
          error_list[conditions[i].ifnot] = conditions[i].ifnot;
        }
      }
    }
  }
  return error_list;
}

/**
 * Teste une chaine de caractère en fonction d'un opérateur
 * et d'une opérande
 */
function testString(form_id, conditions) {
  switch(conditions.operator) {
    case '==':
      return (conditions.operand == $.trim($('#' + form_id + ' [name="' + conditions.field + '"]').val()));
    break;
    case '!=': case '<>':
      return (conditions.operand != $.trim($('#' + form_id + ' [name="' + conditions.field + '"]').val()));
    break;
  }
}

/**
 * Teste un nombre en fonction d'un opérateur
 * et d'une opérande
 */
function testNumber(form_id, conditions) {
  switch(conditions.operator) {
    case '==':
      return (conditions.operand == $('#' + form_id + ' [name="' + conditions.field + '"]').val());
    break;
    case '!=': case '<>':
      return (conditions.operand != $('#' + form_id + ' [name="' + conditions.field + '"]').val());
    break;
    case '>':
      return (conditions.operand > $('#' + form_id + ' [name="' + conditions.field + '"]').val());
    break;
    case '>=':
      return (conditions.operand >= $('#' + form_id + ' [name="' + conditions.field + '"]').val());
    break;
    case '<':
      return (conditions.operand < $('#' + form_id + ' [name="' + conditions.field + '"]').val());
    break;
    case '<=':
      return (conditions.operand <= $('#' + form_id + ' [name="' + conditions.field + '"]').val());
    break;
  }
}

/**
 * Teste une date courte en fonction d'un opérateur
 * et d'une opérande
 */
function testShortDate(form_id, conditions, locale) {
  var sep = '/';
  if(locale == 'english') {
    sep = '-';
  }
  var operand_array = conditions.operand.split(sep);
  var field_array = $('#' + form_id + ' [name="' + conditions.field + '"]').val().split(sep);

  if(locale == 'english') {
    operand_date = new Date();
    operand_date.setFullYear(operand_array[0], operand_array[1] - 1, operand_array[2]);
    var operand_timestamp = operand_date.getTime();
    field_date = new Date();
    field_date.setFullYear(field_array[0], field_array[1] - 1, field_array[2]);
    var field_timestamp = field_date.getTime();
  } else {
    operand_date = new Date();
    operand_date.setFullYear(operand_array[2], operand_array[1] - 1, operand_array[0]);
    var operand_timestamp = operand_date.getTime();
    field_date = new Date();
    field_date.setFullYear(field_array[2], field_array[1] - 1, field_array[0]);
    var field_timestamp = field_date.getTime();
  }

  switch(conditions.operator) {
    case '==': return (field_timestamp == operand_timestamp); break;
    case '!=': case '<>': return (field_timestamp != operand_timestamp); break;
    case '>':  return (field_timestamp > operand_timestamp); break;
    case '>=':  return (field_timestamp >= operand_timestamp); break;
    case '<':  return (field_timestamp < operand_timestamp); break;
    case '<=':  return (field_timestamp <= operand_timestamp); break;
  }
}

/**
 *
 */
function compareFields (form_id, conditions){
  var fieldsList = conditions.field;

  for(index in fieldsList) {
    if(!isNaN(index)) {
      for (next_index = fieldsList.length; next_index > index; next_index--){
        if(typeof(fieldsList[next_index])!='undefined'){
          switch(conditions.operator) {
            case '==': if ($.trim($('#' + fieldsList[index]).val()) == $.trim($('#' + fieldsList[next_index]).val())){return false;} break;
            case '!=': case '<>': if ($('#' +fieldsList[index]).val() != $('#' +fieldsList[next_index]).val()){return false;} break;
            case '>':  if ($('#' +fieldsList[index]).val() > $('#' +fieldsList[next_index]).val()){return false;} break;
            case '>=':  if ($('#' +fieldsList[index]).val() >= $('#' +fieldsList[next_index]).val()){return false;} break;
            case '<':  if ($('#' +fieldsList[index]).val() < $('#' +fieldsList[next_index]).val()){return false;} break;
            case '<=':  if ($('#' +fieldsList[index]).val() <= $('#' +fieldsList[next_index]).val()){return false;} break;
          }
        }
      }
    }
  }

  return true;
}

/**
 * Réinitialise les signaux d'erreurs des champs
 */
function resetFieldErrors(form_id, field_list, field_class, field_error_div_id) {
  for(index in field_list) {
    if(index != "in_array" && index != "length" && index != "indexOf") {
      $('#' + form_id + ' [name="' + index + '"]').removeClass(field_class);
      $('#' + index + field_error_div_id).removeClass(field_class);
    }
  }
}

/**
 * Assigne des signaux d'erreurs (ajout de classe css) aux champs pour les
 * mettre en évidence
 */
function assignErrorToFields(form_id, error_div_id, error_list, field_class, field_error_div_id) {
  for(index in error_list) {
    if(index != "in_array" && index != "length" && index != "indexOf") {
      $('#' + form_id + ' [name="' + index + '"]').addClass(field_class);
      $('#' + index + field_error_div_id).addClass(field_class);
    }
  }
}

/**
 * Construit les messages d'erreur dans un div spécifié
 * grâce à une liste d'erreurs
 */
function buildErrorMessages(form_id, error_div_id, error_list, div_class, error_messages) {
  var hasError = arraySize(error_list);
  if(hasError > 0) {
    $('#' + error_div_id).addClass(div_class);
    $('#' + error_div_id).html('<span class="ico-err">Erreur</span>');

    for(index in error_list) {
      if(index != "in_array" && index != "length" && index != "indexOf") {
        $('#' + error_div_id).append(error_messages[error_list[index]] + '<br />');
      }
    }
  } else {
    $('#' + error_div_id).removeClass(div_class);
    $('#' + error_div_id).html('');
  }
}
