
package de.ivu.elect.business.kandidatur.entity;

import java.util.Set;
import java.util.stream.Collectors;

import javax.persistence.Transient;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettel;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStatus;
import de.ivu.elect.jee.entity.customdata.CustomData;

public abstract class AbstractListenkandidatur extends Kandidatur implements ListenkandidaturBase, EntityAufStimmzettel {

  private static final long serialVersionUID = 1L;

  /**
   * Hilfsvariable für das Anzeigen der fortlaufender Position in einer Reihenfolge.
   */
  @Transient
  private transient Long listenpositionFortlaufend = null;

  @Transient
  private transient ListenkandidaturStimmzettelPosition stimmzettelPosition = null;

  @Transient
  private transient boolean stimmzettelPositionBestimmt = false;

  public AbstractListenkandidatur() {
    super();
  }

  public AbstractListenkandidatur(CustomData customData) {
    super(customData);
  }

  @Override
  public Wahlvorschlag getWahlvorschlag() {
    return getListe();
  }

  @Override
  public boolean isListenkandidatur() {
    return true;
  }

  @Override
  public Listenkandidatur getListenkandidatur() {
    return (Listenkandidatur) this;
  }

  @Override
  public boolean isListenkandidaturMarkiertAlsErsatzkandidatur() {
    return getListenkandidaturArt().isErsatzkandidatur();
  }

  public Long getListenpositionFortlaufend() {
    return listenpositionFortlaufend;
  }

  public void setListenpositionFortlaufend(Long listenpositionFortlaufend) {
    this.listenpositionFortlaufend = listenpositionFortlaufend;
  }

  @Override
  protected void postSetKandidaturStatus(KandidaturStatus alterWert, KandidaturStatus neuerWert) {
    if (neuerWert != null && wertHatSichGeaendert(alterWert, neuerWert) && getListe() != null) {
      WahlvorschlagStatus wahlvorschlagStatus = getListe().getWahlvorschlagStatus();

      switch (neuerWert) {
        case OFFEN :
        case NICHT_ZUGELASSEN :
          if (getListe().isZugelassen()) {
            wahlvorschlagStatus = getListe().getWahlvorschlagStatusInitial();
          }

          break;
        case NICHT_MEHR_ZUGELASSEN_WEIL_ZULASSUNGSFAEHIGKEIT_VOR_ZULASSUNGSAUSSCHUSS_NICHT_VORLAG :
        case NICHT_MEHR_ZUGELASSEN_WEIL_ZULASSUNGSFAEHIGKEIT_NACH_ZULASSUNGSAUSSCHUSS_VERLOREN :
          wahlvorschlagStatus = WahlvorschlagStatus.ZUGELASSEN;

          break;
        default :
          break;
      }

      if (isEinzelbewerber()) { // ELECT-12034
        wahlvorschlagStatus = neuerWert.toWahlvorschlagStatus();
      }

      getListe().setWahlvorschlagStatus(wahlvorschlagStatus);
    }
  }

  protected Long preProcessRelativePosition(Long neuerWert) {
    return neuerWert;
  }

  protected void preSetRelativePosition(Long alterWert, Long neuerWert) {
    // nichts zu tun
  }

  protected void postSetRelativePosition(Long alterWert, Long neuerWert) {
    // ELECT-2759 TODO überdenken?
    if (neuerWert != null && getEingereichtePosition() == null) {
      setEingereichtePosition(neuerWert);
    }
  }

  @Transient
  private transient ListenkandidaturStimmzettelPosition stimmzettelPositionMitCache;

  public ListenkandidaturStimmzettelPosition getStimmzettelPositionMitCache(EntityAufStimmzettelDaten entityAufStimmzettelDaten) {
    if (stimmzettelPositionMitCache == null) {
      stimmzettelPositionMitCache = getStimmzettelPosition(entityAufStimmzettelDaten);
    }
    return stimmzettelPositionMitCache;
  }

  public ListenkandidaturStimmzettelPosition getStimmzettelPosition(EntityAufStimmzettelDaten entityAufStimmzettelDaten) {
    return getStimmzettelPosition(getGebiet(), entityAufStimmzettelDaten);
  }

  @Override
  public ListenkandidaturStimmzettelPosition getStimmzettelPosition(Gebiet gebiet, EntityAufStimmzettelDaten entityAufStimmzettelDaten) {
    if (!stimmzettelPositionBestimmt) {
      stimmzettelPosition = calculateStimmzettelPosition(gebiet, entityAufStimmzettelDaten);
      stimmzettelPositionBestimmt = true;
    }

    return stimmzettelPosition;
  }

  protected ListenkandidaturStimmzettelPosition calculateStimmzettelPosition(Gebiet gebiet, EntityAufStimmzettelDaten entityAufStimmzettelDaten) {
    return entityAufStimmzettelDaten.calculateStimmzettelPosition(gebiet, getListenkandidatur());
  }

  public boolean hasIdentischePersonenVerknuepfung(Direktkandidatur direktkandidatur) {
    return direktkandidatur.getIdentischVerknuepfteKandidaturen().contains(this);
  }

  @Transient
  private transient Set<Listenkandidatur> identischVerknuepfteListenkandidaturenCache;

  public Set<Listenkandidatur> getIdentischVerknuepfteListenkandidaturen() {
    if (identischVerknuepfteListenkandidaturenCache == null) {
      identischVerknuepfteListenkandidaturenCache = super.getIdentischVerknuepfteKandidaturen().stream()
          .filter(AbstractKandidatur::isListenkandidatur)
          .map(k -> k.castTo(Listenkandidatur.class).getEntity())
          .collect(Collectors.toSet());
    }
    return identischVerknuepfteListenkandidaturenCache;
  }
}
