
package de.ivu.elect.business.ergebnis.boundary;

import java.util.Collection;
import java.util.List;
import java.util.function.Function;

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

import de.ivu.elect.business.datei.entity.DateiImportBerichtCustomData;
import de.ivu.elect.business.ergebnis.control.SitzeImportContext;
import de.ivu.elect.business.ergebnis.control.SitzeImportExchange;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.Sitze;
import de.ivu.elect.business.ergebnis.entity.SitzeTK;
import de.ivu.elect.business.ergebnis.entity.SitzergebnisMeta;
import de.ivu.elect.business.exchange.control.AbstractEntityImporter;
import de.ivu.elect.business.exchange.control.ImportExchange;
import de.ivu.elect.jee.exchange.Violations;
import de.ivu.elect.business.exchange.entity.ImportUpdateReport;
import de.ivu.elect.business.gruppeimgebiet.control.AbstractGruppeImGebietCache;
import de.ivu.elect.business.gruppeimgebiet.control.GruppeImGebietCacheFactory;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebietTK;
import de.ivu.elect.business.wahl.boundary.WahlDAO;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.jee.entity.Meta;
import de.ivu.elect.jee.exchange.ImportOptions;

@Stateless
public class SitzeImporter
    extends
      AbstractEntityImporter<Sitze, SitzeTK, SitzeImportContext, DateiImportBerichtCustomData> {

  @Inject
  transient ErgebnisImportSearch ergebnisSearch;

  @Inject
  transient GruppeImGebietCacheFactory gruppeImGebietCacheFactory;

  @Inject
  private transient SitzeImportValidator sitzeImportValidator;

  @Inject
  private transient SitzeImportExchange sitzeImportExchange;

  @Inject
  private transient SitzergebnisMeta sitzergebnisMeta;

  @Inject
  transient SitzeDAO sitzeDAO;

  @Inject
  transient WahlDAO wahlDAO;

  @Override
  protected ImportExchange<List<Sitze>, SitzeImportContext> getExchange() {
    return sitzeImportExchange;
  }

  @Override
  public Meta getMetaForEntityInternal() {
    return sitzergebnisMeta;
  }

  @Override
  protected void validiere(Violations violations, List<Sitze> importObject, SitzeImportContext context, ImportOptions importOptions) {
    sitzeImportValidator.validiere(violations, importObject, context);
  }

  @Override
  protected void loescheAusDatenbank(Collection<Sitze> sitzeInDb, SitzeImportContext context,
      DateiImportBerichtCustomData dateiImportBerichtCustomData, StringBuilder bericht) {
    sitzeInDb.forEach(sitze -> sitzeDAO.remove(sitze));
  }

  @Override
  protected void persistiere(Collection<Sitze> sitzeNurInDateiNichtInDb, SitzeImportContext context,
      DateiImportBerichtCustomData dateiImportBerichtCustomData, StringBuilder bericht) {
    Ergebnis ergebnis = findErgebnis(context);
    Wahl wahl = wahlDAO.attach(context.getWahl());

    AbstractGruppeImGebietCache gruppeImGebietCache = gruppeImGebietCacheFactory
        .createNewGruppeImGebietCompleteHierarchyCache(wahl);

    for (Sitze sitze : sitzeNurInDateiNichtInDb) {
      // Sitze von Gruppen, die nicht in der aktuellen Wahl vorhanden sind ignorieren
      if (gruppeImGebietCache.isGruppeVorhanden(sitze.getGruppe().getGruppeTK())) {
        exchangeGruppeImGebietWithGruppeImGebietFromDb(sitze, gruppeImGebietCache);
        sitze.setErgebnis(ergebnis);
        sitzeDAO.persist(sitze);
      }
    }
  }

  protected void exchangeGruppeImGebietWithGruppeImGebietFromDb(Sitze sitze,
      AbstractGruppeImGebietCache gruppeImGebietCache) {
    GruppeImGebietTK gruppeImGebietTK = sitze.getGruppeImGebietTK();
    GruppeImGebiet gruppeImGebietAusDatenbank = gruppeImGebietCache.findOrCreate(gruppeImGebietTK);
    sitze.setGruppe(gruppeImGebietAusDatenbank.getGruppe());
    sitze.setGebiet(gruppeImGebietAusDatenbank.getGebiet());
  }

  @Override
  protected void aktualisiere(Sitze entityInDatei, Sitze entityInDatenbank, SitzeImportContext context,
      DateiImportBerichtCustomData dateiImportBerichtCustomData, StringBuilder bericht) {
    // Ich gehe davon aus, dass entityInDatenbank.getGruppeImGebiet() und entityInDatenbank.getErgebnis() schon stimmen 

    entityInDatenbank.setAnzahl(entityInDatei.getAnzahl());
    entityInDatenbank.setAnzahlAnspruch(entityInDatei.getAnzahlAnspruch());
    entityInDatenbank.setCustomDataXml(entityInDatei.getCustomDataXml());
  }

  @Override
  protected List<Sitze> getAllEntitiesInDB(SitzeImportContext context) {
    return sitzeDAO.findByErgebnis(findErgebnis(context));
  }

  @Override
  protected Function<Sitze, SitzeTK> getEntityToEntityTKFunction() {
    return SitzeTK.getSitzeToTKFunction();
  }

  @Override
  protected void erstelleBericht(List<Sitze> importObject, SitzeImportContext context, ImportOptions importOptions,
      StringBuilder bericht, boolean vorab) {
    // nichts zu tun
  }

  Ergebnis findErgebnis(SitzeImportContext context) {
    return ergebnisSearch.loadUniqueErgebnis(context.getWahl(), context.getZiel());
  }

  @Override
  protected void importiereImportObject(List<Sitze> inDatei, SitzeImportContext context, ImportOptions importOptions,
      DateiImportBerichtCustomData customDateiImportBerichtCustomData, StringBuilder bericht) {
    // Wird nur überschrieben, damit die Methode im Test sichtbar wird
    super.importiereImportObject(inDatei, context, importOptions, customDateiImportBerichtCustomData, bericht);
  }

  @Override
  protected ImportUpdateReport createImportUpdateReport(List<Sitze> inDatei, Violations violations,
      SitzeImportContext context, ImportOptions importOptions, StringBuilder bericht) {
    // Wird nur überschrieben, damit die Methode im Test sichtbar wird
    return super.createImportUpdateReport(inDatei, violations, context, importOptions, bericht);
  }

}
