
package de.ivu.elect.sitzberechnung.verteilung.trivial;

import java.util.ArrayList;
import java.util.List;

import de.ivu.elect.sitzberechnung.math.FractionConverter;
import de.ivu.elect.sitzberechnung.math.NachStimmenSortierer;
import de.ivu.elect.sitzberechnung.verteilung.AbstractVerteilung;
import de.ivu.elect.sitzberechnung.verteilung.Teilnehmer;
import de.ivu.elect.sitzberechnung.verteilung.VerteilungContext;

/**
 * Implementation einer trivialen Verteilung nach Anzahl der Stimmen pro Teilnehmer.
 *
 * <p>
 * Die Verteilung von Restsitzen per Los ist nicht enthalten. Es werden im Ergebnisobjekt lediglich die dafür erforderlichen Informationen geliefert.
 */
public class NachStimmenVerteilung extends AbstractVerteilung<NachStimmenTeilnehmerErgebnis, NachStimmenErgebnis> {

  public NachStimmenVerteilung() {
    super(FractionConverter.convertingExakt());
  }

  @Override
  protected NachStimmenErgebnis verteileSitzeKeineSitze(VerteilungContext context, List< ? extends Teilnehmer> teilnehmerInVerteilung) {
    return NachStimmenErgebnis.ohneVerteilung(context, teilnehmerInVerteilung);
  }

  @Override
  protected NachStimmenErgebnis verteileSitzeKeineStimmen(VerteilungContext context, List< ? extends Teilnehmer> teilnehmerInVerteilung) {
    return NachStimmenErgebnis.ohneVerteilung(context, teilnehmerInVerteilung);
  }

  @Override
  protected NachStimmenErgebnis verteileSitze(VerteilungContext context, List< ? extends Teilnehmer> teilnehmerInVerteilung) {
    long anzahlSitze = context.getAnzahlSitze();

    NachStimmenSortierer<Teilnehmer> anzahlStimmenSortierer = new NachStimmenSortierer<>(anzahlSitze);

    for (Teilnehmer teilnehmer : teilnehmerInVerteilung) {
      long anzahlStimmen = context.getFractionConverter().asFractionConverted(teilnehmer.getStimmen()).longValue();

      anzahlStimmenSortierer.add(anzahlStimmen, teilnehmer);
    }

    List<NachStimmenTeilnehmerErgebnis> teilnehmerErgebnisseMitSitz = new ArrayList<>();

    for (Teilnehmer teilnehmer : anzahlStimmenSortierer.getVordere()) {
      teilnehmerErgebnisseMitSitz.add(new NachStimmenTeilnehmerErgebnis(teilnehmer, true));
    }

    List<NachStimmenTeilnehmerErgebnis> teilnehmerErgebnisseImLosverfahren = new ArrayList<>();

    for (Teilnehmer teilnehmer : anzahlStimmenSortierer.getUnentschiedene()) {
      NachStimmenTeilnehmerErgebnis teilnehmerErgebnis = new NachStimmenTeilnehmerErgebnis(teilnehmer, false);
      teilnehmerErgebnis.seiTeilnehmerAmLosverfahren();

      teilnehmerErgebnisseImLosverfahren.add(teilnehmerErgebnis);
    }

    List<NachStimmenTeilnehmerErgebnis> teilnehmerErgebnisseOhneSitz = new ArrayList<>();

    for (Teilnehmer teilnehmer : anzahlStimmenSortierer.getHintere()) {
      teilnehmerErgebnisseOhneSitz.add(new NachStimmenTeilnehmerErgebnis(teilnehmer, false));
    }

    List<NachStimmenTeilnehmerErgebnis> teilnehmerErgebnisse = new ArrayList<>();
    teilnehmerErgebnisse.addAll(teilnehmerErgebnisseMitSitz);
    teilnehmerErgebnisse.addAll(teilnehmerErgebnisseImLosverfahren);
    teilnehmerErgebnisse.addAll(teilnehmerErgebnisseOhneSitz);

    long anzahlSitzeZuVerlosen = anzahlSitze - teilnehmerErgebnisseMitSitz.size();

    if (anzahlSitze > teilnehmerErgebnisse.size()) {
      anzahlSitzeZuVerlosen = 0L;
    }

    return new NachStimmenErgebnis(context, anzahlSitzeZuVerlosen, teilnehmerErgebnisse, teilnehmerErgebnisseMitSitz, teilnehmerErgebnisseImLosverfahren, teilnehmerErgebnisseOhneSitz);
  }
}
