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

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.validation.constraints.Null;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.ergebnis.entity.DHondtQuotient;
import de.ivu.elect.business.ergebnis.entity.ErgebnisLogEintrag;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.ergebnis.entity.Sitze;
import de.ivu.elect.business.ergebniskonflikt.control.util.ErgebnisKonfliktLoeser;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.sitzberechnung.control.varianten.VariantenStatistik;

public class Sitzberechnungsergebnis {

  public static final Sitzberechnungsergebnis KEIN_ERGEBNIS = new Sitzberechnungsergebnis(
      Collections.<Sitze>emptyList(), Collections.<Gewaehlt>emptyList(), Collections.<ErgebnisKonflikt>emptyList(),
      Collections.<ErgebnisLogEintrag>emptyList(), null);

  private final List<Sitze> sitze;

  private final List<Gewaehlt> gewaehlte;

  private final List<ErgebnisKonflikt> konflikte;

  private final List<ErgebnisLogEintrag> ergebnisLogEintraege;

  private final List<DHondtQuotient> dHondtQuotienten;

  private final Map<ErgebnisKonflikt, HinweisAnVariantenberechner> hinweiseAnVariantenberechner;

  private final Map<ErgebnisKonflikt, ErgebnisKonfliktLoeser> konfliktLoeserMap;

  private final List<VariantenStatistik> variantenStatistiken;

  private final List<String> bemerkungen;

  private final List<String> customDataList;

  public String getBemerkung() {
    return String.join(" - ", getBemerkungen());
  }

  public static Sitzberechnungsergebnis createLeeresErgebnis() {
    return new Sitzberechnungsergebnis(keineSitze(), new ArrayList<Gewaehlt>(), new ArrayList<ErgebnisKonflikt>(),
        keinErgebnisLog(), null);
  }

  @Deprecated // Unfug
  public static ArrayList<Sitze> keineSitze() {
    return new ArrayList<>();
  }

  @Deprecated // Unfug
  public static ArrayList<ErgebnisLogEintrag> keinErgebnisLog() {
    return new ArrayList<>();
  }

  @Deprecated // Unfug
  public static ArrayList<DHondtQuotient> keineDHondtQuotienten() {
    return new ArrayList<>();
  }

  /**
   * public static Sitzberechnungsergebnis createLeeresErgebnis() { return new Sitzberechnungsergebnis(keineSitze(), new
   * ArrayList<Gewaehlt>(), new ArrayList<ErgebnisKonflikt>(), keinErgebnisLog(), null); }
   * 
   * Ergebnis ohne Log, ohne D'Hondt, ohne Hinweise an Variantenberechner
   */
  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte, String bemerkung) {
    this(sitze, gewaehlte, konflikte, keinErgebnisLog(), bemerkung);
  }

  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte, @Nullable String bemerkung, @Nullable String customData) {
    this(sitze, gewaehlte, konflikte, keinErgebnisLog(), bemerkung, customData);
  }

  /**
   * Ergebnis ohne D'Hondt, ohne Hinweise an Variantenberechner
   */
  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
      List<ErgebnisLogEintrag> ergebnisLogEintraege, @Nullable String bemerkung) {
    this(sitze, gewaehlte, konflikte, ergebnisLogEintraege, keineDHondtQuotienten(), bemerkung);
  }

  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
      List<ErgebnisLogEintrag> ergebnisLogEintraege, @Nullable String bemerkung, @Nullable String customData) {
    this(sitze, gewaehlte, konflikte, ergebnisLogEintraege, keineDHondtQuotienten(), bemerkung, customData);
  }

  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
      List<ErgebnisLogEintrag> ergebnisLogEintraege, VariantenStatistik variantenStatistik,  @Nullable String bemerkung) {
    this(sitze, gewaehlte, konflikte, ergebnisLogEintraege, keineDHondtQuotienten(), variantenStatistik, bemerkung);
  }

  /**
   * Ergebnis ohne Hinweise an Variantenberechner
   */
  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
      List<ErgebnisLogEintrag> ergebnisLogEintraege, List<DHondtQuotient> dHondtQuotienten, @Nullable String bemerkung) {
    this(sitze, gewaehlte, konflikte, new HashMap<>(), new HashMap<>(), ergebnisLogEintraege, dHondtQuotienten, null, bemerkung, null);
  }

  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
      List<ErgebnisLogEintrag> ergebnisLogEintraege, List<DHondtQuotient> dHondtQuotienten, @Nullable String bemerkung, @Nullable String customData) {
    this(sitze, gewaehlte, konflikte, new HashMap<>(), new HashMap<>(), ergebnisLogEintraege, dHondtQuotienten, null, bemerkung, customData);
  }

  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
      List<ErgebnisLogEintrag> ergebnisLogEintraege, List<DHondtQuotient> dHondtQuotienten, VariantenStatistik variantenStatistik, @Nullable String bemerkung) {
    this(sitze, gewaehlte, konflikte, new HashMap<>(), new HashMap<>(), ergebnisLogEintraege, dHondtQuotienten, variantenStatistik, bemerkung, null);
  }

  /**
   * Ergebnis ohne D'Hondt
   */
  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
      Map<ErgebnisKonflikt, HinweisAnVariantenberechner> hinweiseAnVariantenberechner,
      Map<ErgebnisKonflikt, ErgebnisKonfliktLoeser> konfliktLoeserMap, List<ErgebnisLogEintrag> ergebnisLogEintraege,
      @Nullable String bemerkung) {
    this(sitze, gewaehlte, konflikte, hinweiseAnVariantenberechner, konfliktLoeserMap, ergebnisLogEintraege,
        keineDHondtQuotienten(), null, bemerkung, null);
  }

  /**
   * Ergebnis komplett
   */
  public Sitzberechnungsergebnis(List<Sitze> sitze, List<Gewaehlt> gewaehlte, List<ErgebnisKonflikt> konflikte,
                                 Map<ErgebnisKonflikt, HinweisAnVariantenberechner> hinweiseAnVariantenberechner,
                                 Map<ErgebnisKonflikt, ErgebnisKonfliktLoeser> konfliktLoeserMap, List<ErgebnisLogEintrag> ergebnisLogEintraege,
                                 List<DHondtQuotient> dHondtQuotienten, @Nullable VariantenStatistik variantenStatistik, @Nullable String bemerkung, @Nullable String customData) {
    this.sitze = sitze;
    this.gewaehlte = gewaehlte;
    this.konflikte = konflikte;
    this.hinweiseAnVariantenberechner = new HashMap<>(hinweiseAnVariantenberechner);
    this.konfliktLoeserMap = new HashMap<>(konfliktLoeserMap);
    this.ergebnisLogEintraege = ergebnisLogEintraege;
    this.dHondtQuotienten = dHondtQuotienten;
    this.bemerkungen = new ArrayList<>();
    this.variantenStatistiken = new ArrayList<>();
    if (variantenStatistik != null) {
      this.variantenStatistiken.add(variantenStatistik);
    }
    if (StringUtils.isNotBlank(bemerkung)) {
      this.bemerkungen.add(bemerkung);
    }
    this.customDataList = new ArrayList<>();
    if (StringUtils.isNotBlank(customData)) {
      this.customDataList.add(customData);
    }
  }

  public List<Sitze> getSitze() {
    return sitze;
  }

  public List<Gewaehlt> getGewaehlte() {
    return gewaehlte;
  }

  public List<ErgebnisKonflikt> getKonflikte() {
    return konflikte;
  }

  public Map<ErgebnisKonflikt, HinweisAnVariantenberechner> getHinweiseAnVariantenberechner() {
    return hinweiseAnVariantenberechner;
  }

  public Map<ErgebnisKonflikt, ErgebnisKonfliktLoeser> getKonfliktLoeserMap() {
    return konfliktLoeserMap;
  }

  public List<ErgebnisLogEintrag> getErgebnisLogEintraege() {
    return ergebnisLogEintraege;
  }

  public List<DHondtQuotient> getDHondtQuotienten() {
    return dHondtQuotienten;
  }

  public void addAll(Sitzberechnungsergebnis other) {
    this.sitze.addAll(other.getSitze());
    this.gewaehlte.addAll(other.getGewaehlte());
    this.konflikte.addAll(other.getKonflikte());
    this.konfliktLoeserMap.putAll(other.getKonfliktLoeserMap());
    this.hinweiseAnVariantenberechner.putAll(other.getHinweiseAnVariantenberechner());
    this.ergebnisLogEintraege.addAll(other.getErgebnisLogEintraege());
    this.dHondtQuotienten.addAll(other.getDHondtQuotienten());
    this.variantenStatistiken.addAll(other.getVariantenStatistiken());
    this.bemerkungen.addAll(other.getBemerkungen());
    this.customDataList.addAll(other.getCustomDataList());
  }

  public List<VariantenStatistik> getVariantenStatistiken() {
    return variantenStatistiken;
  }

  public List<String> getBemerkungen() {
    return bemerkungen;
  }

  public List<String> getCustomDataList() {
    return customDataList;
  }

}
