
package de.ivu.elect.was.exchange.wahl;

import static java.util.stream.Collectors.toList;

import java.io.IOException;
import java.io.OutputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.List;
import java.util.zip.ZipOutputStream;

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

import de.ivu.elect.EmlExportMapper;
import de.ivu.elect.EmlExportMapperHelper;
import de.ivu.elect.business.datei.entity.Datei;
import de.ivu.elect.business.datei.entity.FileType;
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.entity.AbstractGebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.security.boundary.EmlSignKeyService;
import de.ivu.elect.business.wahl.control.WahlExportContext;
import de.ivu.elect.business.wahl.control.WahlExportObject;
import de.ivu.elect.business.wahl.control.Wahldaten;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.nl.eml.EmlWrapper;
import de.ivu.elect.nl.x509.NlX509Metadata;
import de.ivu.elect.util.FileUtil;
import de.ivu.elect.wus.exchange.wahl.WahlExportMapper;

public class Eml110aZipWahlExportMapper implements WahlExportMapper, EmlExportMapper {

  public static final String FILE_FORMAT = "eml.110a.file.format";

  @Inject
  private transient Eml110Mapper eml110Mapper;

  @Inject
  private transient EmlExportMapperHelper emlExportMapperHelper;

  @Inject
  private transient EmlSignKeyService emlSignKeyService;

  @Inject
  private transient Messages messages;

  public Eml110aZipWahlExportMapper() {
    super();
  }

  @Override
  public void serialize(WahlExportObject object, OutputStream os, WahlExportContext context, FileKonfiguration fileKonfiguration) throws MappingException {
    Wahldaten<Wahl, Gebiet> wahldaten = object.getWahldaten();

    Wahl wahl = wahldaten.getWahl();
    List<Gebiet> wahlgebiete = bestimmeWahlgebiete(wahldaten);

    try (ZipOutputStream zos = new ZipOutputStream(os)) {
      PrivateKey privateKey = retrievePrivateKey(wahl, context, emlSignKeyService);
      PublicKey publicKey = retrievePublicKey(wahl, context, emlSignKeyService);
      NlX509Metadata nlX509Metadata = retrieveNlX509Metadata(wahl, context, emlSignKeyService);

      for (Gebiet gebiet : wahlgebiete) {
        EmlWrapper emlWrapper = eml110Mapper.mappe(wahldaten, gebiet);

        emlExportMapperHelper.writeEml(emlWrapper, zos, getFileName(gebiet, wahl), gebiet, context, privateKey, publicKey, nlX509Metadata, true /* ELECT-11335 */);
      }
      zos.finish();
    } catch (IOException e) {
      throw new MappingException(e.getMessage(), e);
    }
  }

  protected String getFileName(Gebiet gebiet, Wahl wahl) {
    String wahlartKennzeichen = wahl.getWahlart().getKennzeichen();
    int wahljahr = wahl.getWahljahr();

    if (NlWahlart.TWEEDE_KAMER.equalsWahlart(wahl) || NlWahlart.EUROPEES_PARLEMENT.equalsWahlart(wahl) || NlWahlart.EERSTE_KAMER.equalsWahlart(wahl)) {
      return "Verkiezingsdefinitie_" + wahlartKennzeichen + wahljahr + EML_FILE_EXTENSION;
    }

    return "Verkiezingsdefinitie_" + wahlartKennzeichen + wahljahr + "_" + FileUtil.normalizeZipEntryNamePreserveCase(gebiet.getName()) + EML_FILE_EXTENSION;
  }

  public List<Gebiet> bestimmeWahlgebiete(Wahldaten<Wahl, Gebiet> wahldaten) {
    return wahldaten.getGebiete().stream().filter(AbstractGebiet::isWahlgebiet).collect(toList());
  }

  @Override
  public FileFormat getFileFormat() {
    return new FileFormat(FILE_FORMAT, FileType.ZIP);
  }

  @Override
  public boolean isAcceptContext(WahlExportContext context) {
    return context.getWahl() != null;
  }

  @Override
  public boolean isSignEml(Wahl wahl) {
    return false; // nicht notwendig https://confluence.ivu.de/pages/viewpage.action?spaceKey=VAPP&title=EML-Import+validation
  }

  @Override
  public void addProperties(FormBuilder formBuilder, WahlExportContext context, @Nullable Datei datei) {
    addSignProperties(context.getWahl(), formBuilder, context, messages);
  }
}
