
package de.ivu.elect.core.exchange.stimmen.csv;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;
import javax.inject.Inject;

import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportContext;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportObject;
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.GebietByNummerComparator;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.exchange.csv.CsvDescriptor;
import de.ivu.elect.exchange.csv.CsvMarshaller;
import de.ivu.elect.was.exchange.ergebnis.ErgebnisExportMapper;

public abstract class AbstractStimmenCsvExportMapper<T extends AbstractStimmenCsvDTO> extends AbstractStimmenMapper implements ErgebnisExportMapper {

  @Inject
  private transient CsvMarshaller csvMarshaller;

  public AbstractStimmenCsvExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(ErgebnisExportContext context) {
    return true;
  }

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

  protected abstract String getFileFormatName();

  protected CsvMarshaller getCsvMarshaller() {
    return csvMarshaller;
  }

  protected abstract Class<T> getStimmenCsvDTOClass();

  @Override
  public void serialize(ErgebnisExportObject exportObject, OutputStream os, ErgebnisExportContext context, FileKonfiguration fileKonfiguration) throws MappingException {
    List<T> dtos = mappeEntityInternToExtern(exportObject, context);

    getCsvMarshaller().serialize(getStimmenCsvDTOClass(), dtos, os, createCsvDescriptor(fileKonfiguration, dtos));
  }

  private CsvDescriptor createCsvDescriptor(FileKonfiguration fileKonfiguration, List< ? extends T> objects) {
    Class< ? > subDtoClass = null;
    int maxAnzahlSubDTOClass = 0;
    for (T object : objects) {
      subDtoClass = object.getSubDTOClass();
      if (maxAnzahlSubDTOClass < object.getAnzahlSubDTO()) {
        maxAnzahlSubDTOClass = object.getAnzahlSubDTO();
      }
    }
    return createCsvDescriptor(fileKonfiguration, subDtoClass, maxAnzahlSubDTOClass);
  }

  public CsvDescriptor createCsvDescriptor(FileKonfiguration fileKonfiguration, @Nullable Class< ? > subDtoClass, int maxAnzahlSubDTOClass) {
    List<String> header = new ArrayList<>();
    header.addAll(CsvDescriptor.createHeaderForClass(getStimmenCsvDTOClass()));
    if (subDtoClass != null) {
      List<String> subDtoClassHeader = CsvDescriptor.createHeaderForClass(subDtoClass);
      for (int i = 0; i < maxAnzahlSubDTOClass; i++) {
        header.addAll(subDtoClassHeader);
      }
    }

    CsvDescriptor csvDescriptor = CsvDescriptor.withHeader(fileKonfiguration, header);
    // ELECTDD-168: Trennzeichen nach letzter Spalte wird erwartet
    DefaultCsvFileKonfiguration defaultCsvFileKonfiguration = (DefaultCsvFileKonfiguration) csvDescriptor.getCsvFileKonfiguration();
    defaultCsvFileKonfiguration.setNutzeTrennzeichenNachLetztemFeld(true);

    return csvDescriptor;
  }

  protected abstract List<T> mappeEntityInternToExtern(ErgebnisExportObject object, ErgebnisExportContext context);

  protected Gebiet[] getSortedGebiete(Map<Gebiet, ? > map) {
    Gebiet[] result = map.keySet().toArray(new Gebiet[0]);
    Arrays.sort(result, GebietByNummerComparator.ASCENDING);

    return result;
  }
}
