
package de.ivu.elect.was.exchange.gebietsbaum.wahlberechtigte.vois;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import de.ivu.elect.business.datei.entity.CsvAnfuehrungszeichen;
import de.ivu.elect.business.datei.entity.CsvMaskierungszeichen;
import de.ivu.elect.business.datei.entity.CsvTrennzeichen;
import de.ivu.elect.business.datei.entity.CsvZeichensatz;
import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.exchange.control.CsvFileKonfiguration;
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.boundary.WahldurchfuehrungsgebietFactory;
import de.ivu.elect.business.gebietsbaum.entity.AnzahlWahlberechtigteImportContext;
import de.ivu.elect.business.gebietsbaum.entity.AnzahlWahlberechtigteExchangeObjekt;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.gebietsbaum.entity.GebietsartBezirksart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.exchange.CsvImportMapper;
import de.ivu.elect.exchange.csv.CsvMarshaller;
import de.ivu.elect.jee.exchange.Violations;
import de.ivu.elect.was.exchange.gebietsbaum.wahlberechtigte.AnzahlWahlberechtigteImportMapper;

public abstract class AbstractAnzahlWahlberechtigteMesoVoisCsvImportMapper
    implements
    AnzahlWahlberechtigteImportMapper,
    CsvImportMapper<AnzahlWahlberechtigteExchangeObjekt, AnzahlWahlberechtigteImportContext> {

  @Inject
  private transient CsvMarshaller csvMarshaller;

  @Inject
  private transient WahldurchfuehrungsgebietFactory wahldurchfuehrungsgebietFactory;

  public AbstractAnzahlWahlberechtigteMesoVoisCsvImportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(AnzahlWahlberechtigteImportContext context) {
    return isAcceptContext(context.getWahl());
  }

  protected abstract boolean isAcceptContext(Wahl wahl);

  @Override
  public FileFormat getFileFormat() {
    return new FileFormat(getFileFormatName(), getFileFormatType());
  }

  protected abstract String getFileFormatName();

  protected FileType getFileFormatType() {
    return FileType.CSV;
  }

  @Override
  public List<String> getCsvColumnHeaders(AnzahlWahlberechtigteImportContext context) {
    return csvMarshaller.extractHeader(AnzahlWahlberechtigteMesoVoisCsvDTO.class);
  }

  @Override
  public AnzahlWahlberechtigteExchangeObjekt deserialize(InputStream is, AnzahlWahlberechtigteImportContext context, FileKonfiguration fileKonfiguration) throws MappingException {
    List<AnzahlWahlberechtigteMesoVoisCsvDTO> dtos = deserialize(is, createCsvFileKonfiguration(fileKonfiguration));

    List<Wahldurchfuehrungsgebiet> gebiete = new ArrayList<>(dtos.size());

    for (AnzahlWahlberechtigteMesoVoisCsvDTO dto : dtos) {
      if (dto.hasGebietNummerStimmbezirk()) {
        Gebietsart gebietsart = new Gebietsart();
        gebietsart.setName(getWahldurchfuehrungsgebietGebietsartName());

        Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = createWahldurchfuehrungsgebiet();
        wahldurchfuehrungsgebiet.setNummer(dto.getGebietNummer());
        wahldurchfuehrungsgebiet.setName(dto.getGebietName());
        wahldurchfuehrungsgebiet.setGebietsart(gebietsart);

        wahldurchfuehrungsgebiet.setAnzahlWahlberechtigteOhneWahlschein(dto.getAnzahlWahlberechtigteOhneWahlschein());
        wahldurchfuehrungsgebiet.setAnzahlWahlberechtigteMitWahlschein(dto.getAnzahlWahlberechtigteMitWahlschein());
        wahldurchfuehrungsgebiet.setAnzahlWahlberechtigteNichtImWaehlerverzeichnis(dto.getAnzahlWahlberechtigteNichtImWaehlerverzeichnis());

        gebiete.add(wahldurchfuehrungsgebiet);
      }
    }

    return new AnzahlWahlberechtigteExchangeObjekt(gebiete);
  }

  protected List<AnzahlWahlberechtigteMesoVoisCsvDTO> deserialize(InputStream is, FileKonfiguration fileKonfiguration) {
    return csvMarshaller.deserialize(AnzahlWahlberechtigteMesoVoisCsvDTO.class, is, fileKonfiguration);
  }

  @Override
  public Violations validateInputFormat(InputStream is, AnzahlWahlberechtigteImportContext context, FileKonfiguration fileKonfiguration) {
    return new Violations();
  }

  protected String getWahldurchfuehrungsgebietGebietsartName() {
    return GebietsartBezirksart.STIMMBEZIRK.name();
  }

  protected Wahldurchfuehrungsgebiet createWahldurchfuehrungsgebiet() {
    return wahldurchfuehrungsgebietFactory.create();
  }

  private CsvFileKonfiguration createCsvFileKonfiguration(FileKonfiguration fileKonfiguration) {
    // In TXT-Datei...
    // 1. Wahl Europaparlament;
    // Wahlbezirk;GES;STR;STB;MSP;OSP;
    long anzahlKopfzeilenDefault = 2;
    long anzahlKopfzeilen;

    CsvZeichensatz csvZeichensatz;
    CsvTrennzeichen csvTrennzeichen;
    CsvAnfuehrungszeichen csvAnfuehrungszeichen;
    CsvMaskierungszeichen csvMaskierungszeichen;

    if (fileKonfiguration instanceof CsvFileKonfiguration) {
      CsvFileKonfiguration csvFileKonfiguration = (CsvFileKonfiguration) fileKonfiguration;

      anzahlKopfzeilen = csvFileKonfiguration.getAnzahlKopfzeilen();

      csvZeichensatz = csvFileKonfiguration.getZeichensatz();
      csvTrennzeichen = csvFileKonfiguration.getTrennzeichen();
      csvAnfuehrungszeichen = csvFileKonfiguration.getAnfuehrungszeichen();
      csvMaskierungszeichen = csvFileKonfiguration.getMaskierungszeichen();
    } else {
      anzahlKopfzeilen = anzahlKopfzeilenDefault;

      csvZeichensatz = CsvZeichensatz.UTF_8;
      csvTrennzeichen = CsvTrennzeichen.SEMIKOLON;
      csvAnfuehrungszeichen = CsvAnfuehrungszeichen.DOPPELT;
      csvMaskierungszeichen = CsvMaskierungszeichen.BACKSLASH;
    }

    return new CsvFileKonfiguration() {

      @Override
      public FileFormat getFileFormat() {
        return getFileFormat();
      }

      @Override
      public Boolean isWithHeader() {
        return getAnzahlKopfzeilen() > 0;
      }

      @Override
      public Long getAnzahlKopfzeilen() {
        return anzahlKopfzeilen;
      }

      @Override
      public Boolean isNutzeTrennzeichenNachLetztemFeld() {
        return true;
      }

      @Override
      public CsvZeichensatz getZeichensatz() {
        return csvZeichensatz;
      }

      @Override
      public CsvTrennzeichen getTrennzeichen() {
        return csvTrennzeichen;
      }

      @Override
      public CsvAnfuehrungszeichen getAnfuehrungszeichen() {
        return csvAnfuehrungszeichen;
      }

      @Override
      public CsvMaskierungszeichen getMaskierungszeichen() {
        return csvMaskierungszeichen;
      }
    };
  }
}
