
package de.ivu.elect.business.stimmeingabe.control.plausi;

import java.util.Collection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;

/**
 * Ergänzt in einer Summengleichung NUR die Summe oder NUR EINEN der Summanden, sodass die Summe stimmt.
 */
public class EinenWertErgaenzenderSummenFehlerBeheber implements StimmeingabePlausiFiktiveWerteFehlerBeheber {

  private static final Logger LOG = LoggerFactory.getLogger(EinenWertErgaenzenderSummenFehlerBeheber.class);

  private final Collection<Stimmeingabe> stimmeingabenSummand;

  // fallback
  private final StimmeingabePlausiFiktiveWerteFehlerBeheber alleSummandenKorrigierenderSummenFehlerBeheber;

  public EinenWertErgaenzenderSummenFehlerBeheber(Collection<Stimmeingabe> stimmeingabenSummand) {
    super();

    this.stimmeingabenSummand = stimmeingabenSummand;
    this.alleSummandenKorrigierenderSummenFehlerBeheber = new SummenRueckwaertsKorrigierenderFehlerBeheber(stimmeingabenSummand);
  }

  @Override
  public void behebeFehler(Stimmeingabe stimmeingabeSumme) throws StimmeingabePlausiFiktiveWerteFehlerNichtBehebbarException {
    if (!stimmeingabeSumme.hasAnzahlGroesserNull()) {
      stimmeingabeSumme.setAnzahl(getSummeAusStimmeingabenSummand());
    } else {
      korrigiereSummand(stimmeingabeSumme);
    }
  }

  protected void korrigiereSummand(Stimmeingabe stimmeingabeSumme) throws StimmeingabePlausiFiktiveWerteFehlerNichtBehebbarException {
    Stimmeingabe unbekannterSummand = null;
    long summeBekannteSummanden = 0L;

    for (Stimmeingabe stimmeingabeSummand : stimmeingabenSummand) {
      if (!stimmeingabeSummand.hasAnzahlGroesserNull()) {
        if (unbekannterSummand == null) {
          unbekannterSummand = stimmeingabeSummand;
        } else {
          throw new StimmeingabePlausiFiktiveWerteFehlerNichtBehebbarException(
              "Mehr als ein Summand <= 0. [ersterUnbekannterSummand = " + unbekannterSummand + ", zweiterUnbekannterSummand = " + stimmeingabeSummand + "]");
        }
      } else {
        summeBekannteSummanden += stimmeingabeSummand.getAnzahl();
      }
    }

    if (unbekannterSummand != null) {
      unbekannterSummand.setAnzahl(bestimmeWertFuerUnbekanntenSummanden(stimmeingabeSumme, summeBekannteSummanden));
    } else {
      korrigiereAlleSummanden(stimmeingabeSumme);
    }
  }

  private long bestimmeWertFuerUnbekanntenSummanden(Stimmeingabe stimmeingabeSumme, long summeBekannterSummanden) throws StimmeingabePlausiFiktiveWerteFehlerNichtBehebbarException {
    long result = stimmeingabeSumme.getAnzahl() - summeBekannterSummanden;
    if (result > 0) {
      return result;
    }

    throw new StimmeingabePlausiFiktiveWerteFehlerNichtBehebbarException(
        "Kann Summand nicht korrigieren, da neuer Wert < 0 wäre [summe = " + stimmeingabeSumme.getAnzahl() + ", summeBekannterSummanden = " + summeBekannterSummanden + "]");
  }

  private void korrigiereAlleSummanden(Stimmeingabe stimmeingabeSumme) throws StimmeingabePlausiFiktiveWerteFehlerNichtBehebbarException {
    LOG.debug("Keine Unbekannte in Summe; korrigiere alle Summanden [summe = " + stimmeingabeSumme.getAnzahl() + "]");
    alleSummandenKorrigierenderSummenFehlerBeheber.behebeFehler(stimmeingabeSumme);
  }

  private long getSummeAusStimmeingabenSummand() {
    long result = 0L;

    for (Stimmeingabe stimmeingabeFuerSumme : stimmeingabenSummand) {
      result = result + stimmeingabeFuerSumme.getAnzahl();
    }

    return result;
  }
}
