
package de.ivu.elect.dokumente.ergebnis;

import java.util.LinkedList;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import de.ivu.document.generator.template.BaseDocument;
import de.ivu.document.generator.template.annotations.DocumentQueue;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.kandidatur.control.NlStimmzettelFormatter;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatter;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.wahlvorschlag.entity.NlListe;

public class NlKandidatStimmenDocument extends BaseDocument {

  private static final long serialVersionUID = 1L;

  @DocumentSimpleField("ID")
  public final Long id;

  @DocumentSimpleField(value = "isGewaehlt")
  public final Boolean isEndgueltigGewaehlt;

  @DocumentSimpleField(value = "isUeberVorzugGewaehlt")
  public final Boolean isUeberVorzugGewaehlt;

  @DocumentSimpleField("GesamteStimmenzahl")
  public final Long anzahlStimmen;

  @DocumentSimpleField("Listenposition")
  public final Long listenposition;

  @DocumentSimpleField("StimmzettelNamenFormatiert")
  public final String nameAufStimmzettelFormatted;

  @DocumentQueue(value = "StimmenProGebiet", elementClass = Long.class)
  public final LinkedList<Long> kandidatStimmenProGebiet;

  @DocumentSimpleField(value = "Wohnort")
  public final String wohnort;

  @DocumentSimpleField(value = "Rang")
  public final Long rang;

  @DocumentSimpleField(value = "isGewaehltAufStel")
  public final Boolean isAufStelGewaehlt;

  @DocumentSimpleField(value = "Stelnummer")
  public final Integer stelnummer;

  @DocumentSimpleField(value = "Gebietsnummer")
  public final String gebietsnummer;

  @DocumentSimpleField(value = "IsGewaehltInStelOderWahlkreis")
  public final String gewaehltIn;

  private final Listenkandidatur listenkandidatur;

  public NlKandidatStimmenDocument(Gewaehlt gewaehlt, StimmzettelFormatter stimmzettelFormatter, Long anzahlStimmen, LinkedList<Long> kandidatStimmenProGebiet, boolean isUeberVorzugGewaehlt) {
    super();

    this.listenkandidatur = gewaehlt.getKandidatur().castTo(Listenkandidatur.class).getEntity();

    this.id = listenkandidatur.getId();

    this.isEndgueltigGewaehlt = gewaehlt.getGewaehltStatus().isGewaehlt();

    if (isKandidatAufEinzelnenGebiet(kandidatStimmenProGebiet)) {
      // nur die Gesamte Stimmenzahlen der Kandiaten werden in der Tabelle angezeigt
      this.kandidatStimmenProGebiet = createEmptyList(kandidatStimmenProGebiet);
    } else {
      this.kandidatStimmenProGebiet = kandidatStimmenProGebiet;
    }

    if (stimmzettelFormatter instanceof NlStimmzettelFormatter) {
      this.nameAufStimmzettelFormatted = ((NlStimmzettelFormatter) stimmzettelFormatter).formatKandidaturNamenInDokument(listenkandidatur);
    } else {
      this.nameAufStimmzettelFormatted = stimmzettelFormatter.formatKandidaturNamen(listenkandidatur);
    }

    this.anzahlStimmen = anzahlStimmen;
    this.listenposition = listenkandidatur.getRelativePosition();
    this.wohnort = listenkandidatur.getAnschrift().getOrt();
    this.rang = gewaehlt.getRang();
    this.isUeberVorzugGewaehlt = isUeberVorzugGewaehlt;
    Optional<Integer> stelNummer = NlListe.getStelNummerWas(listenkandidatur.getListe());

    if (stelNummer.isPresent()) {
      this.stelnummer = stelNummer.get();
      this.gewaehltIn = "Stel " + stelNummer.get();
      this.gebietsnummer = null;
    } else {
      this.gebietsnummer = gewaehlt.getGebiet().getNummer();
      this.gewaehltIn = "Kieskring " + this.gebietsnummer;
      this.stelnummer = null;
    }

    this.isAufStelGewaehlt = stelNummer.isPresent();
  }

  public Listenkandidatur getListenkandidatur() {
    return listenkandidatur;
  }

  private boolean isKandidatAufEinzelnenGebiet(LinkedList<Long> kandidatStimmenProGebiet) {
    return kandidatStimmenProGebiet.stream().filter(Objects::nonNull).count() == 1;
  }

  private LinkedList<Long> createEmptyList(LinkedList<Long> kandidatStimmenProGebiet) {
    return IntStream.range(0, kandidatStimmenProGebiet.size()).<Long> mapToObj(i -> null).collect(Collectors.toCollection(LinkedList::new));
  }
}
