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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

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

import de.ivu.elect.business.ergebnis.entity.DHondtQuotient;
import de.ivu.elect.business.ergebnis.entity.Ergebnis;
import de.ivu.elect.business.ergebnis.entity.ErgebnisLogEintrag;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.ergebnis.entity.Sitze;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.fremdkandidatur.entity.Fremdkandidatur;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPolygonPoint;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsgruppierung;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppeEigenschaften;
import de.ivu.elect.business.gruppeimgebiet.control.GruppeImGebietReihenfolgeVorsortierer;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.internet.entity.InternetSeite;
import de.ivu.elect.business.kandidatenportal.entity.WvpWarnung;
import de.ivu.elect.business.kandidatur.control.GewaehltByIsGewaehltAndRangComparator;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatter;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.person.entity.PersonenVerknuepfung;
import de.ivu.elect.business.pruefung.boundary.ZulassungPruefer;
import de.ivu.elect.business.staat.entity.StaatenGruppe;
import de.ivu.elect.business.stimmeingabe.boundary.StimmeingabeErfassenDescriptionResolver;
import de.ivu.elect.business.stimmeingabe.entity.ErgebnisGueltigerEingang;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingangsart;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiKonfiguration;
import de.ivu.elect.business.stimmen.control.ErgebnisStimmenFilter;
import de.ivu.elect.business.stimmzettel.boundary.EntityAufStimmzettelDatenStimmzettelPositionBerechnung;
import de.ivu.elect.business.stimmzettel.entity.Stimmzettel;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelKopfdatum;
import de.ivu.elect.business.veranstaltung.entity.Veranstaltung;
import de.ivu.elect.business.wahl.control.Loader;
import de.ivu.elect.business.wahl.control.ParameterLoader;
import de.ivu.elect.business.wahl.control.StimmenLoader;
import de.ivu.elect.business.wahl.entity.AbstractWahlParameterLoader;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.business.wahlausschuss.entity.WahlausschussEntschaedigung;
import de.ivu.elect.business.wahlausschuss.entity.Wahlausschussmitglied;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungVerlauf;
import de.ivu.elect.business.wahlrechtspruefung.entity.Pruefkriterium;
import de.ivu.elect.business.wahlrechtspruefung.entity.Wahlrechtspruefung;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlagsperson.entity.WahlvorschlagsPerson;

public class ErgebnisDatenLoader extends StimmergebnisDaten {

  private static final long serialVersionUID = 1L;

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

  private final Loader<Gewaehlt> gewaehlteLoader;

  private final Loader<Sitze> sitzeLoader;

  private final Loader<ErgebnisKonflikt> konflikteLoader;

  private final Loader<ErgebnisLogEintrag> ergebnisLogeintraegeLoader;

  private final Loader<DHondtQuotient> dHondtQuotientenLoader;

  private final Loader<ErgebnisGueltigerEingang> gueltigerEingaengeLoader;

  private List<Gewaehlt> gewaehlte;

  private List<Sitze> sitze;

  private List<ErgebnisKonflikt> konflikte;

  private List<ErgebnisLogEintrag> ergebnisLogeintraege;

  private List<DHondtQuotient> dHondtQuotienten;

  private List<ErgebnisGueltigerEingang> gueltigerEingaenge;

  public ErgebnisDatenLoader(StimmergebnisDaten stimmergebnisDaten, Loader<Gewaehlt> gewaehlteLoader, Loader<Sitze> sitzeLoader, Loader<ErgebnisKonflikt> konflikteLoader,
      Loader<ErgebnisLogEintrag> ergebnisLogeintraegeLoader, Loader<DHondtQuotient> dHondtQuotientenLoader, Loader<ErgebnisGueltigerEingang> gueltigerEingaengeLoader) {
    super(stimmergebnisDaten);

    this.gewaehlteLoader = gewaehlteLoader;
    this.sitzeLoader = sitzeLoader;
    this.konflikteLoader = konflikteLoader;
    this.ergebnisLogeintraegeLoader = ergebnisLogeintraegeLoader;
    this.dHondtQuotientenLoader = dHondtQuotientenLoader;
    this.gueltigerEingaengeLoader = gueltigerEingaengeLoader;
  }

  public ErgebnisDatenLoader(ErgebnisDatenLoader ergebnisDatenLoader) {
    this(ergebnisDatenLoader.getWahl(), ergebnisDatenLoader.getGebieteLoader(), ergebnisDatenLoader.getGruppenLoader(), ergebnisDatenLoader.getGruppenImGebietLoader(),
        ergebnisDatenLoader.getWahlvorschlaegeLoader(), ergebnisDatenLoader.getKandidaturenLoader(), ergebnisDatenLoader.getPersonenVerknuepfungenLoader(), ergebnisDatenLoader.getStimmenLoader(),
        ergebnisDatenLoader.getGewaehlteVorperiodeLoader(), ergebnisDatenLoader.getSitzeVorperiodeLoader(), ergebnisDatenLoader.getStaatenGruppenLoader(),
        ergebnisDatenLoader.getGebietsgruppierungenLoader(), ergebnisDatenLoader.getWahlvorschlagsPersonenLoader(), ergebnisDatenLoader.getWahlausschussmitgliederLoader(),
        ergebnisDatenLoader.getWahlausschussEntschaedigungenLoader(), ergebnisDatenLoader.getErgebnis(), ergebnisDatenLoader.getErgebnisVorperiode(), ergebnisDatenLoader.getStimmen(),
        ergebnisDatenLoader.getSystemGruppeEigenschaften(), ergebnisDatenLoader.getStimmenKumulierer(), ergebnisDatenLoader.getWahlParameterLoader(), ergebnisDatenLoader.getZulassungPruefer(),
        ergebnisDatenLoader.getStimmzettelFormatter(), ergebnisDatenLoader.getEntityAufStimmzettelDatenStimmzettelPositionBerechnung(), ergebnisDatenLoader.getGruppeImGebietReihenfolgeVorsortierer(),
        ergebnisDatenLoader.getGebietPolygonPointsLoader(), ergebnisDatenLoader.getFremdkandidaturenLoader(), ergebnisDatenLoader.getInternetSeitenLoader(), ergebnisDatenLoader.getGewaehlteLoader(),
        ergebnisDatenLoader.getSitzeLoader(), ergebnisDatenLoader.getKonflikteLoader(), ergebnisDatenLoader.getErgebnisLogeintraegeLoader(), ergebnisDatenLoader.getdHondtQuotientenLoader(),
        ergebnisDatenLoader.getGueltigerEingaengeLoader(), ergebnisDatenLoader.getErfassteGebieteLoader(), ergebnisDatenLoader.getErgebnisStimmenFilter(),
        ergebnisDatenLoader.getLetzterErgebniseingangLoader(), ergebnisDatenLoader.getErgebnisGueltigerEingangLoader(), ergebnisDatenLoader.getWahlbeteiligungVerlaeufeLoader(),
        ergebnisDatenLoader.getWahlbeteiligungAuswertungenLoader(), ergebnisDatenLoader.getStimmeingabeErfassenDescriptionResolver(), ergebnisDatenLoader.getStimmeingabePlausiKonfigurationenLoader(),
        ergebnisDatenLoader.getVeranstaltungenLoader(), ergebnisDatenLoader.getStimmzettelLoader(), ergebnisDatenLoader.getStimmzettelKopfdatenLoader(), ergebnisDatenLoader.getPruefkriterienLoader(),
        ergebnisDatenLoader.getWahlrechtspruefungenLoader(), ergebnisDatenLoader.getWvpWarnungenLoader());
  }

  public ErgebnisDatenLoader(Wahldurchfuehrung wahl, Loader<Wahldurchfuehrungsgebiet> gebieteLoader, Loader<Gruppe> gruppenLoader, Loader<GruppeImGebiet> gruppenImGebietLoader,
      Loader<Wahlvorschlag> wahlvorschlaegeLoader, Loader<Kandidatur> kandidaturenLoader, Loader<PersonenVerknuepfung> personenVerknuepfungenLoader, StimmenLoader stimmenLoader,
      Loader<Gewaehlt> gewaehlteVorperiodeLoader, Loader<Sitze> sitzeVorperiodeLoader, Loader<StaatenGruppe> staatenGruppenLoader, Loader<Gebietsgruppierung> gebietsgruppierungenLoader,
      Loader<WahlvorschlagsPerson> wahlvorschlagsPersonenLoader, Loader<Wahlausschussmitglied> wahlausschussmitgliederLoader, Loader<WahlausschussEntschaedigung> wahlausschussEntschaedigungenLoader,
      Ergebnis ergebnis, Ergebnis ergebnisVorperiode, StimmenPool stimmen, SystemGruppeEigenschaften systemGruppeEigenschaften, StimmenKumulierer stimmenKumulierer,
      AbstractWahlParameterLoader wahlParameterLoader, ZulassungPruefer zulassungPruefer, StimmzettelFormatter stimmzettelFormatter,
      EntityAufStimmzettelDatenStimmzettelPositionBerechnung entityAufStimmzettelDatenStimmzettelPositionBerechnung, GruppeImGebietReihenfolgeVorsortierer gruppeImGebietReihenfolgeVorsortierer,
      Loader<GebietPolygonPoint> gebietPolygonPointsLoader, Loader<Fremdkandidatur> fremdkandidaturenLoader, Loader<InternetSeite> internetSeitenLoader, Loader<Gewaehlt> gewaehlteLoader,
      Loader<Sitze> sitzeLoader, Loader<ErgebnisKonflikt> konflikteLoader, Loader<ErgebnisLogEintrag> ergebnisLogeintraegeLoader, Loader<DHondtQuotient> dHondtQuotientenLoader,
      Loader<ErgebnisGueltigerEingang> gueltigerEingaengeLoader, Loader<Gebiet> erfassteGebieteLoader, ErgebnisStimmenFilter ergebnisStimmenFilter,
      ParameterLoader<Ergebniseingang, Ergebniseingangsart> letzterErgebniseingangLoader, ParameterLoader<ErgebnisGueltigerEingang, Ergebniseingangsart> ergebnisGueltigerEingangLoader,
      Loader<WahlbeteiligungVerlauf> wahlbeteiligungVerlaeufeLoader, Loader<WahlbeteiligungAuswertung> wahlbeteiligungAuswertungenLoader,
      StimmeingabeErfassenDescriptionResolver stimmeingabeErfassenDescriptionResolver, Loader<StimmeingabePlausiKonfiguration> stimmeingabePlausiKonfigurationenLoader,
      Loader<Veranstaltung> veranstaltungenLoader, Loader<Stimmzettel> stimmzettelLoader, Loader<StimmzettelKopfdatum> stimmzettelKopfdatenLoader, Loader<Pruefkriterium> pruefkriterienLoader,
      Loader<Wahlrechtspruefung> wahlrechtspruefungenLoader, Loader<WvpWarnung> wvpWarnungenLoader) {
    super(wahl, gebieteLoader, gruppenLoader, gruppenImGebietLoader, wahlvorschlaegeLoader, kandidaturenLoader, personenVerknuepfungenLoader, stimmenLoader, gewaehlteVorperiodeLoader,
        sitzeVorperiodeLoader, staatenGruppenLoader, gebietsgruppierungenLoader, wahlvorschlagsPersonenLoader, wahlausschussmitgliederLoader, wahlausschussEntschaedigungenLoader, ergebnis,
        ergebnisVorperiode, stimmen, systemGruppeEigenschaften, stimmenKumulierer, wahlParameterLoader, zulassungPruefer, stimmzettelFormatter, entityAufStimmzettelDatenStimmzettelPositionBerechnung,
        gruppeImGebietReihenfolgeVorsortierer, gebietPolygonPointsLoader, fremdkandidaturenLoader, internetSeitenLoader, erfassteGebieteLoader, ergebnisStimmenFilter, letzterErgebniseingangLoader,
        ergebnisGueltigerEingangLoader, wahlbeteiligungVerlaeufeLoader, wahlbeteiligungAuswertungenLoader, stimmeingabeErfassenDescriptionResolver, stimmeingabePlausiKonfigurationenLoader,
        veranstaltungenLoader, stimmzettelLoader, stimmzettelKopfdatenLoader, pruefkriterienLoader, wahlrechtspruefungenLoader, wvpWarnungenLoader);

    this.gewaehlteLoader = gewaehlteLoader;
    this.sitzeLoader = sitzeLoader;
    this.konflikteLoader = konflikteLoader;
    this.ergebnisLogeintraegeLoader = ergebnisLogeintraegeLoader;
    this.dHondtQuotientenLoader = dHondtQuotientenLoader;
    this.gueltigerEingaengeLoader = gueltigerEingaengeLoader;
  }

  private List<Gewaehlt> sortiereGewaehlte(List<Gewaehlt> gewaehlte) {
    List<Gewaehlt> result = new ArrayList<>(gewaehlte);
    Collections.sort(result, new GewaehltByIsGewaehltAndRangComparator());
    return result;
  }

  public List<DHondtQuotient> getdHondtQuotienten() {
    if (dHondtQuotienten == null) {
      LOG.info("Lade dHondtQuotienten");
      dHondtQuotienten = dHondtQuotientenLoader.load();
      LOG.info("Lade dHondtQuotienten - done");

    }
    return dHondtQuotienten;
  }

  public List<ErgebnisLogEintrag> getErgebnisLogeintraege() {
    if (ergebnisLogeintraege == null) {
      LOG.info("Lade ergebnisLogeintraege");
      ergebnisLogeintraege = ergebnisLogeintraegeLoader.load();
      LOG.info("Lade ergebnisLogeintraege - done");
    }
    return ergebnisLogeintraege;
  }

  public List<Gewaehlt> getGewaehlte(Predicate<Gewaehlt> gewaehltPredicate) {
    return getGewaehlte().stream().filter(gewaehltPredicate).collect(Collectors.toList());
  }

  public List<Gewaehlt> getGewaehlte() {
    if (gewaehlte == null) {
      LOG.info("Lade gewaehlte");
      gewaehlte = sortiereGewaehlte(gewaehlteLoader.load());
      LOG.info("Lade gewaehlte - done");
    }
    return gewaehlte;
  }

  @Override
  public List<Gewaehlt> getGewaehltVorperiode() {
    if (gewaehlteVorperiode == null) {
      LOG.info("Lade gewaehltVorperiode");
      List<Gewaehlt> result = super.getGewaehltVorperiode();
      LOG.info("Lade gewaehltVorperiode - done");
      return result;
    }
    return super.getGewaehltVorperiode();
  }

  public List<ErgebnisGueltigerEingang> getGueltigerEingaenge() {
    if (gueltigerEingaenge == null) {
      LOG.info("Lade gueltigerEingaenge");
      gueltigerEingaenge = gueltigerEingaengeLoader.load();
      LOG.info("Lade gueltigerEingaenge - done, gueltigerEingaenge=" + gueltigerEingaenge.size());
    }
    return gueltigerEingaenge;
  }

  public List<ErgebnisKonflikt> getKonflikte() {
    if (konflikte == null) {
      LOG.info("Lade konflikte");
      konflikte = konflikteLoader.load();
      LOG.info("Lade konflikte - done, konflikte=" + konflikte.size());

    }
    return konflikte;
  }

  public List<Sitze> getSitze() {
    if (sitze == null) {
      LOG.info("Lade sitze");
      sitze = sitzeLoader.load();
      LOG.info("Lade sitze - done, sitze=" + sitze.size());
    }
    return sitze;
  }

  @Override
  public List<Sitze> getSitzeVorperiode() {
    if (sitzeVorperiode == null) {
      LOG.info("Lade sitzeVorperiode");
      List<Sitze> result = super.getSitzeVorperiode();
      LOG.info("Lade sitzeVorperiode - done, result=" + result.size());
      return result;
    }
    return super.getSitzeVorperiode();
  }

  protected Loader<DHondtQuotient> getdHondtQuotientenLoader() {
    return dHondtQuotientenLoader;
  }

  protected Loader<ErgebnisLogEintrag> getErgebnisLogeintraegeLoader() {
    return ergebnisLogeintraegeLoader;
  }

  protected Loader<Gewaehlt> getGewaehlteLoader() {
    return gewaehlteLoader;
  }

  protected Loader<ErgebnisGueltigerEingang> getGueltigerEingaengeLoader() {
    return gueltigerEingaengeLoader;
  }

  protected Loader<ErgebnisKonflikt> getKonflikteLoader() {
    return konflikteLoader;
  }

  protected Loader<Sitze> getSitzeLoader() {
    return sitzeLoader;
  }
}
