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

import javax.annotation.Nullable;

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

import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;

public class GebietGemaessVorperiodeStimmeingabeSkalierer implements StimmeingabeSkalierer {

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

  private final Wahldurchfuehrungsgebiet gebiet;
  private final Wahldurchfuehrungsgebiet obergebiet;
  private final ErgebnisDaten ergebnisDatenVorperiode;

  public GebietGemaessVorperiodeStimmeingabeSkalierer(Wahldurchfuehrungsgebiet gebiet, Wahldurchfuehrungsgebiet obergebiet, ErgebnisDaten ergebnisDaten) {
    super();

    this.gebiet = gebiet;
    this.obergebiet = obergebiet;
    this.ergebnisDatenVorperiode = ergebnisDaten;
  }

  @Nullable
  @Override
  public Double berechneSkalierungsfaktor(Stimmeingabe stimmeingabe) {
    if (stimmeingabe.isWahlvorschlagStimmeingabe()) {
      return berechneFaktorFuerSkalierungVonObergebietAufGebiet(stimmeingabe);
    }

    // HINT: Systemgruppen werden nicht skaliert (da separat und endgültig berechnet)
    // HINT: Listenkandidaturstimmen werden nicht skaliert (da komplett zufällig bestimmt)
    return UNVERAENDERT;
  }

  private double berechneFaktorFuerSkalierungVonObergebietAufGebiet(Stimmeingabe stimmeingabe) {
    double anteilStimmenGebiet = getAnteilStimmen(stimmeingabe, gebiet);
    double anteilStimmenObergebiet = getAnteilStimmen(stimmeingabe, obergebiet);

    if (anteilStimmenObergebiet > 0) {
      double result = 1.0d * anteilStimmenGebiet / anteilStimmenObergebiet;

      log("\t\t\t\tSkalierungsfaktor {} [anteilStimmenGebiet = {}, anteilStimmenObergebiet = {}, stimmeingabe = {}]", ergebnisDatenVorperiode.getErgebnis().getErgebnisart(), result,
          anteilStimmenGebiet, anteilStimmenObergebiet, stimmeingabe.getTk());

      return result;
    }

    return UNVERAENDERT;
  }

  private double getAnteilStimmen(Stimmeingabe stimmeingabe, Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet) {
    long anzahlStimmenGruppe = getAnzahlStimmenGruppe(wahldurchfuehrungsgebiet, stimmeingabe);
    long anzahlStimmenGueltige = getAnzahlStimmenGueltige(wahldurchfuehrungsgebiet, stimmeingabe);
    if (anzahlStimmenGueltige > 0) {
      return 1.0d * anzahlStimmenGruppe / anzahlStimmenGueltige;
    }

    return 0d;
  }

  private long getAnzahlStimmenGueltige(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, Stimmeingabe stimmeingabe) {
    if (Stimmenart.DIREKTSTIMME.equals(stimmeingabe.getStimmenart())) {
      return ergebnisDatenVorperiode.getErststimmenVorperiodeGueltigeGesamt(wahldurchfuehrungsgebiet);
    }
    if (Stimmenart.LISTENSTIMME.equals(stimmeingabe.getStimmenart())) {
      return ergebnisDatenVorperiode.getZweitstimmenVorperiodeGueltigeGesamt(wahldurchfuehrungsgebiet);
    }
    if (Stimmenart.REFERENDUM_STIMME.equals(stimmeingabe.getStimmenart())) {
      return ergebnisDatenVorperiode.getErgebnisDatenReferendumOptionen().getStimmenFuerReferendumOptionenGueltig(stimmeingabe.getReferendumOption().getGruppe(), wahldurchfuehrungsgebiet);
    }
    throw new IllegalArgumentException("Unbekannte Stimmenart [" + stimmeingabe.getStimmenart() + "] für Stimmeingabe [" + stimmeingabe + "]");
  }

  private long getAnzahlStimmenGruppe(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, Stimmeingabe stimmeingabe) {
    if (Stimmenart.DIREKTSTIMME.equals(stimmeingabe.getStimmenart())) {
      return ergebnisDatenVorperiode.getErststimmenAktuellGesamt(stimmeingabe.getPolitischeGruppe(), wahldurchfuehrungsgebiet);
    }
    if (Stimmenart.LISTENSTIMME.equals(stimmeingabe.getStimmenart())) {
      return ergebnisDatenVorperiode.getZweitstimmenAktuellGesamt(stimmeingabe.getPolitischeGruppe(), wahldurchfuehrungsgebiet);
    }
    if (Stimmenart.REFERENDUM_STIMME.equals(stimmeingabe.getStimmenart())) {
      return ergebnisDatenVorperiode.getErgebnisDatenReferendumOptionen().getStimmenFuerReferendumOption(stimmeingabe.getReferendumOption(), wahldurchfuehrungsgebiet);
    }
    throw new IllegalArgumentException("Unbekannte Stimmenart [" + stimmeingabe.getStimmenart() + "] für Stimmeingabe [" + stimmeingabe + "]");
  }

  private static void log(String message, Object... args) {
    LOG.debug(message, args);
  }
}
