
package de.ivu.elect.business.dokumente.control;

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

import javax.annotation.Nullable;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;

import org.apache.commons.io.FileUtils;
import org.primefaces.model.file.UploadedFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.datei.entity.DateiExport;
import de.ivu.elect.business.datei.entity.DateiFileNames;
import de.ivu.elect.business.datei.entity.FileType;
import de.ivu.elect.business.datei.entity.FileTypeResolver;
import de.ivu.elect.business.dokumente.entity.DokumentGeneratorArt;
import de.ivu.elect.business.dokumente.entity.DokumentKonverterResult;
import de.ivu.elect.business.dokumente.entity.DokumentVorlage;
import de.ivu.elect.business.exchange.control.ImportExportStreamCreator;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.jee.exception.ElectCommonException;

@RequestScoped // ELECT-6404
public class DokumentGenerieren implements Serializable {

  private static final long serialVersionUID = 1L;

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

  @Inject
  private transient FileTypeResolver fileTypeResolver;

  @Inject
  private transient Instance<DokumentMerger> dokumentGenerators;

  @Inject
  private transient ImportExportStreamCreator importExportStreamCreator;

  public DateiExport generiereDokument(@Nullable DokumentVorlage dokumentVorlage, @Nullable UploadedFile uploadedFile, DokumentKonverterResult contentData,
      DokumentExtraFileOutput dokumentExtraFileOutput, Wahl wahl, Wahltermin wahltermin, FileType zieldateiTyp, DateiFileNames dateiFileNames, ProgressMonitor monitor) {
    DokumentMerger dokumentMerger = findeDokumentGenrator(contentData.getDokumentGeneratorArt());
    return dokumentMerger.generiereDatei(createTempFile(dokumentVorlage, uploadedFile), contentData, dokumentExtraFileOutput, wahl, wahltermin, zieldateiTyp, dateiFileNames, monitor);
  }

  private DokumentMerger findeDokumentGenrator(DokumentGeneratorArt dokumentGeneratorArt) {

    for (DokumentMerger dokumentMerger : dokumentGenerators) {
      if (dokumentGeneratorArt.equals(dokumentMerger.getArt())) {
        return dokumentMerger;
      }
    }

    throw new ElectCommonException("kein.dokument.generator.gefunden", dokumentGeneratorArt);

  }

  private File createTempFile(@Nullable DokumentVorlage dokumentVorlage, @Nullable UploadedFile uploadedFile) {
    File templateFile;
    if (dokumentVorlage == null) {
      if (uploadedFile == null) {
        throw new ElectCommonException("dokument.generator.weder.vorlage.noch.datei");
      }
      try {
        String suffix = FileType.ODT.getFileExtension();

        if (isDokumentVorlageArchive(uploadedFile)) {
          suffix = FileType.ZIP.getFileExtension();
        }
        templateFile = File.createTempFile("dokumentvorlage" + System.currentTimeMillis(), "." + suffix);
        try (InputStream is = uploadedFile.getInputStream(); FileOutputStream os = new FileOutputStream(templateFile)) {
          org.apache.commons.io.IOUtils.copy(is, os);
          os.close();
        }
        deleteDirOnExit(templateFile);
      } catch (IOException e) {
        throw new ElectCommonException("dokument.generator.lesen.vorlage.fehlerhaft", e, e.getLocalizedMessage());
      }
    } else {
      templateFile = dokumentVorlage.getDatei().createFile(importExportStreamCreator);
    }
    return templateFile;
  }

  public boolean isDokumentVorlageArchive(@Nullable UploadedFile uploadedFile) {
    return uploadedFile != null && fileTypeResolver.getFileType(uploadedFile.getFileName().trim()).orElse(FileType.ODT).isDokumentVorlageArchive();
  }

  public static void deleteDir(File dir) {
    try {
      FileUtils.deleteDirectory(dir);
    } catch (IOException e) {
      deleteDirOnExit(dir);
    }
  }

  private static void deleteDirOnExit(File dir) {
    try {
      FileUtils.forceDeleteOnExit(dir);
    } catch (IOException e) {
      LOG.warn(dir.getAbsolutePath() + " - " + e.getMessage());
    }
  }
}
