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

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.inject.Inject;

import de.ivu.elect.EmlImportMapper;
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.stimmeingabe.boundary.ErgebniseingangDAO;
import de.ivu.elect.business.stimmeingabe.control.NlStimmeingabefehlerFactory;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeImportContext;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingabestufe;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.jee.exchange.AbstractViolation;
import de.ivu.elect.jee.exchange.Violations;

public class Eml510aBackupRestoreImportMapper extends AbstractStimmeingabeImportMapper implements EmlImportMapper {

  private static final long serialVersionUID = 1L;

  public static final String FILE_FORMAT = "eml.510.file.format.backup";

  @Inject
  private transient ErgebniseingangDAO ergebniseingangDAO;

  @Inject
  private transient NlStimmeingabefehlerFactory nlStimmeingabefehlerFactory;

  @Inject
  private transient Eml510StimmeingabeImportMapperHelper eml510StimmeingabeImportMapperHelper;

  @Inject
  private transient Eml510StimmeingabeImportMapper eml510StimmeingabeImportMapper;

  public Eml510aBackupRestoreImportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(StimmeingabeImportContext context) {
    return super.isAcceptContext(context) && eml510StimmeingabeImportMapper.isAcceptWahl(context.getWahldurchfuehrung());
  }

  @Override
  protected boolean isAcceptWahl(Wahldurchfuehrung wahldurchfuehrung) {
    // ELECT-11355 NlWahlart.isWasGemeinde(() -> wahldurchfuehrung.getWurzelgebiet(EntityMitWurzelgebietDAO.fromDao(gebietDAO)), currentCustomer .getCustomer())
    return wahldurchfuehrung != null && eml510StimmeingabeImportMapperHelper.isBackupRestoreImportZulaessig(this, wahldurchfuehrung) && !isErgebniseingangVorhanden(wahldurchfuehrung);
  }

  private boolean isErgebniseingangVorhanden(Wahldurchfuehrung wahldurchfuehrung) {
    return ergebniseingangDAO.findByCountWahl(wahldurchfuehrung) > 0;
  }

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

  @Override
  public List<Ergebniseingang> deserialize(InputStream is, StimmeingabeImportContext context, FileKonfiguration fileKonfiguration) throws MappingException {
    List<Ergebniseingang> result = new ArrayList<>();

    // Backups werden immer als "Endstufe" eingespielt
    context.put(Eml510StimmeingabeImportMapper.EINGANGSTUFE_FORCIEREN, Ergebniseingabestufe.ENDSTUFE);

    try (ZipInputStream zisOuter = new ZipInputStream(is) {

      @Override
      public void close() throws IOException {
        // ...
      }
    }) {
      ZipEntry entryOuter;

      while ((entryOuter = zisOuter.getNextEntry()) != null) {
        try (ZipInputStream zisInner = new ZipInputStream(zisOuter) {

          @Override
          public void close() throws IOException {
            // ...
          }
        }) {
          ZipEntry entryInner;

          while ((entryInner = zisInner.getNextEntry()) != null) {
            if (entryInner.getName().toLowerCase().endsWith("xml")) {
              result.addAll(eml510StimmeingabeImportMapper.deserialize(zisInner, context, fileKonfiguration));
            }
          }
        }
      }
    } catch (IOException e) {
      throw new MappingException(e.getMessage(), e);
    }

    for (Ergebniseingang ergebniseingang : result) {
      nlStimmeingabefehlerFactory.createStimmeingabefehlerEndstufeSpezifischStimmeingabeNachBulkImportPruefen(ergebniseingang); // ELECT-10371
    }

    return result;
  }

  @Override
  public Violations validateInputFormat(InputStream is, StimmeingabeImportContext context, FileKonfiguration fileKonfiguration) {
    Violations result = new Violations();
    boolean found = false;

    try (ZipInputStream zisOuter = new ZipInputStream(is) {

      @Override
      public void close() throws IOException {
        // ...
      }
    }) {
      ZipEntry entryOuter;

      while ((entryOuter = zisOuter.getNextEntry()) != null) {
        try (ZipInputStream zisInner = new ZipInputStream(zisOuter) {

          @Override
          public void close() throws IOException {
            // ...
          }
        }) {
          ZipEntry entryInner;

          while ((entryInner = zisInner.getNextEntry()) != null) {
            if (entryInner.getName().toLowerCase().endsWith("xml")) {
              context.put(Eml510StimmeingabeImportMapperHelper.SIGNATUR_IGNORIEREN, "true");
              Violations violations = eml510StimmeingabeImportMapper.validateInputFormat(zisInner, context, fileKonfiguration);
              context.put(Eml510StimmeingabeImportMapperHelper.SIGNATUR_IGNORIEREN, "false");

              for (AbstractViolation violation : violations.getViolations()) {
                result.add(violation);
              }

              found = true;
            }
          }
        } catch (Exception e) {
          error("Fehler beim Lesen: " + e.getMessage(), e);

          result.addError("nl.backup.format.error.zip.inner", e.getMessage(), entryOuter.getName());
        }
      }
    } catch (Exception e) {
      error("Fehler beim Lesen: " + e.getMessage(), e);

      result.addError("nl.backup.format.error.zip.outer", e.getMessage());
    }

    if (!found) {
      result.addError("nl.backup.format.error.nothing.found");
    }

    return result;
  }
}
