
package de.ivu.elect.sitzberechnung.konflikt;

import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;

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

import com.google.gson.Gson;

import de.ivu.elect.sitzberechnung.Gruppe;
import de.ivu.elect.sitzberechnung.Listenverbindung;
import de.ivu.elect.sitzberechnung.SitzberechnungEntity;

public class ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen extends AbstractErgebnisKonfliktEntitiesAuswaehlen {

  private final List<String> gruppeKeysAuswaehlbar;

  private final List<String> gruppeKeysAusgewaehlt;

  private final List<String> listenverbindungKeysAuswaehlbar;

  private final List<String> listenverbindungKeysAusgewaehlt;

  private ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen(Enum< ? > typ, ErgebnisKonfliktStatus ergebnisKonfliktStatus, long anzahlAuszuwaehlen, List<String> gruppeKeysAuswaehlbar,
      List<String> gruppeKeysAusgewaehlt, List<String> listenverbindungKeysAuswaehlbar, List<String> listenverbindungKeysAusgewaehlt) {
    super(typ, ergebnisKonfliktStatus, anzahlAuszuwaehlen);

    this.gruppeKeysAuswaehlbar = gruppeKeysAuswaehlbar;
    this.gruppeKeysAusgewaehlt = gruppeKeysAusgewaehlt;

    this.listenverbindungKeysAuswaehlbar = listenverbindungKeysAuswaehlbar;
    this.listenverbindungKeysAusgewaehlt = listenverbindungKeysAusgewaehlt;
  }

  @Override
  public ErgebnisKonfliktArt getErgebnisKonfliktArt() {
    return ErgebnisKonfliktArt.LOSENTSCHEID_AUSWAHL_GRUPPEN;
  }

  public List<String> getGruppeKeysAuswaehlbar() {
    return gruppeKeysAuswaehlbar;
  }

  public List<String> getGruppeKeysAusgewaehlt() {
    return gruppeKeysAusgewaehlt;
  }

  public List<String> getListenverbindungKeysAuswaehlbar() {
    return listenverbindungKeysAuswaehlbar;
  }

  public List<String> getListenverbindungKeysAusgewaehlt() {
    return listenverbindungKeysAusgewaehlt;
  }

  @Override
  public boolean isFachlichGleich(ErgebnisKonflikt other) {
    return other instanceof ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen && isFachlichGleich((ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen) other);
  }

  protected boolean isFachlichGleich(ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen other) {
    return other.getAnzahlAuszuwaehlen() == getAnzahlAuszuwaehlen() && other.getGruppeKeysAuswaehlbar().size() == getGruppeKeysAuswaehlbar().size()
        && other.getGruppeKeysAuswaehlbar().containsAll(getGruppeKeysAuswaehlbar()) && other.getListenverbindungKeysAuswaehlbar().size() == getListenverbindungKeysAuswaehlbar().size()
        && other.getListenverbindungKeysAuswaehlbar().containsAll(getListenverbindungKeysAuswaehlbar());
  }

  public <E extends SitzberechnungEntity> List<E> filterGruppenAuswaehlbar(Collection<E> entities) {
    return filterEntitiesByEntityKeys(entities, getGruppeKeysAuswaehlbar());
  }

  public <E extends SitzberechnungEntity> List<E> filterGruppenAusgewaehlt(Collection<E> entities) {
    return filterEntitiesByEntityKeys(entities, getGruppeKeysAusgewaehlt());
  }

  public <E extends SitzberechnungEntity> List<E> filterListenverbindungenAuswaehlbar(Collection<E> entities) {
    return filterEntitiesByEntityKeys(entities, getListenverbindungKeysAuswaehlbar());
  }

  public <E extends SitzberechnungEntity> List<E> filterListenverbindungenAusgewaehlt(Collection<E> entities) {
    return filterEntitiesByEntityKeys(entities, getListenverbindungKeysAusgewaehlt());
  }

  @Override
  public String toJson() {
    return toJson(this);
  }

  public static String toJson(ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen ergebnisKonflikt) {
    ErgebnisKonfliktEntitiesAuswaehlenDaten daten = new ErgebnisKonfliktEntitiesAuswaehlenDaten();
    daten.setLosentscheidTyp(ergebnisKonflikt.getLosentscheidTyp());
    daten.setAnzahlAuszuwaehlen(ergebnisKonflikt.getAnzahlAuszuwaehlen());
    daten.setErgebnisKonfliktStatus(ergebnisKonflikt.getErgebnisKonfliktStatus());
    daten.setGruppeKeysAuswaehlbar(ergebnisKonflikt.getGruppeKeysAuswaehlbar());
    daten.setGruppeKeysAusgewaehlt(ergebnisKonflikt.getGruppeKeysAusgewaehlt());
    daten.setListenverbindungKeysAuswaehlbar(ergebnisKonflikt.getListenverbindungKeysAuswaehlbar());
    daten.setListenverbindungKeysAusgewaehlt(ergebnisKonflikt.getListenverbindungKeysAusgewaehlt());

    return new Gson().toJson(daten);
  }

  public static ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen fromJson(String json) {
    ErgebnisKonfliktEntitiesAuswaehlenDaten daten = new Gson().fromJson(json, ErgebnisKonfliktEntitiesAuswaehlenDaten.class);

    if (daten != null && !daten.isEmpty()) {
      return newInstance(daten.getLosentscheidTyp(), daten.getErgebnisKonfliktStatus(), daten.getAnzahlAuszuwaehlen(), daten.getGruppeKeysAuswaehlbar(), daten.getGruppeKeysAusgewaehlt(),
          daten.getListenverbindungKeysAuswaehlbar(), daten.getListenverbindungKeysAusgewaehlt());
    }

    return null;
  }

  public static ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen newInstance(Enum< ? > typ, long anzahlAuszuwaehlen, List<Gruppe> gruppenAuswaehlbar,
      List<Listenverbindung> listenverbindungenAuswaehlbar) {
    return newInstance(typ, ErgebnisKonfliktStatus.UNGELOEST, anzahlAuszuwaehlen, gruppenAuswaehlbar.stream().map(SitzberechnungEntity::getKey).collect(toList()), emptyList(),
        listenverbindungenAuswaehlbar.stream().map(SitzberechnungEntity::getKey).collect(toList()), emptyList());
  }

  public static ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen newInstance(Enum< ? > typ, ErgebnisKonfliktStatus ergebnisKonfliktStatus, long anzahlAuszuwaehlen,
      List<String> gruppeKeysAuswaehlbar, List<String> gruppeKeysAusgewaehlt, List<String> listenverbindungKeysAuswaehlbar, List<String> listenverbindungKeysAusgewaehlt) {
    return new ErgebnisKonfliktGruppenUndListenverbindungenAuswaehlen(typ, ergebnisKonfliktStatus, anzahlAuszuwaehlen, gruppeKeysAuswaehlbar, gruppeKeysAusgewaehlt, listenverbindungKeysAuswaehlbar,
        listenverbindungKeysAusgewaehlt);
  }
}
