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

import java.util.*;

import de.ivu.elect.business.gebietsbaum.boundary.AbstractWahldurchfuehrungsgebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.boundary.AbstractPolitischeGruppeDAO;
import de.ivu.elect.business.gruppe.entity.GruppePK;
import de.ivu.elect.business.kandidatur.boundary.AbstractKandidaturDAO;
import de.ivu.elect.business.person.entity.PersonendatenPK;
import de.ivu.elect.business.wahlvorschlag.boundary.AbstractListenverbindungDAO;
import de.ivu.elect.business.wahlvorschlag.boundary.AbstractWahlvorschlagDAO;
import de.ivu.elect.business.wahlvorschlag.entity.ListenverbindungPK;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagPK;
import de.ivu.elect.jee.faces.Messages;

/**
 * CustomData für {@link ErgebnisKonflikt}e, bei dem aus {@link Gebiet}en ausgelost wird. Ob die Reihenfolge eine Rolle
 * spielt, hängt von der Unterklasse ab.
 * 
 *
 */
public abstract class AbstractGebieteErgebnisKonfliktCustomData extends AbstractErgebnisKonfliktLosoptionenCustomData {

  private static final long serialVersionUID = 1L;

  private Set<GebietPK> beteiligteGebietPKs = new LinkedHashSet<>();
  private Set<GebietPK> gelosteGebietPKs = new LinkedHashSet<>();

  @Override
  protected Collection<PersonendatenPK> getBeteiligteKandidaturenPKs() {
    return Collections.emptySet();
  }

  @Override
  protected Collection<PersonendatenPK> getGelosteKandidaturenPKs() {
    return Collections.emptySet();
  }

  @Override
  protected Collection<WahlvorschlagPK> getBeteiligteListenPKs() {
    return Collections.emptySet();
  }

  @Override
  protected Collection<WahlvorschlagPK> getGelosteListenPKs() {
    return Collections.emptySet();
  }

  @Override
  protected Collection<ListenverbindungPK> getBeteiligteListenverbindungenPKs() {
    return Collections.emptySet();
  }

  @Override
  protected Collection<ListenverbindungPK> getGelosteListenverbindungenPKs() {
    return Collections.emptySet();
  }

  @Override
  public Set<GruppePK> getBeteiligtePolitischeGruppenPKs() {
    return Collections.emptySet();
  }

  @Override
  public Collection<GruppePK> getGelostePolitischeGruppenPKs() {
    return Collections.emptySet();
  }

  @Override
  public Set<GebietPK> getBeteiligteGebietPKs() {
    return beteiligteGebietPKs;
  }

  public void setBeteiligteGebietPKs(Set<GebietPK> beteiligteGebietPKs) {
    this.beteiligteGebietPKs = new LinkedHashSet<>(beteiligteGebietPKs);

    notifyEntity();
  }

  @Override
  public Set<GebietPK> getGelosteGebietPKs() {
    return gelosteGebietPKs;
  }

  public void setGelosteGebietPKs(Collection<GebietPK> gelosteGebietPKs) {
    this.gelosteGebietPKs = new LinkedHashSet<>(gelosteGebietPKs);

    notifyEntity();
  }

  public void setBeteiligteGebiete(Collection< ? extends Gebiet> beteiligteGebiete) {
    Set<GebietPK> pks = new LinkedHashSet<>();
    for (Gebiet gebiet : beteiligteGebiete) {
      pks.add(gebiet.getPk());
    }
    setBeteiligteGebietPKs(pks);
  }

  @Override
  public List<ErgebnisKonfliktLosoption> getLosoptionenVerfuegbar(AbstractWahlvorschlagDAO wahlvorschlagDao,
                                                                  AbstractKandidaturDAO kandidaturDao, AbstractListenverbindungDAO listenverbindungDao,
                                                                  AbstractPolitischeGruppeDAO politischeGruppeDAO, AbstractWahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO, Messages messages) {
    return createLosoptionen(wahldurchfuehrungsgebietDAO, getBeteiligteGebietPKs());
  }

  @Override
  public List<ErgebnisKonfliktLosoption> getLosoptionenGelost(AbstractWahlvorschlagDAO wahlvorschlagDao,
                                                              AbstractKandidaturDAO kandidaturDao, AbstractListenverbindungDAO listenverbindungDao,
                                                              AbstractPolitischeGruppeDAO politischeGruppeDAO, AbstractWahldurchfuehrungsgebietDAO wahldurchfuehrungsgebietDAO, Messages messages) {
    return createLosoptionen(wahldurchfuehrungsgebietDAO, getGelosteGebietPKs());
  }

  @Override
  public void setLosoptionenGelost(List<ErgebnisKonfliktLosoption> losoptionenGelost) {
    Set<GebietPK> result = new LinkedHashSet<>();

    for (ErgebnisKonfliktLosoption losoption : losoptionenGelost) {
      if (losoption.isInstanceOf(Gebiet.class)) {
        result.add((GebietPK) losoption.getPk());
      }
    }

    setGelosteGebietPKs(result);
  }

  /**
   * equals() bezieht sich nur auf die Attribute, die die zu entscheidene Situation beschreiben, aber nicht auf die
   * Attribute, die die Lösung / Auswahl / Entscheidung betreffen.
   * 
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }

    if (!(o instanceof AbstractGebieteErgebnisKonfliktCustomData)) {
      return false;
    }

    // Gleichheit: Gleicher Typ und gleiche Alternativen

    AbstractGebieteErgebnisKonfliktCustomData that = (AbstractGebieteErgebnisKonfliktCustomData) o;
    if (this.getAnzahlZuLosen() != that.getAnzahlZuLosen()) {
      return false;
    }

    // alle Alternativen müssen übereinstimmen
    return this.beteiligteGebietPKs.equals(that.beteiligteGebietPKs);
  }

  @Override
  public int hashCode() {
    int result = (int) (getAnzahlZuLosen() ^ getAnzahlZuLosen() >>> 32);
    return 31 * result + beteiligteGebietPKs.hashCode();
  }

  //**************** Erzeugen einer Beschreibung des Konflikts bzw. der Lösung ***********************//

  public String createLoesungBeschreibung(Collection<Wahldurchfuehrungsgebiet> gebiete, Collection<GebietPK> gebietPKs) {
    return createLoesungBeschreibung(mapEntityPerPk(gebiete), gebietPKs);
  }

  private String createLoesungBeschreibung(Map<GebietPK, Wahldurchfuehrungsgebiet> gebietPerPk,
      Collection<GebietPK> gebietPKs) {
    Collection<String> result = new ArrayList<>();

    for (GebietPK gebietPK : gebietPKs) {
      result.add(createGebietDisplayName(gebietPerPk.get(gebietPK)));
    }

    return joinErgebnisKonfliktLoesungItems(result);
  }

  public String createErgebnisKonfliktBeschreibung(String typBeschreibung, List<Wahldurchfuehrungsgebiet> gebiete) {
    return typBeschreibung + ": " + createErgebnisKonfliktBeschreibung(gebiete);
  }

  public String createErgebnisKonfliktBeschreibung(Collection<Wahldurchfuehrungsgebiet> gebiete) {
    Collection<String> result = new ArrayList<>();

    for (Wahldurchfuehrungsgebiet gebiet : gebiete) {
      result.add(createGebietDisplayName(gebiet));
    }

    return joinErgebnisKonfliktBeschreibungItems(result);
  }

}
