package de.ivu.elect.was.exchange.ergebnis.eml;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.EmlExportMapper;
import de.ivu.elect.business.ergebnis.boundary.ErgebnisDAO;
import de.ivu.elect.business.ergebnis.control.ErgebnisDatenCreator;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportContext;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportObject;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.exchange.control.MappingException;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.konfiguration.entity.ElectKonfigurationWerte;
import de.ivu.elect.business.konfiguration.entity.KonfigurationLoader;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.presentation.ergebnis.exchange.NlErgebnisExportView;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;
import de.ivu.elect.util.FileUtil;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class Eml510ExportBackup implements Serializable {

  private static final Logger LOG = LoggerFactory.getLogger(Eml510ExportBackup.class);

  private static final long serialVersionUID = 1L;

  private static final int BUFFER_SIZE = 64 * 1024;

  @Inject
  private transient WahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO;

  @Inject
  private transient Eml510aGSBErgebnisExportMapper eml510aGSBErgebnisExportMapper;

  @Inject
  private transient Eml510bHSBErgebnisExportMapper eml510bHSBErgebnisExportMapper;

  @Inject
  private transient Eml510cCSBErgebnisExportMapper eml510cCSBErgebnisExportMapper;

  @Inject
  private transient ErgebnisDAO ergebnisDAO;

  @Inject
  private transient ErgebnisDatenCreator ergebnisDatenCreator;

  @Inject
  private transient KonfigurationLoader konfigurationLoader;

  @Inject
  private transient GebietNummerFormatter gebietNummerFormatter;

  public void export(GebietPK gebietPK) {
    try {
      LOG.info("Backup: " + gebietPK);
      Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = wahldurchfuehrungsgebietDAO.findByPrimaryKey(gebietPK);

      for (Ergebnis ergebnis : ergebnisDAO.findByWahlAndErgebnisart(wahldurchfuehrungsgebiet.getWahl(),
          wahldurchfuehrungsgebiet.getWahl().castTo(Wahldurchfuehrung.class).getEntity().getErgebniseingangsart().korrespondierendeErgebnisart())) {

        ErgebnisExportContext context = new ErgebnisExportContext(ergebnis);
        context.put(EmlExportMapper.BACKUP_MARKER, true);
        context.put(NlErgebnisExportView.NL_ERGEBNIS_EXPORT_CONTEXT_PARAM_SELECTED_GEBIET_PK, gebietPK);

        ErgebnisExportObject ergebnisExportObject = new ErgebnisExportObject(ergebnisDatenCreator.createErgebnisDatenExporte(ergebnis), Stimmabgabeart.GESAMT);

        context.put(EmlExportMapper.EML_SIGN_SKIP_KEY, Boolean.TRUE); /* Beim Backup keine Signierung, da Passwort zum Schlüssel nicht bekannt*/
        tryExport(wahldurchfuehrungsgebiet, context, ergebnisExportObject, eml510aGSBErgebnisExportMapper);
        tryExport(wahldurchfuehrungsgebiet, context, ergebnisExportObject, eml510bHSBErgebnisExportMapper);
        tryExport(wahldurchfuehrungsgebiet, context, ergebnisExportObject, eml510cCSBErgebnisExportMapper);

      }

    } catch (Exception e) {
      LOG.error("Backup error: " + gebietPK + ", " + e.getMessage(), e);
    }

  }

  private void tryExport(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, ErgebnisExportContext context, ErgebnisExportObject ergebnisExportObject, Abstract510ErgebnisExportMapper ergebnisExportMapper) {
    if (ergebnisExportMapper.isAcceptContext(context)) {
      LOG.info("Export: " + ergebnisExportMapper);

      try (ByteArrayOutputStream bos = new ByteArrayOutputStream(BUFFER_SIZE)) {
        ergebnisExportMapper.serialize(ergebnisExportObject, bos, context, null);

        String dateiablage = konfigurationLoader.resolveStringValue(ElectKonfigurationWerte.ELECT_COMMON_DATEI_ABLAGE_VERZEICHNIS_PFAD);

        dateiablage += File.separator + "backup";

        if (!wahldurchfuehrungsgebiet.getMandant().getArt().isOhneMandant()) {
          dateiablage += File.separator + wahldurchfuehrungsgebiet.getMandant().getNummer();
        }

        File path = new File(dateiablage);
        path.mkdirs();

        String filename = "backup_" + FileUtil.normalizeFileName(gebietNummerFormatter.getDarstellung(wahldurchfuehrungsgebiet), true) + ".eml.zip";
        File file = new File(path, filename);
        LOG.info("Backupfile: " + file);
        try (FileOutputStream fos = new FileOutputStream(file)) {
          bos.writeTo(fos);
        }

      } catch (IOException | MappingException e) {
        throw new RuntimeException(e.getMessage(), e);
      }
    } else {
      LOG.info("Kein Export: " + ergebnisExportMapper);
    }
  }

}
