
package de.ivu.elect.exchange;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.datei.entity.Datei;
import de.ivu.elect.business.exchange.control.Exchange;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.exchange.control.FileKonfiguration;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;

@RequestScoped // ELECT-6404
public abstract class AbstractExchange<C, M extends ExchangeMapper<C>> implements Exchange<C> {

  private static final Logger LOG = LoggerFactory.getLogger(AbstractExchange.class);

  @Inject
  private transient Messages messages;

  public AbstractExchange() {
    super();
  }

  @Override
  public void addProperties(FormBuilder formBuilder, @Nullable FileFormat fileFormat, C context, @Nullable Datei datei) {
    if (formBuilder != null && context != null) {
      boolean fileFormatSupported = fileFormat != null && getSupportedFileFormats(context).contains(fileFormat);

      if (fileFormatSupported) {
        getMapperForFileTypeAndContext(fileFormat, context).addProperties(formBuilder, context, datei);
      }
    }
  }

  protected abstract Iterable< ? extends M> getAllSupportedMapper();

  @Override
  public List<FileFormat> getSupportedFileFormats(C context) {
    return extractFileTypes(getSupportedMapperForContext(context));
  }

  protected List<M> getSupportedMapperForContext(C context) {
    List<M> result = new ArrayList<>();

    for (M mapper : getAllSupportedMapper()) {
      try {
        if (mapper.isAcceptContext(context)) {
          result.add(mapper);
        }
      } catch (Exception e) {
        LOG.warn("Fehler in Mapper: " + mapper + ", " + e.getMessage(), e);
      }
    }

    return result;
  }

  protected M getMapperForFileTypeAndContext(FileKonfiguration fileKonfiguration, C context) {
    return getMapperForFileTypeAndContext(fileKonfiguration.getFileFormat(), context);
  }

  protected M getMapperForFileTypeAndContext(FileFormat fileFormat, C context) {
    List<M> mappersSupported = getSupportedMapperForContext(context);

    List<M> result = mappersSupported.stream() //
        .filter(mapper -> fileFormat.equals(mapper.getFileFormat())) //
        .collect(Collectors.toList());

    if (result.isEmpty()) {
      throw ExchangeException.newFileTypeNotSupportedException(fileFormat, mappersSupported);
    }

    if (result.size() > 1) {
      throw ExchangeException.newMapperAmbiguousException(fileFormat, result);
    }

    return result.iterator().next();
  }

  private List<FileFormat> extractFileTypes(List<M> mappers) {
    return mappers.stream().map(ExchangeMapper::getFileFormat).distinct().collect(Collectors.toList());
  }

  protected String getMessage(String msgKey, Object... params) {
    return messages.getMessageForMessageKey(msgKey, params);
  }
}
