
package de.ivu.elect.exchange.csv.converter;

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

import java.util.ArrayList;
import java.util.List;

import javax.faces.convert.ConverterException;

import org.jsefa.common.converter.ConversionException;
import org.jsefa.common.converter.SimpleTypeConverter;
import org.jsefa.common.converter.SimpleTypeConverterConfiguration;

import de.ivu.elect.business.exchange.boundary.ExchangeBooleanConverter;

/**
 * Dies ist ein angepasster Boolean-Converter mit folgenden Eigenschaften ...
 * <ul>
 * <li><code>null</code> und leerer String wird zu <code>false</code> konvertiert</li>
 * <li>Format unterstützt mehrere, Pipe-separierte (<code>|</code>) Aliasse für <code>true</code> und <code>false</code> , die als drittes bzw. viertes Element angegeben werden</li>
 * <li>Standard-Format lässt sich per <code>@CsvField(format = {"trueAlias", "falseAlias", "moreTrueAliases", "moreFalseAliases"})</code> überschreiben</li>
 * <li>Standard-Format lässt sich auch nur teilweise überschreiben</li>
 * </ul>
 */
public class ElectCsvBooleanConverter implements SimpleTypeConverter {

  private static final String ALIASES_SEPARATOR = "|";

  private static final String DEFAULT_TRUE_ALIASES = String.join(ALIASES_SEPARATOR, ExchangeBooleanConverter.DEFAULT_TRUE_ALIASES);

  private static final String DEFAULT_TRUE_ALIAS = "1";

  private static final String DEFAULT_FALSE_ALIASES = String.join(ALIASES_SEPARATOR, ExchangeBooleanConverter.DEFAULT_FALSE_ALIASES);

  private static final String DEFAULT_FALSE_ALIAS = "0";

  private static final String[] DEFAULT_FORMAT = {DEFAULT_TRUE_ALIAS, DEFAULT_FALSE_ALIAS, DEFAULT_TRUE_ALIASES, DEFAULT_FALSE_ALIASES};

  private final ExchangeBooleanConverter exchangeBooleanConverter;

  protected ElectCsvBooleanConverter(SimpleTypeConverterConfiguration configuration) {
    super();

    String[] format = getFormat(configuration);
    this.exchangeBooleanConverter = new ExchangeBooleanConverter(getAliases(format[0], format[2]), getAliases(format[1], format[3]));
  }

  @Override
  public Boolean fromString(String value) {
    return exchangeBooleanConverter.fromString(value);
  }

  @Override
  public String toString(Object value) {
    return exchangeBooleanConverter.toString(value);
  }

  public static ElectCsvBooleanConverter create(SimpleTypeConverterConfiguration configuration) {
    return new ElectCsvBooleanConverter(configuration);
  }

  protected String[] getFormat(SimpleTypeConverterConfiguration configuration) {
    String[] format = configuration.getFormat();
    String[] result = getDefaultFormat();

    if (format == null) {
      return result;
    }

    if (format.length == 1 || format.length == 3 || format.length > 4) {
      throw new ConverterException("The format for a BooleanConverter must be an array with 2 or 4 entries");
    }

    for (int i = 0; i < format.length; i++) {
      result[i] = format[i];
    }

    if (result[0].equals(result[1])) {
      throw new ConverterException("Invalid format for a BooleanConverter: " + result[0] + ", " + result[1]);
    }

    return result;
  }

  protected String[] getDefaultFormat() {
    return ElectCsvBooleanConverter.DEFAULT_FORMAT.clone();
  }

  private List<String> getAliases(String value, String aliases) {
    List<String> result = new ArrayList<>();

    result.add(value);

    for (String alias : splitByWholeSeparator(aliases, ALIASES_SEPARATOR)) {
      if (isNotBlank(alias) && !result.contains(alias)) {
        result.add(alias);
      }
    }

    return result;
  }
}
