
package de.ivu.elect.business.sitzberechnung.control.direktwahl;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import de.ivu.elect.sitzberechnung.math.NachStimmenSortierer;

import de.ivu.elect.business.ergebnis.control.ErgebnisDatenQuorum;
import de.ivu.elect.business.ergebnis.entity.ErgebnisLogEintragArt;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.ergebnis.entity.GewaehltStatus;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.sitzberechnung.control.util.SitzberechnungProGebietHelper;
import de.ivu.elect.business.sitzberechnung.entity.SitzberechnungsalgorithmusKonfiguration;
import de.ivu.elect.business.sitzberechnung.entity.Sitzberechnungseingabe;
import de.ivu.elect.util.NotNull;

public class StandardDirektwahlMitQuorumSitzberechnungsalgorithmusInternal extends AbstractStandardDirektwahlSitzberechnungsalgorithmusInternal {

  public StandardDirektwahlMitQuorumSitzberechnungsalgorithmusInternal(Sitzberechnungseingabe<SitzberechnungsalgorithmusKonfiguration> sitzberechnungseingabe, boolean sitzeVergeben) {
    super(sitzberechnungseingabe, sitzeVergeben);
  }

  @Override
  protected void markiereGewaehlte(SitzberechnungProGebietHelper helper, Wahldurchfuehrungsgebiet direktwahlgebiet, NachStimmenSortierer<Direktkandidatur> sortierer) {
    ErgebnisDatenQuorum ergebnisDatenQuorum = getErgebnisDatenQuorumWahlberechtigte(sitzberechnungseingabe);

    if (!ergebnisDatenQuorum.isProzentsatzVorhanden()) {
      helper.log(ErgebnisLogEintragArt.WARNUNG, "sitzberechnung.algorithmus.mehrheitswahl.noch.kein.quorum", direktwahlgebiet.getName());

      return;
    }

    if (!ergebnisDatenQuorum.isGrundwertVorhanden(direktwahlgebiet)) {
      helper.log(ErgebnisLogEintragArt.WARNUNG, "sitzberechnung.algorithmus.mehrheitswahl.noch.keine.anzahl.wahlberechtigte.gesamt", direktwahlgebiet.getName());

      return;
    }

    long anzahlStimmenLautQuorumMinimal = getAnzahlStimmenLautQuorumMinimal(sitzberechnungseingabe, direktwahlgebiet);

    helper.log(ErgebnisLogEintragArt.INFO, "sitzberechnung.algorithmus.mehrheitswahl.anzahl.stimmen.quorum", direktwahlgebiet.getName(), anzahlStimmenLautQuorumMinimal,
        ergebnisDatenQuorum.getProzentsatzFormatted(Locale.getDefault()));

    Map<Direktkandidatur, Long> anzahlStimmenQuorumErreichtPerDirektkandidatur = new HashMap<>();
    Map<Direktkandidatur, Long> anzahlStimmenQuorumVerfehltPerDirektkandidatur = new HashMap<>();

    for (Entry<Long, List<Direktkandidatur>> entry : sortierer.getAlleGruppiert().entrySet()) {
      long anzahlStimmen = NotNull.notNull(entry.getKey());
      boolean anzahlStimmenLautQuorumMinimalErreicht = anzahlStimmenLautQuorumMinimal > 0 && anzahlStimmen >= anzahlStimmenLautQuorumMinimal;

      for (Direktkandidatur direktkandidatur : entry.getValue()) {
        if (anzahlStimmenLautQuorumMinimalErreicht) {
          anzahlStimmenQuorumErreichtPerDirektkandidatur.put(direktkandidatur, anzahlStimmen);
        } else {
          anzahlStimmenQuorumVerfehltPerDirektkandidatur.put(direktkandidatur, anzahlStimmen);
        }
      }
    }

    super.markiereGewaehlte(helper, direktwahlgebiet, sortierer);

    for (Gewaehlt gewaehlt : helper.getGewaehlte()) {
      if (gewaehlt.getGewaehltStatus().isGewaehlt()) {
        Kandidatur kandidatur = gewaehlt.getKandidatur();

        if (kandidatur != null) {
          if (anzahlStimmenQuorumErreichtPerDirektkandidatur.containsKey(kandidatur)) {
            Long anzahlStimmen = NotNull.notNull(anzahlStimmenQuorumErreichtPerDirektkandidatur.get(kandidatur));

            helper.log(ErgebnisLogEintragArt.INFO, "sitzberechnung.algorithmus.mehrheitswahl.kandidat.gewinnt", direktwahlgebiet.getName(), helper.displayPerson(kandidatur), anzahlStimmen);
          } else if (anzahlStimmenQuorumVerfehltPerDirektkandidatur.containsKey(kandidatur)) {
            Long anzahlStimmen = NotNull.notNull(anzahlStimmenQuorumVerfehltPerDirektkandidatur.get(kandidatur));

            helper.log(ErgebnisLogEintragArt.WARNUNG, "sitzberechnung.algorithmus.mehrheitswahl.kandidat.gewinnt.quorum.verfehlt", direktwahlgebiet.getName(), helper.displayPerson(kandidatur),
                anzahlStimmen, anzahlStimmenLautQuorumMinimal);

            gewaehlt.setGewaehltStatus(GewaehltStatus.NICHT_GEWAEHLT);
          }
        }
      }

      // GewaehltStatus#LOS_OFFEN impliziert Konklikte... erstmal losen lassen, anstatt die Konflikte hier aufzuräumen...

      // GewaehltStatus#NACHRUECKER wird nicht vergeben...

      // GewaehltStatus#NICHT_GEWAEHLT passt...
    }
  }
}
