
package de.ivu.elect.dokumente;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.ivu.elect.business.gebietsbaum.boundary.AbstractGebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.gruppe.boundary.AbstractGruppeDAO;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.kandidatur.control.StimmzettelFormatter;
import de.ivu.elect.business.stimmzettel.boundary.AnzahlStimmenProWaehlerBestimmer;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlausschuss.boundary.AbstractWahlausschussEntschaedigungDAO;
import de.ivu.elect.business.wahlvorschlag.boundary.AbstractWahlvorschlagDAO;
import de.ivu.elect.business.wahlvorschlag.boundary.WahlvorschlagUnterstuetzerNotwendigErmittler;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;

public class CoreElectContext extends BaseElectContext {

  private static final long serialVersionUID = 1L;

  private final AnzahlStimmenProWaehlerBestimmer anzahlStimmenProWaehlerBestimmer;

  private final StimmzettelFormatter stimmzettelFormatter;

  private final AbstractGruppeDAO gruppeDAO;

  private final AbstractGebietDAO gebietDAO;

  private final AbstractWahlvorschlagDAO wahlvorschlagDAO;

  private final AbstractWahlausschussEntschaedigungDAO wahlausschussEntschaedigungDAO;

  private final WahlvorschlagUnterstuetzerNotwendigErmittler wahlvorschlagUnterstuetzerNotwendigErmittler;

  private final Map<GebietPK, Boolean> sitzverteilungMehrheitswahlPerGebietPk; // ELECT-13860

  public CoreElectContext(CoreElectContext other) {
    this(other, other.getAnzahlStimmenProWaehlerBestimmer(), other.getStimmzettelFormatter(), other.getGruppeDAO(), other.getGebietDAO(), other.getWahlausschussEntschaedigungDAO(),
        other.getWahlvorschlagDAO(), other.getWahlvorschlagUnterstuetzerNotwendigErmittler());
  }

  public CoreElectContext(BaseElectContext baseElectContext, AnzahlStimmenProWaehlerBestimmer anzahlStimmenProWaehlerBestimmer, StimmzettelFormatter stimmzettelFormatter, AbstractGruppeDAO gruppeDAO,
      AbstractGebietDAO gebietDAO, AbstractWahlausschussEntschaedigungDAO wahlausschussEntschaedigungDAO, AbstractWahlvorschlagDAO wahlvorschlagDAO,
      WahlvorschlagUnterstuetzerNotwendigErmittler wahlvorschlagUnterstuetzerNotwendigErmittler) {
    super(baseElectContext);

    this.anzahlStimmenProWaehlerBestimmer = anzahlStimmenProWaehlerBestimmer;

    this.stimmzettelFormatter = stimmzettelFormatter;

    this.gruppeDAO = gruppeDAO;
    this.gebietDAO = gebietDAO;
    this.wahlvorschlagDAO = wahlvorschlagDAO;

    this.wahlausschussEntschaedigungDAO = wahlausschussEntschaedigungDAO;
    this.wahlvorschlagUnterstuetzerNotwendigErmittler = wahlvorschlagUnterstuetzerNotwendigErmittler;

    this.sitzverteilungMehrheitswahlPerGebietPk = new HashMap<>();
  }

  @Override
  public Long getAnzahlStimmenProWaehlerMaximal(Gebiet gebiet) {
    return getAnzahlStimmenProWaehlerBestimmer().getAnzahlStimmenProWaehlerMaximal(gebiet);
  }

  public AnzahlStimmenProWaehlerBestimmer getAnzahlStimmenProWaehlerBestimmer() {
    return anzahlStimmenProWaehlerBestimmer;
  }

  public StimmzettelFormatter getStimmzettelFormatter() {
    return stimmzettelFormatter;
  }

  public AbstractGruppeDAO getGruppeDAO() {
    return gruppeDAO;
  }

  public AbstractGebietDAO getGebietDAO() {
    return gebietDAO;
  }

  public AbstractWahlvorschlagDAO getWahlvorschlagDAO() {
    return wahlvorschlagDAO;
  }

  public AbstractWahlausschussEntschaedigungDAO getWahlausschussEntschaedigungDAO() {
    return wahlausschussEntschaedigungDAO;
  }

  public WahlvorschlagUnterstuetzerNotwendigErmittler getWahlvorschlagUnterstuetzerNotwendigErmittler() {
    return wahlvorschlagUnterstuetzerNotwendigErmittler;
  }

  public boolean isSitzverteilungPerMehrheitswahl(GebietPK gebietPk) {
    return gebietPk != null && Boolean.TRUE.equals(sitzverteilungMehrheitswahlPerGebietPk.computeIfAbsent(gebietPk, pk -> {
      Gebiet gebiet = getGebietDAO().findByPrimaryKey(pk);

      return getAnzahlStimmenProWaehlerBestimmer().isSitzverteilungPerMehrheitswahl(gebiet, () -> getWahlvorschlaege(gebiet.getWahl()));
    }));
  }

  @Override
  public CoreElectCustomDataDocumentBuilder getCustomDataDocumentBuilder() {
    return (CoreElectCustomDataDocumentBuilder) super.getCustomDataDocumentBuilder();
  }

  public List<Gruppe> getGruppen(Wahl wahl) {
    String key = "CoreElectContext-Gruppen" + wahl.getId();
    List result = computeIfAbsent(key, List.class, x -> getGruppeDAO().findByWahl(wahl));
    return result;
  }

  public List<Gebiet> getGebiete(Wahl wahl) {
    String key = "CoreElectContext-Gebiete" + wahl.getId();
    List result = computeIfAbsent(key, List.class, x -> getGebietDAO().findByWahl(wahl));
    return result;
  }

  public List<Wahlvorschlag> getWahlvorschlaege(Wahl wahl) {
    String key = "CoreElectContext-Wahlvorschlaege" + wahl.getId();
    List result = computeIfAbsent(key, List.class, x -> getWahlvorschlagDAO().findByWahl(wahl));
    return result;
  }
}
