
package de.ivu.elect.dokumente.ergebnis.kandidatur;

import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;

import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.control.ErgebnisDatenDirektkandidaturen;
import de.ivu.elect.business.ergebnis.control.ErgebnisDatenListenkandidaturen;
import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.internet.control.GebietUndStimmabgabeart;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.person.entity.PersonenVerknuepfung;
import de.ivu.elect.business.stimmen.boundary.ListenkandidaturstimmeLabelGenerator;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahl.entity.CommonWahlart;
import de.ivu.elect.business.wahl.entity.WahlartErgebnisart;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStimmzettelPosition;
import de.ivu.elect.dokumente.ergebnis.AbstractErgebnisTabellarischDocumentZeileCreator;

public class ErgebnisKandidaturenTabellarischDocumentZeileCreator extends AbstractErgebnisTabellarischDocumentZeileCreator<ErgebnisKandidaturenTabellarischDocumentZeile> {

  public ErgebnisKandidaturenTabellarischDocumentZeileCreator() {
    super();
  }

  @Override
  protected ErgebnisKandidaturenTabellarischDocumentZeile createZeile(WahlartErgebnisart ergebnisart, Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return new ErgebnisKandidaturenTabellarischDocumentZeile(ergebnisart, wahldurchfuehrungsgebiet);
  }

  @Override
  protected void fillInErgebnisDatenStimmen(ErgebnisKandidaturenTabellarischDocumentZeile zeile, ErgebnisDaten ergebnisDaten, Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet,
      Stimmabgabeart stimmabgabeart) {
    // Cf. ErgebnisKandidaturenTabellarischDocumentZeileCreator#createZeilenFuerGruppe
  }

  /**
   * Während in der V7 eine Zeile sich nur auf ein Gebiet bezieht und dann Informationen zu allen Parteien anzeigt, bezieht sich in der V5 eine Zeile auf EINE Partei in einem Gebiet. Der Einfachheit
   * halber werden zunächst aber wieder nur Zeilen für Gebiete erstellt und diese dann pro Partei dupliziert.
   */
  public List<ErgebnisKandidaturenTabellarischDocumentZeile> createZeilenFuerGruppe(List<ErgebnisKandidaturenTabellarischDocumentZeile> zeilen, ErgebnisDaten ergebnisDaten,
      PolitischeGruppe politischeGruppe, ListenkandidaturstimmeLabelGenerator listenkandidaturstimmeLabelGenerator) {
    List<ErgebnisKandidaturenTabellarischDocumentZeile> result = new ArrayList<>();

    Stimmabgabeart stimmabgabeart = getStimmabgabeart();

    ErgebnisDatenDirektkandidaturen ergebnisDatenDirektkandidaturen = ergebnisDaten.getErgebnisDatenDirektkandidaturen();
    ErgebnisDatenListenkandidaturen ergebnisDatenListenkandidaturen = ergebnisDaten.getErgebnisDatenListenkandidaturen();

    EntityAufStimmzettelDaten entityAufStimmzettelDaten = ergebnisDaten.getEntityAufStimmzettelDaten();

    for (ErgebnisKandidaturenTabellarischDocumentZeile zeile : zeilen) {
      Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = zeile.wahldurchfuehrungsgebiet;
      GebietUndStimmabgabeart gebietUndStimmabgabeart = new GebietUndStimmabgabeart(wahldurchfuehrungsgebiet, stimmabgabeart);

      GruppeImGebiet gruppeImGebiet = ergebnisDaten.getGruppeImGebiet(politischeGruppe, wahldurchfuehrungsgebiet);

      Wahlvorschlag wahlvorschlag = gruppeImGebiet.getErstenWahlvorschlagAbgeleitet(entityAufStimmzettelDaten);
      WahlvorschlagStimmzettelPosition wahlvorschlagStimmzettelPosition = wahlvorschlag.getStimmzettelPosition(wahldurchfuehrungsgebiet, entityAufStimmzettelDaten);

      if (wahlvorschlagStimmzettelPosition.hasPosition()) { // danach wird sortiert!
        ErgebnisKandidaturenTabellarischDocumentZeile copy = zeile.copy();
        copy.listenkandidatStimmenQueueNummer.clear();
        copy.listenkandidatStimmenQueueName.clear();
        copy.listenkandidatStimmenQueueAnzahlStimmen.clear();

        copy.parteiZweitstimmenAnzahl = ergebnisDaten.getZweitstimmenAktuell(politischeGruppe, gebietUndStimmabgabeart);

        copy.wahlvorschlagName = wahlvorschlag.getKurznameOderKennwort();
        copy.parteiKurzName = politischeGruppe.getKurznameAufGebiet(wahldurchfuehrungsgebiet);
        copy.parteiNummer = politischeGruppe.getSchluessel();
        copy.parteiNummerWahlkreisvorschlag = wahlvorschlagStimmzettelPosition.formatPosition();

        List<Listenkandidatur> listenkandidaturen = ergebnisDatenListenkandidaturen.getListenkandidaturenAufStimmzettelFuerGruppeAufGebiet(politischeGruppe, wahldurchfuehrungsgebiet);

        Direktkandidatur direktkandidatur = extractDirektkandidatur(wahldurchfuehrungsgebiet, ergebnisDaten, politischeGruppe, wahlvorschlag);
        Listenkandidatur listenkandidaturZuDirektkandidatur = getListenkandidaturZuDirektkandidatur(direktkandidatur, listenkandidaturen);

        if (direktkandidatur != null) {
          copy.parteiErststimmenNameBewerber = direktkandidatur.getFamilienname();
          copy.parteiErststimmenAnzahl = ergebnisDatenDirektkandidaturen.getStimmenFuerDirektkandidatur(direktkandidatur, gebietUndStimmabgabeart);

          if (listenkandidaturZuDirektkandidatur != null && listenkandidaturZuDirektkandidatur.isAufStimmzettel()) {
            copy.parteiErststimmenNummerBewerber = listenkandidaturstimmeLabelGenerator.formatListenstimmeAnzahlGueltigeKennung(entityAufStimmzettelDaten, wahlvorschlagStimmzettelPosition,
                listenkandidaturZuDirektkandidatur);
          }
        }

        // Summe der Liste
        if (!listenkandidaturen.isEmpty() && isStimmenFuerListeAbzueglichStimmenFuerAlleListenkandidaturenRelevant(wahldurchfuehrungsgebiet)) {
          copy.listenkandidatStimmenQueueNummer.add("0");
          copy.listenkandidatStimmenQueueNummerMitPartei
              .add(listenkandidaturstimmeLabelGenerator.formatListenstimmeAnzahlGueltigeListeAbzueglichStimmenFuerAlleListenkandidaturenKennung(gruppeImGebiet, wahlvorschlagStimmzettelPosition));
          copy.listenkandidatStimmenQueueName.add("");
          copy.listenkandidatStimmenQueueAnzahlStimmen.add(ergebnisDatenListenkandidaturen.getStimmenFuerListeAbzueglichStimmenFuerAlleListenkandidaturen(politischeGruppe, gebietUndStimmabgabeart));
        }

        for (Listenkandidatur listenkandidatur : listenkandidaturen) {
          // NOTE: NICHT mit isZugelassen() einschränken, sonst zeigt die Landtagswahl-V5 keine Listenkandidaturen an
          if (!listenkandidatur.isNichtZugelassenImSinneAbgelehnt()) {
            copy.listenkandidatStimmenQueueNummer.add("" + listenkandidatur.getRelativePosition());
            copy.listenkandidatStimmenQueueNummerMitPartei
                .add(listenkandidaturstimmeLabelGenerator.formatListenstimmeAnzahlGueltigeKennung(entityAufStimmzettelDaten, wahlvorschlagStimmzettelPosition, listenkandidatur));

            if (listenkandidaturZuDirektkandidatur != null && listenkandidaturZuDirektkandidatur.equals(listenkandidatur)) {
              copy.listenkandidatStimmenQueueAnzahlStimmen.add(null);
              copy.listenkandidatStimmenQueueName.add(null);
            } else {
              copy.listenkandidatStimmenQueueAnzahlStimmen.add(ergebnisDatenListenkandidaturen.getStimmenFuerListenkandidatur(listenkandidatur, gebietUndStimmabgabeart));
              copy.listenkandidatStimmenQueueName.add(listenkandidatur.getFamilienname());
            }
          }
        }

        result.add(copy);
      }
    }

    return result;
  }

  protected boolean isStimmenFuerListeAbzueglichStimmenFuerAlleListenkandidaturenRelevant(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return EnumSet.of(CommonWahlart.LANDTAGSWAHL_BAYERN, CommonWahlart.BEZIRKSWAHL_BAYERN).stream().anyMatch(wahlart -> wahlart.equalsWahlart(wahldurchfuehrungsgebiet.getWahl()));
  }

  private Listenkandidatur getListenkandidaturZuDirektkandidatur(Direktkandidatur direktkandidatur, List<Listenkandidatur> listenkandidaturenFuerGruppe) {
    if (direktkandidatur == null) {
      return null;
    }

    Collection<PersonenVerknuepfung> personenVerknuepfungenDirektkandidat = direktkandidatur.getPersonenVerknuepfungen();

    for (Listenkandidatur listenkandidatur : listenkandidaturenFuerGruppe) {
      Collection<PersonenVerknuepfung> personenVerknuepfungenListenkandidat = listenkandidatur.getPersonenVerknuepfungen();

      for (PersonenVerknuepfung personenVerknuepfungDirektkandidat : personenVerknuepfungenDirektkandidat) {
        if (personenVerknuepfungenListenkandidat.contains(personenVerknuepfungDirektkandidat)) {
          return listenkandidatur;
        }
      }
    }

    return null;
  }
}
