
package de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentRepeat;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.document.generator.template.annotations.DocumentSubTemplate;
import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.internet.control.GebietUndStimmabgabeart;
import de.ivu.elect.business.kandidatur.control.DirektkandidaturByStimmzettelPositionComparator;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.business.wahlvorschlag.entity.Listenverbindung;
import de.ivu.elect.dokumente.CoreElectContext;
import de.ivu.elect.dokumente.kandidatur.KandidaturCoreDaten;
import de.ivu.elect.dokumente.wahlvorschlag.CoreWahlvorschlagsdatenDocument;

// Cf. ListeStimmenDocument, GebietMitListenDocument, ListeMitStimmergebnissenDocument!!!
public class GebietMitDirektkandidatenDocument extends GebietMitStimmenUndWahlausschussDocument {

  private static final long serialVersionUID = 1L;

  private static final Comparator<KandidaturMitStimmergebnissenDocument> NACH_RANG_COMPARATOR = new KandidaturDocumentNachRangComparator();

  @DocumentRepeat(value = "Direktkandidaturen", elementClass = KandidaturMitStimmergebnissenDocument.class, itemName = "direktkandidatur")
  public final List<KandidaturMitStimmergebnissenDocument> direktkandidaturen;

  @DocumentRepeat(value = "DirektkandidaturenSortiertNachRang", elementClass = KandidaturMitStimmergebnissenDocument.class, itemName = "direktkandidatur")
  public final List<KandidaturMitStimmergebnissenDocument> direktkandidaturenSortiertNachRang;

  @DocumentRepeat(value = "DirektkandidaturenGewaehlt", elementClass = KandidaturMitStimmergebnissenDocument.class, itemName = "direktkandidatur")
  public final List<KandidaturMitStimmergebnissenDocument> direktkandidaturenGewaehlt;

  @DocumentSubTemplate
  @DocumentRepeat(value = "Lose", elementClass = ErgebnisKonfliktDocument.class, itemName = "los")
  public final List<ErgebnisKonfliktDocument> lose; // Lose damit es hinter Direktkandidaturen kommt...

  @DocumentComplexField("ErgebnisGewähltMarkiert")
  public final ErgebnisGewaehltMarkiertDocument ergebnisGewaehltMarkiert; // ELECT-9429

  /**
   * @deprecated
   *
   * @see GebietMitDirektkandidatenDocument#ergebnisGewaehltMarkiert#anzahlKandidaturenGesamt
   */
  @Deprecated
  @DocumentSimpleField("AnzahlGewähltVorhandenDirektkandidaturen")
  public final Long anzahlGewaehltVorhandenDirektkandidaturen;

  /**
   * @deprecated
   *
   * @see GebietMitDirektkandidatenDocument#ergebnisGewaehltMarkiert#anzahlKandidaturenIstGewaehltGesamt
   */
  @Deprecated
  @DocumentSimpleField("AnzahlGewählterDirektkandidaturen")
  public final Long anzahlGewaehlterDirektkandidaturen;

  /**
   * @deprecated
   *
   * @see GebietMitDirektkandidatenDocument#ergebnisGewaehltMarkiert#anzahlKandidaturenIstStichwahlGesamt
   */
  @Deprecated
  @DocumentSimpleField("IstGewaehlterStichwahlVorhanden")
  public final boolean gewaehlteStichwahlVorhanden; // ELECT-9298

  public GebietMitDirektkandidatenDocument(CoreElectContext coreElectContext, ErgebnisDaten ergebnisDaten, GebietUndStimmabgabeart gebietUndStimmabgabeart,
      GebietMitStimmenDocument wahlgebietUebergeordnet, Map<Liste, ListeMitStimmergebnissenDocument> ergebnisDokumentPerListe,
      Map<Listenverbindung, WasListenverbindungDokument> ergebnisDokumentPerListenverbindung, KandidaturCoreDaten kandidaturCoreDaten,
      Map<Kandidatur, KandidaturMitStimmergebnissenDocument> ergebnisDokumentPerKandidatur) {
    super(coreElectContext, ergebnisDaten, gebietUndStimmabgabeart, wahlgebietUebergeordnet);

    this.direktkandidaturen = bestimmeDirektkandidaturen(coreElectContext, ergebnisDaten, gebietUndStimmabgabeart, kandidaturCoreDaten, ergebnisDokumentPerKandidatur, false);

    this.direktkandidaturenSortiertNachRang = new ArrayList<>(this.direktkandidaturen);
    this.direktkandidaturenSortiertNachRang.sort(NACH_RANG_COMPARATOR);

    this.direktkandidaturenGewaehlt = bestimmeDirektkandidaturen(coreElectContext, ergebnisDaten, gebietUndStimmabgabeart, kandidaturCoreDaten, ergebnisDokumentPerKandidatur, true);

    this.ergebnisGewaehltMarkiert = new ErgebnisGewaehltMarkiertDocument(coreElectContext, this.direktkandidaturenSortiertNachRang);
    this.anzahlGewaehltVorhandenDirektkandidaturen = this.ergebnisGewaehltMarkiert.anzahlKandidaturenGesamt;
    this.anzahlGewaehlterDirektkandidaturen = this.ergebnisGewaehltMarkiert.anzahlKandidaturenIstGewaehltGesamt;
    this.gewaehlteStichwahlVorhanden = this.ergebnisGewaehltMarkiert.anzahlKandidaturenIstStichwahlGesamt > 0L;

    this.lose = erstelleKonflikte(coreElectContext, ergebnisDaten, gebietUndStimmabgabeart, ergebnisDokumentPerListe, ergebnisDokumentPerListenverbindung, ergebnisDokumentPerKandidatur);
  }

  private List<KandidaturMitStimmergebnissenDocument> bestimmeDirektkandidaturen(CoreElectContext coreElectContext, ErgebnisDaten ergebnisDaten, GebietUndStimmabgabeart gebietUndStimmabgabeart,
      KandidaturCoreDaten kandidaturCoreDaten, Map<Kandidatur, KandidaturMitStimmergebnissenDocument> ergebnisDokumentPerKandidatur, boolean nurGewaehlte) {
    List<KandidaturMitStimmergebnissenDocument> result = new ArrayList<>();

    EntityAufStimmzettelDaten entityAufStimmzettelDaten = ergebnisDaten.getEntityAufStimmzettelDaten();

    Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = gebietUndStimmabgabeart.getWahldurchfuehrungsgebiet();

    List<Direktkandidatur> direktkandidaturenSorted = new ArrayList<>(ergebnisDaten.getDirektkandidaturenNachGebiet(wahldurchfuehrungsgebiet));
    direktkandidaturenSorted.sort(new DirektkandidaturByStimmzettelPositionComparator(wahldurchfuehrungsgebiet, entityAufStimmzettelDaten));

    Long laufendeNummer = 0L;

    for (Direktkandidatur direktkandidatur : direktkandidaturenSorted) {
      if (!nurGewaehlte || isGewaehlt(direktkandidatur, ergebnisDaten)) {
        laufendeNummer++;

        CoreWahlvorschlagsdatenDocument wahlvorschlagsdatenDocument = new CoreWahlvorschlagsdatenDocument(coreElectContext, entityAufStimmzettelDaten, wahldurchfuehrungsgebiet,
            direktkandidatur.getWahlvorschlag(), laufendeNummer);

        KandidaturMitStimmergebnissenDocument kandidaturMitStimmergebnissenDocument = new KandidaturMitStimmergebnissenDocument(coreElectContext, ergebnisDaten, gebietUndStimmabgabeart,
            wahlvorschlagsdatenDocument, kandidaturCoreDaten, direktkandidatur, laufendeNummer);

        ergebnisDokumentPerKandidatur.put(direktkandidatur, kandidaturMitStimmergebnissenDocument);

        result.add(kandidaturMitStimmergebnissenDocument);
      }
    }

    return result;
  }

  private boolean isGewaehlt(Direktkandidatur direktkandidatur, ErgebnisDaten ergebnisDaten) {
    Gewaehlt gewaehlteFuerKandidatur = ergebnisDaten.getGewaehlteFuerKandidatur(direktkandidatur);

    return gewaehlteFuerKandidatur != null && gewaehlteFuerKandidatur.getIstGewaehlt();
  }
}
