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

import static java.util.stream.Collectors.toList;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import de.ivu.document.generator.template.BaseDocument;
import de.ivu.document.generator.template.annotations.Document;
import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentRepeat;
import de.ivu.elect.business.dokumente.entity.DokumentVorlageArt;
import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.entity.DHondtQuotientListenImGebiet;
import de.ivu.elect.business.ergebnis.entity.DHondtQuotientListenInGruppe;
import de.ivu.elect.business.ergebnis.entity.DHondtQuotientPolitischeGruppe;
import de.ivu.elect.business.ergebnis.entity.Stimmabgabeart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.internet.control.GebietUndStimmabgabeart;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.dokumente.CoreElectContext;
import de.ivu.elect.dokumente.wahlvorschlag.CoreWahlvorschlagsdatenDocument;

@Document(value = DokumentVorlageArt.DHONDT_SUB_TEMPLATE, isSubTemplate = true)
public class DHondtQuotientenDocument extends BaseDocument {

  private static final long serialVersionUID = 1L;

  @DocumentRepeat(value = "QuotientenNachPolitischerGruppe", elementClass = DHondtQuotientPolitischeGruppeDocument.class, itemName = "quotient")
  public final List<DHondtQuotientPolitischeGruppeDocument> dHondtQuotientPolitischeGruppe;

  @DocumentComplexField("QuotientenNachPolitischerGruppeTabelle")
  public final DHondtQuotientPolitischeGruppeTabelleDocument dHondtQuotientPolitischeGruppeTabelle;

  @DocumentRepeat(value = "QuotientenListenImGebiet", elementClass = DHondtQuotientListenImGebietDocument.class, itemName = "quotient")
  public final List<DHondtQuotientListenImGebietDocument> dHondtQuotientListenImGebiet;

  @DocumentRepeat(value = "QuotientenProGebietTabellen", elementClass = DHondtQuotientenProGebietDocument.class, itemName = "dHondtQuotientenProGebietTabelle")
  public final List<DHondtQuotientenProGebietDocument> dHondtQuotientenProGebietTabellen;

  @DocumentRepeat(value = "QuotientenListenInGruppe", elementClass = DHondtQuotientListenInGruppeDocument.class, itemName = "quotient")
  public final List<DHondtQuotientListenInGruppeDocument> dHondtQuotientListenInGruppe;

  @DocumentRepeat(value = "QuotientenProPolitischeGruppeTabellen", elementClass = DHondtQuotientenProPolitischeGruppeDocument.class, itemName = "dHondtQuotientenProPolitischeGruppeTabelle")
  public final List<DHondtQuotientenProPolitischeGruppeDocument> dHondtQuotientenProPolitischeGruppeTabellen;

  public DHondtQuotientenDocument(CoreElectContext coreElectContext, ErgebnisDaten ergebnisDaten, Map< ? extends Wahlvorschlag, ? extends CoreWahlvorschlagsdatenDocument> wahlvorschlagsdokumente) {
    super();

    Stimmabgabeart stimmabgabeart = Stimmabgabeart.GESAMT; // Quotienten werden für GESAMT berechnet, eine Aufschlüsselung ist daher nicht sinnvoll/möglich...

    Collection<DHondtQuotientPolitischeGruppe> dHondtQuotientenPolitischeGruppe = ergebnisDaten.getDHondtQuotientenPolitischeGruppeSortiertNachRang();

    this.dHondtQuotientPolitischeGruppe = createDHondtQuotientPolitischeGruppeDocuments(coreElectContext, dHondtQuotientenPolitischeGruppe, wahlvorschlagsdokumente);
    this.dHondtQuotientPolitischeGruppeTabelle = createDHondtQuotientPolitischeGruppeTabelleDocument(coreElectContext, ergebnisDaten, stimmabgabeart, dHondtQuotientenPolitischeGruppe);

    Map<Wahldurchfuehrungsgebiet, List<DHondtQuotientListenImGebiet>> dHondtQuotientenListenImGebiet = ergebnisDaten.getDHondtQuotientListenImGebiet();

    this.dHondtQuotientListenImGebiet = createDHondtQuotientListenImGebietDocuments(coreElectContext, dHondtQuotientenListenImGebiet, wahlvorschlagsdokumente);
    this.dHondtQuotientenProGebietTabellen = createDHondtQuotientenProGebietDocuments(coreElectContext, ergebnisDaten, stimmabgabeart, dHondtQuotientenListenImGebiet);

    Map<PolitischeGruppe, List<DHondtQuotientListenInGruppe>> dHondtQuotientenListenInGruppe = ergebnisDaten.getDHondtQuotientListenInGruppe();

    this.dHondtQuotientListenInGruppe = createDHondtQuotientListenInGruppeDocuments(coreElectContext, dHondtQuotientenListenInGruppe, wahlvorschlagsdokumente);
    this.dHondtQuotientenProPolitischeGruppeTabellen = createDHondtQuotientenProPolitischeGruppeDocuments(coreElectContext, ergebnisDaten, stimmabgabeart, dHondtQuotientenListenInGruppe);
  }

  private List<DHondtQuotientPolitischeGruppeDocument> createDHondtQuotientPolitischeGruppeDocuments(CoreElectContext coreElectContext,
      Collection<DHondtQuotientPolitischeGruppe> dHondtQuotientenPolitischeGruppe, Map< ? extends Wahlvorschlag, ? extends CoreWahlvorschlagsdatenDocument> wahlvorschlagsdokumente) {
    return dHondtQuotientenPolitischeGruppe.stream() //
        .map(entry -> new DHondtQuotientPolitischeGruppeDocument(coreElectContext, entry)) //
        .collect(toList());
  }

  private DHondtQuotientPolitischeGruppeTabelleDocument createDHondtQuotientPolitischeGruppeTabelleDocument(CoreElectContext coreElectContext, ErgebnisDaten ergebnisDaten,
      Stimmabgabeart stimmabgabeart, Collection<DHondtQuotientPolitischeGruppe> dHondtQuotientenPolitischeGruppe) {
    Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = ergebnisDaten.getWurzelgebiet();

    return new DHondtQuotientPolitischeGruppeTabelleDocument(coreElectContext, ergebnisDaten, new GebietUndStimmabgabeart(wahldurchfuehrungsgebiet, stimmabgabeart), dHondtQuotientenPolitischeGruppe);
  }

  private List<DHondtQuotientListenImGebietDocument> createDHondtQuotientListenImGebietDocuments(CoreElectContext coreElectContext,
      Map<Wahldurchfuehrungsgebiet, List<DHondtQuotientListenImGebiet>> dHondtQuotientenListenImGebiet,
      Map< ? extends Wahlvorschlag, ? extends CoreWahlvorschlagsdatenDocument> wahlvorschlagsdokumente) {
    return dHondtQuotientenListenImGebiet.entrySet().stream() //
        .flatMap(entry -> entry.getValue().stream()) //
        .map(entry -> new DHondtQuotientListenImGebietDocument(coreElectContext, entry, wahlvorschlagsdokumente)) //
        .collect(toList());
  }

  private List<DHondtQuotientenProGebietDocument> createDHondtQuotientenProGebietDocuments(CoreElectContext coreElectContext, ErgebnisDaten ergebnisDaten, Stimmabgabeart stimmabgabeart,
      Map<Wahldurchfuehrungsgebiet, List<DHondtQuotientListenImGebiet>> dHondtQuotientenListenImGebiet) {
    return dHondtQuotientenListenImGebiet.entrySet().stream() //
        .map(entry -> new DHondtQuotientenProGebietDocument(coreElectContext, ergebnisDaten, new GebietUndStimmabgabeart(entry.getKey(), stimmabgabeart), entry.getValue())) //
        .collect(toList());
  }

  private List<DHondtQuotientListenInGruppeDocument> createDHondtQuotientListenInGruppeDocuments(CoreElectContext coreElectContext,
      Map<PolitischeGruppe, List<DHondtQuotientListenInGruppe>> dHondtQuotientenListenInGruppe, Map< ? extends Wahlvorschlag, ? extends CoreWahlvorschlagsdatenDocument> wahlvorschlagsdokumente) {
    return dHondtQuotientenListenInGruppe.entrySet().stream() //
        .flatMap(entry -> entry.getValue().stream()) //
        .map(entry -> new DHondtQuotientListenInGruppeDocument(coreElectContext, entry, wahlvorschlagsdokumente)) //
        .collect(toList());
  }

  private List<DHondtQuotientenProPolitischeGruppeDocument> createDHondtQuotientenProPolitischeGruppeDocuments(CoreElectContext coreElectContext, ErgebnisDaten ergebnisDaten,
      Stimmabgabeart stimmabgabeart, Map<PolitischeGruppe, List<DHondtQuotientListenInGruppe>> dHondtQuotientenListenInGruppe) {
    Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = ergebnisDaten.getWurzelgebiet();

    return dHondtQuotientenListenInGruppe.entrySet().stream() //
        .map(entry -> new DHondtQuotientenProPolitischeGruppeDocument(coreElectContext, ergebnisDaten, new GebietUndStimmabgabeart(wahldurchfuehrungsgebiet, stimmabgabeart), entry.getKey(),
            entry.getValue())) //
        .collect(toList());
  }
}
