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

import java.util.ArrayList;
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.elect.business.dokumente.entity.DokumentVorlageArt;
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;

@Document(DokumentVorlageArt.GESAMTERGEBNIS_V7_DOKUMENT_PREFIX)
public class ErgebnisGesamtergebnisTabellarischDocument extends AbstractErgebnisTabellarischDocument<ErgebnisGesamtergebnisTabellarischDocumentZeile> {

  private static final long serialVersionUID = 1L;

  public final ErgebnisGesamtergebnisTabellarischDocumentDokumentVorlageArt dokumentVorlageArt;

  @DocumentRepeat(value = "Zeilen", elementClass = ErgebnisGesamtergebnisTabellarischDocumentZeile.class, itemName = "zeilenItem")
  public final List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilen;

  // Die Queues für die Überschriften
  @DocumentQueue(value = "ParteiStimmenSummeQueue-Nummer", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNummer;

  @DocumentQueue(value = "ParteiStimmenSummeQueue-Kennung", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueKennung;

  @DocumentQueue(value = "ParteiStimmenSummeQueue-NameGruppe", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameGruppe;

  @DocumentQueue(value = "ParteiStimmenSummeQueue-NameWahlvorschlag", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameWahlvorschlag;

  @DocumentQueue(value = "ParteiStimmenSummeQueue-NameDirektkandidat", elementClass = String.class)
  public final LinkedList<String> parteiStimmenSummeQueueNameDirektkandidat;

  @DocumentQueue(value = "ParteiStimmenSummeQueue-AnzahlErststimmen", elementClass = String.class)
  public final LinkedList<Long> parteiStimmenSummeQueueAnzahlErststimmen;

  @DocumentQueue(value = "ParteiStimmenSummeQueue-AnzahlZweitstimmen", elementClass = String.class)
  public final LinkedList<Long> parteiStimmenSummeQueueAnzahlZweitstimmen;

  // Eine einzelne Zeile mit den Summen
  @DocumentComplexField("Summen")
  public ErgebnisGesamtergebnisTabellarischDocumentZeileSummen ergebnisSummen;

  public ErgebnisGesamtergebnisTabellarischDocument(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, ErgebnisGesamtergebnisTabellarischDocumentDokumentVorlageArt dokumentVorlageArt,
      ErgebnisDocumentDatenGebietDocument datenGebiet, ErgebnisDocumentDatenArt datenArt) {
    super(baseElectContext, ergebnisart, datenGebiet, datenArt);

    this.dokumentVorlageArt = dokumentVorlageArt;

    this.zeilen = new ArrayList<>();

    this.parteiStimmenSummeQueueNummer = new LinkedList<>();
    this.parteiStimmenSummeQueueKennung = new LinkedList<>();
    this.parteiStimmenSummeQueueNameGruppe = new LinkedList<>();
    this.parteiStimmenSummeQueueNameWahlvorschlag = new LinkedList<>();
    this.parteiStimmenSummeQueueNameDirektkandidat = new LinkedList<>();
    this.parteiStimmenSummeQueueAnzahlErststimmen = new LinkedList<>();
    this.parteiStimmenSummeQueueAnzahlZweitstimmen = new LinkedList<>();
  }

  @Override
  public List<ErgebnisGesamtergebnisTabellarischDocumentZeile> getZeilen() {
    return zeilen;
  }

  public void removeAnzahlParteiEintraege(int anzahl) {
    // Naive Implementierung, kann sicher mit sublist verbesser werden
    for (int i = 0; i < anzahl; i++) {
      parteiStimmenSummeQueueNummer.poll();
      parteiStimmenSummeQueueKennung.poll();
      parteiStimmenSummeQueueNameGruppe.poll();
      parteiStimmenSummeQueueNameWahlvorschlag.poll();
      parteiStimmenSummeQueueNameDirektkandidat.poll();
      parteiStimmenSummeQueueAnzahlErststimmen.poll();
      parteiStimmenSummeQueueAnzahlZweitstimmen.poll();

      if (ergebnisSummen != null) {
        ergebnisSummen.parteiStimmenQueueNummer.poll();
        ergebnisSummen.parteiStimmenQueueKennung.poll();
        ergebnisSummen.parteiStimmenQueueNameGruppe.poll();
        ergebnisSummen.parteiStimmenQueueNameWahlvorschlag.poll();
        ergebnisSummen.parteiStimmenQueueNameDirektkandidat.poll();
        ergebnisSummen.parteiStimmenQueueAnzahlErststimmen.poll();
        ergebnisSummen.parteiStimmenQueueAnzahlZweitstimmen.poll();
      }
    }

    for (ErgebnisGesamtergebnisTabellarischDocumentZeile zeile : zeilen) {
      for (int j = 0; j < anzahl; j++) {
        zeile.parteiStimmenQueueNummer.poll();
        zeile.parteiStimmenQueueKennung.poll();
        zeile.parteiStimmenQueueNameGruppe.poll();
        zeile.parteiStimmenQueueNameWahlvorschlag.poll();
        zeile.parteiStimmenQueueNameDirektkandidat.poll();
        zeile.parteiStimmenQueueAnzahlErststimmen.poll();
        zeile.parteiStimmenQueueAnzahlZweitstimmen.poll();
      }
    }
  }

  public void berechnenSummen(List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilen) {
    if (ergebnisSummen == null) {
      Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = null; // ELECT-8094

      List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilenBerechenbar = filterZeilenBerechenbar(zeilen);

      if (!zeilenBerechenbar.isEmpty()) {
        wahldurchfuehrungsgebiet = zeilenBerechenbar.get(0).wahldurchfuehrungsgebiet;
      }

      ergebnisSummen = createDocumentZeileSummen(wahldurchfuehrungsgebiet);
    }

    ergebnisSummen.setSummen(zeilen);
  }

  public void berechneUeberschriftenQueue() {
    parteiStimmenSummeQueueNummer.clear();
    parteiStimmenSummeQueueKennung.clear();
    parteiStimmenSummeQueueNameGruppe.clear();
    parteiStimmenSummeQueueNameWahlvorschlag.clear();
    parteiStimmenSummeQueueNameDirektkandidat.clear();

    if (!zeilen.isEmpty()) { // ELECT-8775
      ErgebnisGesamtergebnisTabellarischDocumentZeile ersteZeile = zeilen.get(0);

      parteiStimmenSummeQueueNummer.addAll(ersteZeile.parteiStimmenQueueNummer);
      parteiStimmenSummeQueueKennung.addAll(ersteZeile.parteiStimmenQueueKennung);
      parteiStimmenSummeQueueNameGruppe.addAll(ersteZeile.parteiStimmenQueueNameGruppe);
      parteiStimmenSummeQueueNameWahlvorschlag.addAll(ersteZeile.parteiStimmenQueueNameWahlvorschlag);
      parteiStimmenSummeQueueNameDirektkandidat.addAll(ersteZeile.parteiStimmenQueueNameDirektkandidat);
    }

    List<ErgebnisGesamtergebnisTabellarischDocumentZeile> zeilenBerechenbar = filterZeilenBerechenbar(zeilen);

    parteiStimmenSummeQueueAnzahlErststimmen.clear();
    parteiStimmenSummeQueueAnzahlZweitstimmen.clear();

    if (!zeilenBerechenbar.isEmpty()) {
      ErgebnisGesamtergebnisTabellarischDocumentZeile ersteZeile = zeilenBerechenbar.get(0);

      for (Long value : ersteZeile.parteiStimmenQueueAnzahlErststimmen) {
        parteiStimmenSummeQueueAnzahlErststimmen.add(value == null ? null : 0L);
      }

      for (Long value : ersteZeile.parteiStimmenQueueAnzahlZweitstimmen) {
        parteiStimmenSummeQueueAnzahlZweitstimmen.add(value == null ? null : 0L);
      }
    }

    for (ErgebnisGesamtergebnisTabellarischDocumentZeile zeile : zeilenBerechenbar) {
      for (int i = 0; i < zeile.parteiStimmenQueueAnzahlErststimmen.size(); i++) {
        Long anzahlErststimmenSumme = parteiStimmenSummeQueueAnzahlErststimmen.get(i);
        Long anzahlErststimmenZeile = zeile.parteiStimmenQueueAnzahlErststimmen.get(i);

        if (anzahlErststimmenZeile != null) {
          if (anzahlErststimmenSumme == null) {
            parteiStimmenSummeQueueAnzahlErststimmen.set(i, anzahlErststimmenZeile);
          } else {
            parteiStimmenSummeQueueAnzahlErststimmen.set(i, anzahlErststimmenSumme + anzahlErststimmenZeile);
          }
        }
      }

      for (int i = 0; i < zeile.parteiStimmenQueueAnzahlZweitstimmen.size(); i++) {
        Long anzahlZweitstimmenSumme = parteiStimmenSummeQueueAnzahlZweitstimmen.get(i);
        Long anzahlZweitstimmenZeile = zeile.parteiStimmenQueueAnzahlZweitstimmen.get(i);

        if (anzahlZweitstimmenZeile != null) {
          if (anzahlZweitstimmenSumme == null) {
            parteiStimmenSummeQueueAnzahlZweitstimmen.set(i, anzahlZweitstimmenZeile);
          } else {
            parteiStimmenSummeQueueAnzahlZweitstimmen.set(i, anzahlZweitstimmenSumme + anzahlZweitstimmenZeile);
          }
        }
      }
    }
  }

  protected ErgebnisGesamtergebnisTabellarischDocumentZeileSummen createDocumentZeileSummen(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    return new ErgebnisGesamtergebnisTabellarischDocumentZeileSummen(ergebnisart, wahldurchfuehrungsgebiet);
  }

  public ErgebnisGesamtergebnisTabellarischDocument copy() {
    return copy(dokumentVorlageArt);
  }

  public ErgebnisGesamtergebnisTabellarischDocument copy(ErgebnisGesamtergebnisTabellarischDocumentDokumentVorlageArt dokumentVorlageArt) {
    return copyTo(new ErgebnisGesamtergebnisTabellarischDocument(baseElectContext, ergebnisart, dokumentVorlageArt, datenGebiet, datenArt));
  }

  protected ErgebnisGesamtergebnisTabellarischDocument copyTo(ErgebnisGesamtergebnisTabellarischDocument target) {
    super.copyTo(target);

    for (ErgebnisGesamtergebnisTabellarischDocumentZeile zeile : zeilen) {
      target.zeilen.add(zeile.copy());
    }

    target.parteiStimmenSummeQueueNummer.addAll(parteiStimmenSummeQueueNummer);
    target.parteiStimmenSummeQueueKennung.addAll(parteiStimmenSummeQueueKennung);
    target.parteiStimmenSummeQueueNameGruppe.addAll(parteiStimmenSummeQueueNameGruppe);
    target.parteiStimmenSummeQueueNameWahlvorschlag.addAll(parteiStimmenSummeQueueNameWahlvorschlag);
    target.parteiStimmenSummeQueueNameDirektkandidat.addAll(parteiStimmenSummeQueueNameDirektkandidat);
    target.parteiStimmenSummeQueueAnzahlErststimmen.addAll(parteiStimmenSummeQueueAnzahlErststimmen);
    target.parteiStimmenSummeQueueAnzahlZweitstimmen.addAll(parteiStimmenSummeQueueAnzahlZweitstimmen);

    if (ergebnisSummen != null) {
      target.ergebnisSummen = ergebnisSummen.copy();
    }

    return target;
  }
}
