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

import java.util.Set;
import java.util.function.BiFunction;

import de.ivu.elect.business.auffaelligkeit.entity.AbstandartZwischenGebieten;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsgruppierung;
import de.ivu.elect.business.hochrechnung.entity.AbstandGetter;
import de.ivu.elect.business.hochrechnung.entity.GebietDaten;
import de.ivu.elect.business.hochrechnung.entity.KoordinatenInformationen;
import de.ivu.elect.jee.presentation.dynamicform.FormBuilder;
import de.ivu.elect.jee.presentation.dynamicform.LambdaEnumProperty;

public class AbstandZwischenGebietenAnhandGebietsgruppierungGetter implements AbstandGetter<Double> {
  private Long gewicht = 0L;
  private static final Double ABSCHAETZUNG_FUER_GROESST_MOEGLICHER_ABSTAND_WENN_NICHT_BERECHENBAR = 1E2;
  private final double abschaetzungFuerGroesstMoeglicherAbstand = ABSCHAETZUNG_FUER_GROESST_MOEGLICHER_ABSTAND_WENN_NICHT_BERECHENBAR;
  private Boolean isDefiniert = null;

  @Override
  public boolean isDefiniert() {
    return this.isDefiniert != null && this.isDefiniert;
  }

  @Override
  public Double getAbstandWennDefiniert(GebietDaten<Double> g1, GebietDaten<Double> g2, KoordinatenInformationen koordinatenInformationen) {
    if (!isDefiniert()) {
      return null;
    }

    Set<Gebietsgruppierung> gebietsgruppierungen1 = g1.getGebiet().getGebietsgruppierungs();
    Set<Gebietsgruppierung> gebietsgruppierungen2 = g2.getGebiet().getGebietsgruppierungs();

    if (gebietsgruppierungen1 == null || gebietsgruppierungen2 == null) {
      return abschaetzungFuerGroesstMoeglicherAbstand;
    }

    Long anzahlUeberlabungVonGebietsgruppierungen = getAnzahlUeberlabungVonGebietsgruppierungen(gebietsgruppierungen1, gebietsgruppierungen2);

    if (anzahlUeberlabungVonGebietsgruppierungen > 0) {
      return abschaetzungFuerGroesstMoeglicherAbstand / (anzahlUeberlabungVonGebietsgruppierungen * abschaetzungFuerGroesstMoeglicherAbstand);
    }

    return abschaetzungFuerGroesstMoeglicherAbstand;
  }

  private Long getAnzahlUeberlabungVonGebietsgruppierungen(Set<Gebietsgruppierung> gebietsgruppierungen1, Set<Gebietsgruppierung> gebietsgruppierungen2) {
    Long result = 0L;
    for (Gebietsgruppierung gebietsgruppierung : gebietsgruppierungen1) {
      if (gebietsgruppierungen2.contains(gebietsgruppierung)) {
        result++;
      }
    }
    return result;
  }

  @Override
  public Long getGewicht() {
    return gewicht;
  }
  @Override
  public void setGewicht(Long gewicht) {
    this.gewicht = gewicht;
  }

  @Override
  public boolean setIsDefiniert(KoordinatenInformationen koordinatenInformationen) {
    this.isDefiniert = koordinatenInformationen.getAlleGebiete().stream().anyMatch(g -> !g.getGebietsgruppierungs().isEmpty());
    return this.isDefiniert;
  }

  @Override
  public AbstandartZwischenGebieten getAbstandartZwischenGebieten() {
    return AbstandartZwischenGebieten.BENUTZER_DEFINIERTE_GEBIETSGRUPPIERUNG;
  }

  @Override
  public void addObservingProperties(FormBuilder formBuilder, LambdaEnumProperty observedProperty, BiFunction<String, Object[], String> messageGetter) {
    // do nothing
  }
}
