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

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import de.ivu.document.generator.template.annotations.Document;
import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentQueue;
import de.ivu.document.generator.template.annotations.DocumentRepeat;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahl.entity.WahlartErgebnisart;
import de.ivu.elect.dokumente.BaseElectContext;
import de.ivu.elect.dokumente.ergebnis.AbstractErgebnisTabellarischDocument;
import de.ivu.elect.dokumente.ergebnis.ErgebnisDocumentDatenArt;
import de.ivu.elect.dokumente.ergebnis.ErgebnisDocumentDatenGebietDocument;
import de.ivu.elect.jee.entity.customdata.EmptyCustomData;

@Document(ReferendumErgebnisGesamtergebnisTabellarischDocument.DOKUMENT_PREFIX)
public class ReferendumErgebnisGesamtergebnisTabellarischDocument extends AbstractErgebnisTabellarischDocument<ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile> {

  private static final long serialVersionUID = 1L;

  public static final String DOKUMENT_PREFIX = "gesamtergebnis-v7-ve";

  @DocumentSimpleField("Name")
  public String name;

  @DocumentRepeat(value = "Metadaten-Zeilen", elementClass = ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile.class, itemName = "metadatenZeilenItem")
  public final List<ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile> metadatenZeilen;

  @DocumentComplexField("Metadaten-Summen")
  public ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile metadatenSummen;

  @DocumentRepeat(value = "Stimmergebnisse-Zeilen", elementClass = ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile.class, itemName = "stimmenZeilenItem")
  public final List<ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile> stimmenZeilen;

  @DocumentComplexField("Stimmergebnisse-Summen")
  public ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile stimmergebnisseSummen;

  @DocumentSimpleField("Spalten-Prefix")
  public String spaltenPrefix;

  @DocumentQueue(value = "Optionen-Label-Queue", elementClass = String.class)
  public LinkedList<String> labelDerOptionenQueue;

  @DocumentQueue(value = "Optionen-Kennwort-Queue", elementClass = String.class)
  public LinkedList<String> kennworteDerOptionenQueue;

  @DocumentQueue(value = "Optionen-Kuerzel-Queue", elementClass = String.class)
  public LinkedList<String> kuerzelDerOptionenQueue;

  @DocumentSimpleField("Kuerzel-Gueltige")
  public String kuerzelGueltigeStimmen;

  @DocumentSimpleField("Kuerzel-Ungueltige")
  public String kuerzelUngueltigeStimmen;

  @DocumentSimpleField("Kuerzel-Gesamt")
  public String kuerzelGesamtStimmen;

  @DocumentSimpleField("Vorlage-Schluessel")
  public String referendumVorlageSchluessel;

  @DocumentSimpleField("Vorlage-Position")
  public Long referendumVorlagePosition;

  @DocumentSimpleField("Vorlage-Name")
  public String referendumVorlageName;

  @DocumentSimpleField("Vorlage-Kurzname")
  public String referendumVorlageKurzname;

  /**
   * @deprecated
   * @see ReferendumErgebnisGesamtergebnisTabellarischDocument#referendumVorlagePosition
   */
  @Deprecated
  @DocumentSimpleField("Vorlage-Nummer-Fortaufend")
  public String volksentscheidNummer;

  public ReferendumErgebnisGesamtergebnisTabellarischDocument(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, ErgebnisDocumentDatenGebietDocument datenGebiet,
      ErgebnisDocumentDatenArt datenArt) {
    super(baseElectContext, ergebnisart, datenGebiet, datenArt);

    this.metadatenZeilen = new ArrayList<>();
    this.stimmenZeilen = new ArrayList<>();
    this.labelDerOptionenQueue = new LinkedList<>();
    this.kennworteDerOptionenQueue = new LinkedList<>();
    this.kuerzelDerOptionenQueue = new LinkedList<>();
  }

  @Override
  @Deprecated
  public List<ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile> getZeilen() {
    return new ArrayList<>();
  }

  public void brechneSummenMetadaten(List<ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile> alleMetadatenZeilen) {
    if (!alleMetadatenZeilen.isEmpty()) {
      metadatenSummen = new ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile(ergebnisart, new Wahldurchfuehrungsgebiet(EmptyCustomData.INSTANCE)); // TODO Summenzeile

      metadatenSummen.wahlberechtigteOhneWahlschein = 0L;
      metadatenSummen.wahlberechtigteMitWahlschein = 0L;
      metadatenSummen.wahlberechtigteNichtImWaehlerverzeichnis = 0L;
      metadatenSummen.wahlberechtigteGesamt = 0L;

      // ELECT-8018, LEGACY!!!
      metadatenSummen.a1 = 0L;
      metadatenSummen.a2 = 0L;
      metadatenSummen.a3 = 0L;
      metadatenSummen.a = 0L;

      metadatenSummen.waehlerOhneWahlschein = 0L;
      metadatenSummen.waehlerMitWahlschein = 0L;
      metadatenSummen.waehlerMitWahlscheinAnteilAusUrnenwahl = 0L;
      metadatenSummen.waehlerMitWahlscheinAnteilAusBriefwahl = 0L;
      metadatenSummen.waehlerGesamt = 0L;

      // ELECT-8018, LEGACY!!!
      metadatenSummen.b1 = 0L;
      metadatenSummen.b2 = 0L;
      metadatenSummen.b = 0L;

      metadatenSummen.stimmzettelGueltig = 0L;
      metadatenSummen.stimmzettelUngueltig = 0L;
      metadatenSummen.stimmzettelGesamt = 0L;

      for (ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile zeile : alleMetadatenZeilen) {
        metadatenSummen.wahlberechtigteOhneWahlschein += notNull(zeile.wahlberechtigteOhneWahlschein);
        metadatenSummen.wahlberechtigteMitWahlschein += notNull(zeile.wahlberechtigteMitWahlschein);
        metadatenSummen.wahlberechtigteNichtImWaehlerverzeichnis += notNull(zeile.wahlberechtigteNichtImWaehlerverzeichnis);
        metadatenSummen.wahlberechtigteGesamt += notNull(zeile.wahlberechtigteGesamt);

        // ELECT-8018, LEGACY!!!
        metadatenSummen.a1 += notNull(zeile.a1);
        metadatenSummen.a2 += notNull(zeile.a2);
        metadatenSummen.a3 += notNull(zeile.a3);
        metadatenSummen.a += notNull(zeile.a);

        metadatenSummen.waehlerOhneWahlschein += notNull(zeile.waehlerOhneWahlschein);
        metadatenSummen.waehlerMitWahlschein += notNull(zeile.waehlerMitWahlschein);
        metadatenSummen.waehlerMitWahlscheinAnteilAusUrnenwahl += notNull(zeile.waehlerMitWahlscheinAnteilAusUrnenwahl);
        metadatenSummen.waehlerMitWahlscheinAnteilAusBriefwahl += notNull(zeile.waehlerMitWahlscheinAnteilAusBriefwahl);
        metadatenSummen.waehlerGesamt += notNull(zeile.waehlerGesamt);

        // ELECT-8018, LEGACY!!!
        metadatenSummen.b1 += notNull(zeile.b1);
        metadatenSummen.b2 += notNull(zeile.b2);
        metadatenSummen.b += notNull(zeile.b);

        metadatenSummen.stimmzettelGueltig += notNull(zeile.stimmzettelGueltig);
        metadatenSummen.stimmzettelUngueltig += notNull(zeile.stimmzettelUngueltig);
        metadatenSummen.stimmzettelGesamt += notNull(zeile.stimmzettelGesamt);
      }
    }
  }

  private static Long notNull(Long aLong) {
    if (aLong == null) {
      return 0L;
    }
    return aLong;
  }

  public void brechneSummenStimmergebnis(List<ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile> alleStimmergebnisZeilen) {
    if (!alleStimmergebnisZeilen.isEmpty()) {
      stimmergebnisseSummen = new ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile(ergebnisart, new Wahldurchfuehrungsgebiet(EmptyCustomData.INSTANCE)); // TODO Summenzeile
      stimmergebnisseSummen.gueltigeStimmenInsgesamt = 0L;
      stimmergebnisseSummen.ungueltigeStimmen = 0L;
      stimmergebnisseSummen.abgegebeneStimmenInsgesamt = 0L;

      for (ReferendumErgebnisGesamtergebnisTabellarischDocumentZeile zeile : alleStimmergebnisZeilen) {
        addiereWerteDerZweitenListeAufErsteListe(stimmergebnisseSummen.gueltigeStimmenDerOptionen, zeile.gueltigeStimmenDerOptionen);
        stimmergebnisseSummen.gueltigeStimmenInsgesamt += notNull(zeile.gueltigeStimmenInsgesamt);
        stimmergebnisseSummen.ungueltigeStimmen += notNull(zeile.ungueltigeStimmen);
        stimmergebnisseSummen.abgegebeneStimmenInsgesamt += notNull(zeile.abgegebeneStimmenInsgesamt);
      }
    }
  }

  private void addiereWerteDerZweitenListeAufErsteListe(List<Long> summen, List<Long> summanden) {
    if (summen.isEmpty()) {
      summen.addAll(Collections.nCopies(summanden.size(), 0L));
    }

    if (summanden.size() != summen.size()) {
      throw new IllegalStateException("Unterschiedliche Größen: " + summen.size() + " != " + summanden.size());
    }

    for (int idx = 0; idx < summanden.size(); idx++) {
      summen.set(idx, summen.get(idx) + summanden.get(idx));
    }
  }
}
