
package de.ivu.elect.business.sitzberechnung.control.varianten;

import java.math.BigInteger;

import de.ivu.elect.business.ergebnis.control.StimmergebnisDaten;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.sitzberechnung.entity.SitzberechnungsalgorithmusKonfiguration;
import de.ivu.elect.business.sitzberechnung.entity.Sitzberechnungseingabe;
import de.ivu.elect.business.sitzberechnung.entity.Sitzberechnungsergebnis;

class SitzberechnungseingabeUndErgebnis<K extends SitzberechnungsalgorithmusKonfiguration> {

  private final Sitzberechnungseingabe<K> sitzberechnungseingabe;
  private Sitzberechnungsergebnis sitzberechnungsergebnis;
  private final BigInteger zaehltFuerAnzahlVarianten;
  private final Integer vorgabeBeiZyklischerLoesung;

  SitzberechnungseingabeUndErgebnis(Sitzberechnungseingabe<K> sitzberechnungseingabe,
      BigInteger zaehltFuerAnzahlVarianten) {
    this(sitzberechnungseingabe, zaehltFuerAnzahlVarianten, null);
  }

  SitzberechnungseingabeUndErgebnis(Sitzberechnungseingabe<K> sitzberechnungseingabe,
      BigInteger zaehltFuerAnzahlVarianten, Integer vorgabeBeiZyklischerLoesung) {
    this.sitzberechnungseingabe = sitzberechnungseingabe;
    this.zaehltFuerAnzahlVarianten = zaehltFuerAnzahlVarianten;
    this.vorgabeBeiZyklischerLoesung = vorgabeBeiZyklischerLoesung;
  }

  public void fuehreSitzberechnungDurch(Sitzberechnung<K> kern, boolean mitProtokoll) {
    sitzberechnungseingabe.getKonfiguration().setProtokollErstellen(mitProtokoll);
    sitzberechnungsergebnis = kern.fuehreSitzberechnungDurch(sitzberechnungseingabe);
  }

  public boolean sindAlleKonflikteGeloest() {
    for (ErgebnisKonflikt konflikt : sitzberechnungsergebnis.getKonflikte()) {
      if (!konflikt.isGeloest()) {
        return false;
      }
    }
    return true;
  }

  public Sitzberechnungseingabe<K> getSitzberechnungseingabe() {
    return sitzberechnungseingabe;
  }

  public StimmergebnisDaten getStimmergebnisDaten() {
    return sitzberechnungseingabe.getStimmergebnisDaten();
  }

  public Sitzberechnungsergebnis getSitzberechnungsergebnis() {
    return sitzberechnungsergebnis;
  }

  /**
   * @return eines der Arrays [0], [1] oder [0, 1]
   */
  public int[] getErforderlicheZyklischeLoesungen() {
    if (vorgabeBeiZyklischerLoesung == null) {
      return new int[] {0, 1};
    } else {
      return new int[] {vorgabeBeiZyklischerLoesung.intValue()};
    }
  }

  public Integer getVorgabeBeiZyklischerLoesung() {
    return vorgabeBeiZyklischerLoesung;
  }

  /**
   * Dient der Ermittlung der Anzahl Varianten, auch wenn nicht alle explizit berechnet werden.
   * zaehltFuerAnzahlVarianten gibt an, für wieviele Varianten diese Berechnung stellvertretend ausgeführt wird. Dies
   * ist normalerweise 1. Durch die Optimierung, die nur zwei zyklische Lösungen probiert, wird
   * zaehltFuerAnzahlVarianten bei der ersten zyklischen Lösung mit der Anzahl der möglichen Alternativen bzw. bei der
   * zweiten zyklischen Lösung mit 0 mulitipiziert.
   * 
   * @return die Anzahl Varianten, für die diese Berechnung im Variantenbaum steht
   */
  public BigInteger getZaehltFuerAnzahlVarianten() {
    return zaehltFuerAnzahlVarianten;
  }

  /**
   * @return die Anzahl Konflikte, die durch den Variantenberechner gelöst wurden
   */
  public int getTiefeImVariantenbaum() {
    int count = 0;
    for (ErgebnisKonflikt konflikt : sitzberechnungsergebnis.getKonflikte()) {
      if (konflikt.isLoesungAusVariantenberechnung()) {
        count++;
      }
    }
    return count;
  }

}
