
package de.ivu.elect.sitzberechnung.konflikt;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toSet;

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

import com.google.gson.Gson;

import de.ivu.elect.sitzberechnung.Gebiet;
import de.ivu.elect.sitzberechnung.SitzberechnungEntity;
import de.ivu.elect.sitzberechnung.SitzeZuteilungArt;

public class ErgebnisKonfliktSitzeZuteilungArtenAuswaehlen extends AbstractErgebnisKonfliktEntitiesAuswaehlen {

  private final List<String> sitzeZuteilungArtenEntityKeys;

  private final List<SitzeZuteilungArt> sitzeZuteilungArtenAuswaehlbar;

  private final List<SitzeZuteilungArt> sitzeZuteilungArtenAusgewaehlt;

  private ErgebnisKonfliktSitzeZuteilungArtenAuswaehlen(String wahlgebietKey, String wahlvorschlaggebietKey, Enum< ? > typ, ErgebnisKonfliktStatus ergebnisKonfliktStatus, long anzahlAuszuwaehlen,
      List<String> sitzeZuteilungArtenEntityKeys, List<SitzeZuteilungArt> sitzeZuteilungArtenAuswaehlbar, List<SitzeZuteilungArt> sitzeZuteilungArtenAusgewaehlt) {
    super(wahlgebietKey, wahlvorschlaggebietKey, typ, ergebnisKonfliktStatus, anzahlAuszuwaehlen);

    this.sitzeZuteilungArtenEntityKeys = sitzeZuteilungArtenEntityKeys;

    this.sitzeZuteilungArtenAuswaehlbar = sitzeZuteilungArtenAuswaehlbar;
    this.sitzeZuteilungArtenAusgewaehlt = sitzeZuteilungArtenAusgewaehlt;
  }

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

  public List<String> getSitzeZuteilungArtenEntityKeys() {
    return sitzeZuteilungArtenEntityKeys;
  }

  public List<SitzeZuteilungArt> getSitzeZuteilungArtenAuswaehlbar() {
    return sitzeZuteilungArtenAuswaehlbar;
  }

  public List<SitzeZuteilungArt> getSitzeZuteilungArtenAusgewaehlt() {
    return sitzeZuteilungArtenAusgewaehlt;
  }

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

  protected boolean isFachlichGleich(ErgebnisKonfliktSitzeZuteilungArtenAuswaehlen other) {
    return super.isFachlichGleich(other) && other.getSitzeZuteilungArtenEntityKeys().size() == getSitzeZuteilungArtenEntityKeys().size()
        && other.getSitzeZuteilungArtenEntityKeys().containsAll(getSitzeZuteilungArtenEntityKeys()) && other.getSitzeZuteilungArtenAuswaehlbar().size() == getSitzeZuteilungArtenAuswaehlbar().size()
        && other.getSitzeZuteilungArtenAuswaehlbar().containsAll(getSitzeZuteilungArtenAuswaehlbar());
  }

  public <E extends SitzberechnungEntity> List<E> filterSitzeZuteilungArtenAuswaehlbar(Collection<E> entities) {
    return filterEntitiesByEntityKeys(entities, getSitzeZuteilungArtenAuswaehlbar().stream().map(SitzeZuteilungArt::getKey).collect(toSet()));
  }

  public <E extends SitzberechnungEntity> List<E> filterSitzeZuteilungArtenAusgewaehlt(Collection<E> entities) {
    return filterEntitiesByEntityKeys(entities, getSitzeZuteilungArtenAusgewaehlt().stream().map(SitzeZuteilungArt::getKey).collect(toSet()));
  }

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

  public static String toJson(ErgebnisKonfliktSitzeZuteilungArtenAuswaehlen ergebnisKonflikt) {
    ErgebnisKonfliktEntitiesDaten daten = new ErgebnisKonfliktEntitiesDaten();
    daten.setWahlgebietKey(ergebnisKonflikt.getWahlgebietKey());
    daten.setWahlvorschlaggebietKey(ergebnisKonflikt.getWahlvorschlaggebietKey());
    daten.setLosentscheidTyp(ergebnisKonflikt.getLosentscheidTyp());
    daten.setAnzahlAuszuwaehlen(ergebnisKonflikt.getAnzahlAuszuwaehlen());
    daten.setErgebnisKonfliktStatus(ergebnisKonflikt.getErgebnisKonfliktStatus());
    daten.setSitzeZuteilungArtenEntityKeys(ergebnisKonflikt.getSitzeZuteilungArtenEntityKeys());
    daten.setSitzeZuteilungArtenAuswaehlbar(ergebnisKonflikt.getSitzeZuteilungArtenAuswaehlbar());
    daten.setSitzeZuteilungArtenAusgewaehlt(ergebnisKonflikt.getSitzeZuteilungArtenAusgewaehlt());

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

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

    if (daten != null && !daten.isEmpty()) {
      return newInstance(daten.getWahlgebietKey(), daten.getWahlvorschlaggebietKey(), daten.getLosentscheidTyp(), daten.getErgebnisKonfliktStatus(), daten.getAnzahlAuszuwaehlen(),
          daten.getSitzeZuteilungArtenEntityKeys(), daten.getSitzeZuteilungArtenAuswaehlbar(), daten.getSitzeZuteilungArtenAusgewaehlt());
    }

    return null;
  }

  public static ErgebnisKonfliktSitzeZuteilungArtenAuswaehlen newInstance(Gebiet wahlgebiet, Gebiet wahlvorschlaggebiet, Enum< ? > typ, long anzahlAuszuwaehlen, Gebiet gebiet,
      SitzberechnungEntity sitzeZuteilungArtenEntity, List<SitzeZuteilungArt> sitzeZuteilungArtenAuswaehlbar) {
    return newInstance(wahlgebiet == null ? "" : wahlgebiet.getKey(), wahlvorschlaggebiet == null ? "" : wahlvorschlaggebiet.getKey(), typ, ErgebnisKonfliktStatus.UNGELOEST, anzahlAuszuwaehlen,
        asList(gebiet.getKey(), sitzeZuteilungArtenEntity.getKey()), sitzeZuteilungArtenAuswaehlbar, emptyList());
  }

  public static ErgebnisKonfliktSitzeZuteilungArtenAuswaehlen newInstance(String wahlgebietKey, String wahlvorschlaggebietKey, Enum< ? > typ, ErgebnisKonfliktStatus ergebnisKonfliktStatus,
      long anzahlAuszuwaehlen, List<String> sitzeZuteilungArtenEntityKeys, List<SitzeZuteilungArt> sitzeZuteilungArtenAuswaehlbar, List<SitzeZuteilungArt> sitzeZuteilungArtenAusgewaehlt) {
    return new ErgebnisKonfliktSitzeZuteilungArtenAuswaehlen(wahlgebietKey, wahlvorschlaggebietKey, typ, ergebnisKonfliktStatus, anzahlAuszuwaehlen, sitzeZuteilungArtenEntityKeys,
        sitzeZuteilungArtenAuswaehlbar, sitzeZuteilungArtenAusgewaehlt);
  }
}
