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

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import javax.annotation.Nullable;
import javax.persistence.Transient;

public abstract class AbstractGebietsgruppierung implements GebietsgruppierungBase {

  private static final long serialVersionUID = 1L;

  /**
   * @return die Gebiete, aus denen ich bestehe, die also direkt zugeordnet sind.
   */
  public Set<Gebiet> getGebiete() {
    return getGebiets();
  }

  @Transient
  private transient Map<GebietPK, Boolean> isEnthaeltGebietOderUebergeordnetesGebietVonCache;

  /**
   * Testet die Zugehörigkeit eines Gebiets zur Gebietsgruppierung, wenn man Gebietsgruppierungen mit der Semantik
   * verwendet, dass sich die Zugehörigkeit eines Gebiets zu einer Gebietsgruppierung automatisch auf die unterliegenden
   * Gebiete vererbt.
   *
   * @return true, wenn gebiet oder ein übergeordnetes Gebiet von gebiet zu meinen Gebieten gehört
   */
  public boolean isEnthaeltGebietOderUebergeordnetesGebietVon(Gebiet gebiet) {
    if (gebiet == null) {
      return false;
    }

    if (isEnthaeltGebietOderUebergeordnetesGebietVonCache == null) {
      isEnthaeltGebietOderUebergeordnetesGebietVonCache = new HashMap<>();
    }
    return isEnthaeltGebietOderUebergeordnetesGebietVonCache.computeIfAbsent(gebiet.getPk(),
        x -> getGebiete().contains(gebiet) || gebiet.getInGebietshierarchieUebergeordneteGebiete().stream().anyMatch(g -> getGebiete().contains(g)));
  }

  @Transient
  private transient List<Gebiet> zugeordneteGebieteFuerCreate = new ArrayList<>();

  @Deprecated // ELECT-4674 nur bei CreateView nutzen
  public Collection<Gebiet> getZugeordneteGebieteFuerCreate() {
    return zugeordneteGebieteFuerCreate;
  }

  @Deprecated // ELECT-4674 nur bei CreateView nutzen
  public void setZugeordneteGebieteFuerCreate(List<Gebiet> zugeordneteGebieteFuerCreate) {
    this.zugeordneteGebieteFuerCreate = zugeordneteGebieteFuerCreate;
  }

  public static Predicate<Gebiet> getGebietsgruppierungFilter(@Nullable Gebietsgruppierung gebietsgruppierung) {
    return gebiet -> gebietsgruppierung == null || gebietsgruppierung.isEnthaeltGebietOderUebergeordnetesGebietVon(gebiet);
  }

}
