
package de.ivu.elect.jee.faces;

import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.io.Serializable;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

import org.iban4j.IbanFormatException;
import org.iban4j.IbanUtilDE;
import org.iban4j.InvalidCheckDigitException;
import org.iban4j.UnsupportedCountryException;

import de.ivu.elect.jee.presentation.dynamicform.AbstractMaskProperty;

/**
 * https://github.com/arturmkrtchyan/iban4j
 */
@FacesValidator(IbanValidator.VALIDATOR_ID)
public class IbanValidator implements Validator, Serializable {

  private static final long serialVersionUID = 1L;

  public static final String VALIDATOR_ID = "ibanValidator";

  public static final IbanValidator INSTANCE = new IbanValidator();

  public static final String DE_IBAN_MASK = "aa99 9999 9999 9999 9999 99";

  public static final String DE_IBAN_MASK_SLOT_CHAR = AbstractMaskProperty.DEFAULT_MASK_SLOT_CHAR;

  private static final Converter DE_IBAN_MASK_CONVERTER = AbstractMaskProperty.createMaskConverter(DE_IBAN_MASK_SLOT_CHAR);

  public IbanValidator() {
    super();
  }

  @Override
  public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    String valueNormalized = normalize(value);

    if (isNotBlank(valueNormalized)) {
      try {
        IbanUtilDE.validate(valueNormalized);
      } catch (IbanFormatException | InvalidCheckDigitException | UnsupportedCountryException ex) {
        throw new ValidatorException(FacesMessageUtil.createErrorMessage(context, "iban.validation.failed", "iban.validation.failed.detail", ex.getMessage()));
      }
    }
  }

  public static String normalize(Object value) {
    if (value instanceof String) {
      String result = trimToEmpty((String) value);
      result = result.toUpperCase();
      result = result.replaceAll("\\s+", "");

      if (isNotBlank(result)) {
        // ELECTMUC-1780, dass an dieser Stelle normalisiert wird, da StringMaskDecoratorProperty#setValue erst nach dieser
        // Validierung aufgerufen wird! Beim Aufruf des Setters sollten dann eh alle Platzhalter durch einen Wert ersetzt sein...
        result = DE_IBAN_MASK_CONVERTER.getAsObject(null, null, result).toString();
      }

      return result;
    }

    return "";
  }
}
