package de.ivu.elect.business.auffaelligkeit.control;

public class EntscheidungsgrenzenFuerAuffaelligkeit {

  private double hoheAbweichungWahlbeteiligung;

  private double hoherWertFuerUngueltige;

  private double hoherUnterschiedVerschiedenerStimmenartenGleicherPartei;

  private double hoheAbweichungParteistimmen;

  private double hoechsteNeueAbweichungZuAlterAbweichungRatioBeiSichLohnenderParteistimmenvertausch;

  private double minimalerGuterGewinnBeiReduzierungDerAbweichung;

  public EntscheidungsgrenzenFuerAuffaelligkeit(double hoheAbweichungWahlbeteiligung, double hoherWertFuerUngueltige, double hoherUnterschiedVerschiedenerStimmenartenGleicherPartei, double hoheAbweichungParteistimmen, double hoechsteNeueAbweichungZuAlterAbweichungRatioBeiSichLohnenderParteistimmenvertausch, double minimalerGuterGewinnBeiReduzierungDerAbweichung) {
    this.hoheAbweichungWahlbeteiligung = hoheAbweichungWahlbeteiligung;
    this.hoherWertFuerUngueltige = hoherWertFuerUngueltige;
    this.hoherUnterschiedVerschiedenerStimmenartenGleicherPartei = hoherUnterschiedVerschiedenerStimmenartenGleicherPartei;
    this.hoheAbweichungParteistimmen = hoheAbweichungParteistimmen;
    this.hoechsteNeueAbweichungZuAlterAbweichungRatioBeiSichLohnenderParteistimmenvertausch = hoechsteNeueAbweichungZuAlterAbweichungRatioBeiSichLohnenderParteistimmenvertausch;
    this.minimalerGuterGewinnBeiReduzierungDerAbweichung = minimalerGuterGewinnBeiReduzierungDerAbweichung;
  }

  public double getHoheAbweichungWahlbeteiligung() {
    return hoheAbweichungWahlbeteiligung;
  }

  public double getHoherWertFuerUngueltige() {
    return hoherWertFuerUngueltige;
  }

  public double getHoherUnterschiedVerschiedenerStimmenartenGleicherPartei() {
    return hoherUnterschiedVerschiedenerStimmenartenGleicherPartei;
  }

  public double getHoheAbweichungParteistimmen() {
    return hoheAbweichungParteistimmen;
  }

  public double getHoechsteNeueAbweichungZuAlterAbweichungRatioBeiSichLohnenderParteistimmenvertausch() {
    return hoechsteNeueAbweichungZuAlterAbweichungRatioBeiSichLohnenderParteistimmenvertausch;
  }

  private double getMinimalerGuterGewinnBeiReduzierungDerAbweichung() {
    return minimalerGuterGewinnBeiReduzierungDerAbweichung;
  }

  public boolean isWahlbeteiligungsabweichungAuffaellig(Double aktuell, Double abweichungWahlbeteiligung) {
    if (aktuell == null || abweichungWahlbeteiligung == null) {
      return false;
    }
    return Math.abs(abweichungWahlbeteiligung) > getHoheAbweichungWahlbeteiligung();
  }

  public boolean isUngueltigeAnteilAuffaellig(Double ungueltigeAnteil) {
    if (ungueltigeAnteil == null) {
      return false;
    }
    return ungueltigeAnteil > getHoherWertFuerUngueltige();
  }

  public boolean isEineStimmenartAuffaelligImVerglichenZuAnderenStimmenartenFuerDieGleichePolitischeGruppe(Double anteilAktuellErsterStimmenart, Double anteilAktuellZweiterStimmenart, Double abweichungErsterStimmenart, Double abweichungZweiterStimmenart) {
    if (anteilAktuellErsterStimmenart == null || anteilAktuellZweiterStimmenart == null) {
      return false;
    }
    if (abweichungErsterStimmenart == null || abweichungZweiterStimmenart == null) {
      return Math.abs(anteilAktuellErsterStimmenart - anteilAktuellZweiterStimmenart) > getHoherUnterschiedVerschiedenerStimmenartenGleicherPartei();
    }
    return Math.abs(anteilAktuellErsterStimmenart - anteilAktuellZweiterStimmenart) > getHoherUnterschiedVerschiedenerStimmenartenGleicherPartei() &&
        Math.max(Math.abs(abweichungErsterStimmenart), Math.abs(abweichungZweiterStimmenart)) > getHoheAbweichungParteistimmen();
  }

  public boolean koenntenParteistimmenVertauschtSein(Double anteilAktuellErstePolitischeGruppe, Double anteilAktuellZweitePolitischeGruppe,
                                                     Double anteilErwartetErstePolitischeGruppe, Double anteilErwartetZweitePolitischeGruppe) {
    if (anteilAktuellErstePolitischeGruppe == null || anteilAktuellZweitePolitischeGruppe == null ||
        anteilErwartetErstePolitischeGruppe == null || anteilErwartetZweitePolitischeGruppe == null) {
      return false;
    }

    if (anteilErwartetErstePolitischeGruppe >= anteilErwartetZweitePolitischeGruppe) {
      return koenntenParteistimmenSortiertNachErwartungenAbsteigendVertauschtSein(anteilAktuellErstePolitischeGruppe, anteilAktuellZweitePolitischeGruppe,
          anteilErwartetErstePolitischeGruppe, anteilErwartetZweitePolitischeGruppe);
    }
    return koenntenParteistimmenSortiertNachErwartungenAbsteigendVertauschtSein(anteilAktuellZweitePolitischeGruppe, anteilAktuellErstePolitischeGruppe,
        anteilErwartetZweitePolitischeGruppe, anteilErwartetErstePolitischeGruppe);
  }

  private boolean koenntenParteistimmenSortiertNachErwartungenAbsteigendVertauschtSein(Double anteilAktuellErstePolitischeGruppe, Double anteilAktuellZweitePolitischeGruppe,
                                                                                       Double anteilErwartetErstePolitischeGruppe, Double anteilErwartetZweitePolitischeGruppe) {
    return anteilAktuellErstePolitischeGruppe < anteilAktuellZweitePolitischeGruppe;
  }

  public double getGewichteterGewinnBeiParteiStimmenVertauschung(Double anteilAktuellErstePolitischeGruppe, Double anteilAktuellZweitePolitischeGruppe,
                                                                 Double anteilErwartetErstePolitischeGruppe, Double anteilErwartetZweitePolitischeGruppe,
                                                                 Double abweichungErstePolitischeGruppe, Double abweichungZweitePolitischeGruppe) {
    if (!koenntenParteistimmenVertauschtSein(anteilAktuellErstePolitischeGruppe, anteilAktuellZweitePolitischeGruppe,
        anteilErwartetErstePolitischeGruppe, anteilErwartetZweitePolitischeGruppe) ||
        abweichungErstePolitischeGruppe == null || abweichungZweitePolitischeGruppe == null) {
      return 0;
    }

    double neueAbweichungErstePolitischeGruppe = anteilAktuellZweitePolitischeGruppe - anteilErwartetErstePolitischeGruppe;
    double neueAbweichungZweitePolitischeGruppe = anteilAktuellErstePolitischeGruppe - anteilErwartetZweitePolitischeGruppe;

    double verbesserungAbweichungErstePolitischeGruppe = Math.abs(abweichungErstePolitischeGruppe) - Math.abs(neueAbweichungErstePolitischeGruppe);
    double verbesserungAbweichungZweitePolitischeGruppe = Math.abs(abweichungZweitePolitischeGruppe) - Math.abs(neueAbweichungZweitePolitischeGruppe);

    // jetzt gewichte die Verbesserungen nach der erwarteten Stimmenanteile.
    return getGewichteterVerbesserung (verbesserungAbweichungErstePolitischeGruppe, anteilErwartetErstePolitischeGruppe)
        + getGewichteterVerbesserung (verbesserungAbweichungZweitePolitischeGruppe, anteilErwartetZweitePolitischeGruppe);
  }

  private double getGewichteterVerbesserung(double verbesserungInDerAbweichung, Double stimmenanteil) {
    if (stimmenanteil != null) {
      return verbesserungInDerAbweichung / (stimmenanteil / 10 + .015);
    }
    return 0;
  }

  public boolean isGewichteterGewinnBeiReduzierungDerAbweichungGut(double gewichteterGewinn) {
    return gewichteterGewinn >= getMinimalerGuterGewinnBeiReduzierungDerAbweichung();
  }
}