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

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

import java.util.Collection;
import java.util.EnumMap;
import java.util.List;

import de.ivu.elect.business.gebietsbaum.entity.EntityMitGebiet;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.unterstuetzer.control.EintragungslisteEintragByPositionComparator;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlvorschlag.entity.EntityMitWahlvorschlag;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;

public abstract class AbstractEintragungsliste implements EintragungslisteBase, EntityMitWahlvorschlag, EntityMitGebiet {

  private static final long serialVersionUID = 1L;

  private transient EnumMap<EintragungslisteEintragGueltigkeit, Long> anzahlEintragungslisteEintraegePerGueltigkeit;

  protected AbstractEintragungsliste() {
    super();

    this.anzahlEintragungslisteEintraegePerGueltigkeit = new EnumMap<>(EintragungslisteEintragGueltigkeit.class);
  }

  public long getTransientAnzahlEintragungslisteEintraegeGueltigkeitErfasst() {
    return stream(EintragungslisteEintragGueltigkeit.values()).filter(EintragungslisteEintragGueltigkeit::isErfasst).mapToLong(this::getTransientAnzahlEintragungslisteEintraegePerGueltigkeit).sum();
  }

  public long getTransientAnzahlEintragungslisteEintraegeGesamt() {
    return anzahlEintragungslisteEintraegePerGueltigkeit.values().stream().mapToLong(value -> value).sum();
  }

  public long getTransientAnzahlEintragungslisteEintraegePerGueltigkeit(EintragungslisteEintragGueltigkeit eintragungslisteEintragGueltigkeit) {
    return anzahlEintragungslisteEintraegePerGueltigkeit.getOrDefault(eintragungslisteEintragGueltigkeit, 0L);
  }

  public void updateTransientAnzahlEintragungslisteEintraegePerGueltigkeit(EintragungslisteEintragGueltigkeit eintragungslisteEintragGueltigkeit, long anzahl) {
    anzahlEintragungslisteEintraegePerGueltigkeit.put(eintragungslisteEintragGueltigkeit, anzahl);
  }

  public boolean hasWahl() {
    return getWahl() != null;
  }

  public Wahl getWahl() {
    Wahlvorschlag wahlvorschlag = getWahlvorschlag();

    if (wahlvorschlag != null) {
      return wahlvorschlag.getWahl();
    }

    return null;
  }

  @Override
  public Gebiet getGebiet() {
    Wahlvorschlag wahlvorschlag = getWahlvorschlag();

    if (wahlvorschlag != null) {
      return wahlvorschlag.getGebiet();
    }

    return null;
  }

  @Override
  public boolean hasWahlvorschlag() {
    return getWahlvorschlag() != null;
  }

  public Long getAnzahlEintragungslisteEintraegeErwartet() {
    Wahl wahl = getWahl();

    if (wahl != null) {
      return wahl.getAnzahlUnterstuetzerPerEintragungsliste();
    }

    return 0L;
  }

  public EintragungslisteEintrag getEintragungslisteEintrag(Long position) {
    if (position != null) {
      return getEintragungslisteEintraege().stream().filter(eintragungslisteEintrag -> eintragungslisteEintrag.getPosition().longValue() == position.longValue()).findFirst().orElse(null);
    }

    return null;
  }

  public boolean hasEintragungslisteEintraege() {
    return !getEintragungslisteEintraege().isEmpty();
  }

  public List<EintragungslisteEintrag> getEintragungslisteEintraegeSortedByPosition() {
    return getEintragungslisteEintraege().stream().sorted(new EintragungslisteEintragByPositionComparator()).collect(toList());
  }

  public Collection<EintragungslisteEintrag> getEintragungslisteEintraege() {
    return getEintragungslisteEintragsByEintragungsliste();
  }
}
