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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Transient;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.boundary.AbstractPolitischeGruppeDAO;
import de.ivu.elect.business.gruppe.control.GruppeByPositionComparator;
import de.ivu.elect.business.gruppeimgebiet.boundary.AbstractGruppeImGebietDAO;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.wahlvorschlag.boundary.AbstractWahlvorschlagDAO;
import de.ivu.elect.business.wahlvorschlag.entity.Direktkandidat;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOption;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.jee.entity.customdata.CustomData;

public abstract class AbstractPolitischeGruppe extends Gruppe implements PolitischeGruppeBase {

  /*
   * WASDE-2031
   */
  public static final String TRANSIENT_CONTEXT_KEY_EINZELBEWERBER_FAMILIENNAME = "EINZELBEWERBER_FAMILIENNAME";
  public static final String TRANSIENT_CONTEXT_KEY_EINZELBEWERBER_VORNAMEN = "EINZELBEWERBER_VORNAMEN";
  public static final String TRANSIENT_CONTEXT_KEY_EINZELBEWERBER_GEBIETSNUMMER = "EINZELBEWERBER_GEBIETSNUMMER";

  private static final long serialVersionUID = 1L;

  public AbstractPolitischeGruppe() {
    super();
  }

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

  public AbstractPolitischeGruppe(AbstractPolitischeGruppe gruppe) {
    super(gruppe);
  }

  public boolean hatWahlvorschlag(AbstractWahlvorschlagDAO wahlvorschlagDAO) {
    return !wahlvorschlagDAO.findByGruppe(this).isEmpty();
  }

  @Transient
  private transient Set<Liste> listenCache;

  @Deprecated // Zu langsam, nicht verwenden(!)
  public Collection<Liste> getListen() {
    if (listenCache == null) {
      listenCache = new HashSet<>();
      for (GruppeImGebiet gruppeImGebiet : getGruppenImGebiet()) {
        listenCache.addAll(gruppeImGebiet.getListen());
      }
    }

    return listenCache;
  }

  @Transient
  private transient Set<Direktkandidat> direktkandidatenCache;

  @Deprecated // Zu langsam, nicht verwenden(!)
  public Collection<Direktkandidat> getDirektkandidaten() {
    if (direktkandidatenCache == null) {

      direktkandidatenCache = new HashSet<>();

      for (GruppeImGebiet gruppeImGebiet : getGruppenImGebiet()) {
        direktkandidatenCache.addAll(gruppeImGebiet.getDirektkandidaten());
      }
    }
    return direktkandidatenCache;
  }

  @Deprecated // Zu langsam, nicht verwenden(!)
  public Collection<ReferendumOption> getReferendumOptionen() {
    Set<ReferendumOption> result = new HashSet<>();

    for (GruppeImGebiet gruppeImGebiet : getGruppenImGebiet()) {
      result.addAll(gruppeImGebiet.getReferendumOptionen());
    }

    return result;
  }

  @Override
  protected boolean isPolitischeGruppeInternal() {
    return true;
  }

  public static List<PolitischeGruppe> getPolitischeGruppenAufGebietSortiertNachPosition(Gebiet gebiet, AbstractPolitischeGruppeDAO politischeGruppeDAO, AbstractGruppeImGebietDAO gruppeImGebietDAO) {
    if (gebiet == null) {
      return new ArrayList<>();
    }

    List result = politischeGruppeDAO.findByWahl(gebiet.getWahl());
    List<GruppeImGebiet> gruppenImGebiet = gruppeImGebietDAO.findByGebiet(gebiet);
    Collections.sort(result, new GruppeByPositionComparator(gruppenImGebiet));
    return result;
  }

  @Override
  public boolean hatZugelassenenDirektkandidatInGebietshierarchie(Gebiet gebiet, Map<Gruppe, Set<Wahlvorschlag>> alleWahlvorschlaegeNachGruppe) {
    for (Wahlvorschlag wahlvorschlag : alleWahlvorschlaegeNachGruppe.get(this)) {
      if (wahlvorschlag.isDirektkandidat() && wahlvorschlag.isZugelassen()
          && (wahlvorschlag.getGebiet().equals(gebiet) || wahlvorschlag.getGebiet().isUntergebietVon(gebiet) || gebiet.isUntergebietVon(wahlvorschlag.getGebiet()))) {
        return true;
      }
    }

    return false;
  }

  @Override
  public boolean hatListeInGebietshierarchie(Gebiet gebiet, Map<Gruppe, Set<Wahlvorschlag>> alleWahlvorschlaegeNachGruppe) {
    for (Wahlvorschlag wahlvorschlag : alleWahlvorschlaegeNachGruppe.get(this)) {
      if (wahlvorschlag.isListe() && (wahlvorschlag.getGebiet().equals(gebiet) || wahlvorschlag.getGebiet().isUntergebietVon(gebiet) || gebiet.isUntergebietVon(wahlvorschlag.getGebiet()))) {
        return true;
      }
    }

    return false;
  }

  public boolean hatWahlvorschlagInGebietOderDarunter(Gebiet gebiet, Map<Gruppe, Set<Wahlvorschlag>> alleWahlvorschlaegeNachGruppe) {
    return alleWahlvorschlaegeNachGruppe.getOrDefault(this, Collections.emptySet()/*ELECTBB-557*/).stream()
        .anyMatch(wahlvorschlag -> wahlvorschlag.getGebiet().equals(gebiet) || wahlvorschlag.getGebiet().isUntergebietVon(gebiet));
  }
}
