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

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

import javax.inject.Inject;

import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.exchange.control.DefaultCsvFileKonfiguration;
import de.ivu.elect.business.exchange.control.FileFormat;
import de.ivu.elect.business.exchange.control.FileKonfiguration;
import de.ivu.elect.business.exchange.control.MappingException;
import de.ivu.elect.business.gebietsbaum.control.GebietByBreadthFirstComparator;
import de.ivu.elect.business.gebietsbaum.control.Gebietsbaum;
import de.ivu.elect.business.gebietsbaum.control.GebietsbaumExchangeContext;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.exchange.BaseDTO;
import de.ivu.elect.exchange.csv.CsvDescriptor;
import de.ivu.elect.exchange.csv.CsvMarshaller;
import de.ivu.elect.exchange.gebietsbaum.GebietsbaumExportMapper;

public abstract class AbstractGebietsbaumCsvExportMapper<T extends BaseDTO> implements GebietsbaumExportMapper {

  @Inject
  private transient CsvMarshaller csvMarshaller;

  public AbstractGebietsbaumCsvExportMapper() {
    super();
  }

  @Override
  public FileFormat getFileFormat() {
    return new FileFormat(getFileFormatName(), FileType.CSV);
  }

  protected abstract String getFileFormatName();

  protected boolean isExportHeader() {
    return true;
  }

  protected boolean isNutzeTrennzeichenNachLetztemFeld() {
    return false;
  }

  @Override
  public void serialize(Gebietsbaum gebietsbaum, OutputStream os, GebietsbaumExchangeContext context, FileKonfiguration fileKonfiguration) throws MappingException {
    CsvDescriptor csvDescriptor = CsvDescriptor.forFileKonfiguration(fileKonfiguration);

    if (!isExportHeader()) {
      csvDescriptor.setWithHeader(false);
    }

    if (isNutzeTrennzeichenNachLetztemFeld()) {
      DefaultCsvFileKonfiguration defaultCsvFileKonfiguration = (DefaultCsvFileKonfiguration) csvDescriptor.getCsvFileKonfiguration();
      defaultCsvFileKonfiguration.setNutzeTrennzeichenNachLetztemFeld(true);
    }

    List<T> dtos = createDtos(gebietsbaum.getGebiete(), context);

    if (!dtos.isEmpty()) {
      csvMarshaller.serialize((Class<T>) dtos.get(0).getClass(), dtos, os, csvDescriptor);
    }
  }

  protected List<T> createDtos(List<Gebiet> gebiete, GebietsbaumExchangeContext context) {
    gebiete.sort(new GebietByBreadthFirstComparator());

    return gebiete.stream().filter(gebiet -> isRelevantGebiet(gebiet, context)).map(gebiet -> createDto(gebiet, context))
        .collect(Collectors.toCollection(() -> new ArrayList<>(gebiete.size())));
  }

  protected abstract boolean isRelevantGebiet(Gebiet gebiet, GebietsbaumExchangeContext context);

  protected abstract T createDto(Gebiet gebiet, GebietsbaumExchangeContext context);
}
