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

import java.util.Collections;
import java.util.Map;

import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.hochrechnung.control.AbweichungZwischenGebietDatenBerechner;

public class GebietDatenAbweichung implements GebietDaten<Double> {
  private final Gebiet gebiet;
  private final WahlteilnehmerAnzahl anzahlWahlberechtigte;
  private final WahlteilnehmerAnzahl anzahlWaehler;
  private final GebietDatenWahlbeteiligung wahlbeteiligung;
  private final Map<Stimmenart, Double> gueltige;
  private final Map<Stimmenart, Double> ungueltige;
  private final Map<PolitischeGruppe, ParteiStimmen<Double>> parteiStimmen;
  private final Map<Gruppe, ReferendumFrage<Double>> referendumFragen;
  private final Boolean ergebnisVorhanden;

  public GebietDatenAbweichung(GebietDaten<Double> actual, GebietDaten<Double> expected, KoordinatenInformationen koordinatenInformationen) {
    AbweichungZwischenGebietDatenBerechner abweichungBerechner = new AbweichungZwischenGebietDatenBerechner();

    gebiet = extractGebiet(actual, expected);
    anzahlWahlberechtigte = new WahlteilnehmerAnzahl();
    anzahlWaehler = new WahlteilnehmerAnzahl();
    wahlbeteiligung = abweichungBerechner.getAbweichungZwischenWahlbeteiligung(getNotNullWahlbeteiligung(actual), getNotNullWahlbeteiligung(expected));
    gueltige = abweichungBerechner.getAbweichungZwischenStimmenMaps(getNotNullGueltigeStimmen(actual), getNotNullGueltigeStimmen(expected) , koordinatenInformationen);
    ungueltige = abweichungBerechner.getAbweichungZwischenStimmenMaps(getNotNullUngueltigeStimmen(actual), getNotNullUngueltigeStimmen(expected) , koordinatenInformationen);
    parteiStimmen = abweichungBerechner.getParteiStimmenAbweichungZwischenGebietDaten(getNotNullParteiStimmen(actual), getNotNullParteiStimmen(expected) , koordinatenInformationen);
    referendumFragen = abweichungBerechner.getReferendumFragenStimmenAbweichungZwischenGebietDaten(getNotNullReferendumFragen(actual), getNotNullReferendumFragen(expected) , koordinatenInformationen);
    ergebnisVorhanden = isAbweichungBerechenbar(actual, expected);
  }

  private Gebiet extractGebiet(GebietDaten<Double> actual, GebietDaten<Double> expected) {
    if (actual != null && actual.getGebiet() != null) {
      return actual.getGebiet();
    } else if (expected != null && expected.getGebiet() != null) {
      return expected.getGebiet();
    }
    return null;
  }

  private Boolean isAbweichungBerechenbar(GebietDaten<Double> actual, GebietDaten<Double> expected) {
    if (actual != null && actual.isErgebnisVorhanden() && expected != null && expected.isErgebnisVorhanden()) {
      return true;
    }
    return false;
  }

  private Map<Gruppe, ReferendumFrage<Double>> getNotNullReferendumFragen(GebietDaten<Double> gebietDaten) {
    if (gebietDaten != null) {
      return gebietDaten.getReferendumFragen();
    }
    return Collections.emptyMap();
  }

  private GebietDatenWahlbeteiligung getNotNullWahlbeteiligung(GebietDaten<Double> gebietDaten) {
    if (gebietDaten != null) {
      return gebietDaten.getWahlbeteiligung();
    }
    return new GebietDatenWahlbeteiligung();
  }

  private Map<Stimmenart, Double> getNotNullGueltigeStimmen(GebietDaten<Double> gebietDaten) {
    if (gebietDaten != null) {
      return gebietDaten.getGueltige();
    }
    return Collections.emptyMap();
  }

  private Map<Stimmenart, Double> getNotNullUngueltigeStimmen(GebietDaten<Double> gebietDaten) {
    if (gebietDaten != null) {
      return gebietDaten.getUngueltige();
    }
    return Collections.emptyMap();
  }

  private Map<PolitischeGruppe, ParteiStimmen<Double>> getNotNullParteiStimmen(GebietDaten<Double> gebietDaten) {
    if (gebietDaten != null) {
      return gebietDaten.getParteiStimmen();
    }
    return Collections.emptyMap();
  }

  @Override
  public Gebiet getGebiet() {
    return gebiet;
  }

  @Override
  public WahlteilnehmerAnzahl getAnzahlWahlberechtigteImGebiet() {
    return anzahlWahlberechtigte;
  }

  @Override
  public WahlteilnehmerAnzahl getAnzahlWaehlerImGebiet() {
    return anzahlWaehler;
  }

  @Override
  public Map<Stimmenart, Double> getGueltige() {
    return gueltige;
  }

  @Override
  public Map<Stimmenart, Double> getUngueltige() {
    return ungueltige;
  }

  @Override
  public boolean isErgebnisVorhanden() {
    return ergebnisVorhanden;
  }

  @Override
  public GebietDatenWahlbeteiligung getWahlbeteiligung() {
    return wahlbeteiligung;
  }

  @Override
  public Map<PolitischeGruppe, ParteiStimmen<Double>> getParteiStimmen() {
    return parteiStimmen;
  }

  @Override
  public Map<Gruppe, ReferendumFrage<Double>> getReferendumFragen() {
    return referendumFragen;
  }
}
