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

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import de.ivu.elect.business.hochrechnung.control.AbstandImGebietsBaumGetter;
import de.ivu.elect.business.hochrechnung.control.AbstandZwischenGebietenAnhandGebietsgruppierungGetter;
import de.ivu.elect.business.hochrechnung.control.AbstandZwischenGebietenAnhandGebietsposition;
import de.ivu.elect.business.hochrechnung.control.AbstandZwischenGebietenAnhandMehrereMethoden;
import de.ivu.elect.business.hochrechnung.control.GeometricAbstandZwischenGebietDaten;
import de.ivu.elect.business.hochrechnung.control.PointGetter;
import de.ivu.elect.business.hochrechnung.control.PointImRaumAusGebietDatenErzeuger;
import de.ivu.elect.business.hochrechnung.entity.AbstandGetter;


import static java.util.Arrays.asList;

public enum AbstandartZwischenGebieten {
  GEOMETRISCH {
    @Override
    public AbstandGetter<Double> getAbstandGetter() {
      PointGetter<Double> pointGetter = new PointImRaumAusGebietDatenErzeuger<>();
      return new GeometricAbstandZwischenGebietDaten(pointGetter);
    }

    @Override
    public boolean isInMischung() {
      return true;
    }
  },
  GEOMETRISCH_AUSGEWAEHLTE_GEBIETE {
    @Override
    public AbstandGetter<Double> getAbstandGetter() {
      PointGetter<Double> pointGetter = new PointImRaumAusGebietDatenErzeuger<>();
      return new GeometricAbstandZwischenGebietDaten(pointGetter);
    }

    @Override
    public boolean isEntferneGebieteOhneVorperiodenWerte() {
      return true;
    }
  },
  ABSTAND_IM_GEBIETSBAUM {
    @Override
    public AbstandGetter<Double> getAbstandGetter() {
      return new AbstandImGebietsBaumGetter();
    }

    @Override
    public boolean isInMischung() {
      return true;
    }
  },
  ANHAND_POSITIONEN_DER_GEBIETE {
    @Override
    public AbstandGetter<Double> getAbstandGetter() {
      return new AbstandZwischenGebietenAnhandGebietsposition();
    }

    @Override
    public boolean isInMischung() {
      return true;
    }
  },
  BENUTZER_DEFINIERTE_GEBIETSGRUPPIERUNG {
    @Override
    public AbstandGetter<Double> getAbstandGetter() {
      return new AbstandZwischenGebietenAnhandGebietsgruppierungGetter();
    }

    @Override
    public boolean isInMischung() {
      return true;
    }
  },
  MISCHUNG_MIT_BENUTZER_DEFINIERTE_GEWICHTUNG {
    @Override
    public AbstandGetter<Double> getAbstandGetter() {
      return new AbstandZwischenGebietenAnhandMehrereMethoden(getAndereAbstandarten());
    }

    private List<AbstandGetter<Double>> getAndereAbstandarten() {
      return Arrays.stream(AbstandartZwischenGebieten.values())
          .filter(AbstandartZwischenGebieten::isInMischung)
          .map(AbstandartZwischenGebieten::getAbstandGetter)
          .collect(Collectors.toList());
    }
  };

  public static List<AbstandartZwischenGebieten> getAbstandartenInBevorzugteReihenfolge() {
    return asList (
        AbstandartZwischenGebieten.GEOMETRISCH,
        AbstandartZwischenGebieten.GEOMETRISCH_AUSGEWAEHLTE_GEBIETE,
        AbstandartZwischenGebieten.ABSTAND_IM_GEBIETSBAUM,
        AbstandartZwischenGebieten.ANHAND_POSITIONEN_DER_GEBIETE,
        AbstandartZwischenGebieten.BENUTZER_DEFINIERTE_GEBIETSGRUPPIERUNG,
        AbstandartZwischenGebieten.MISCHUNG_MIT_BENUTZER_DEFINIERTE_GEWICHTUNG
    );
  }

  public abstract AbstandGetter<Double> getAbstandGetter();

  public boolean isInMischung() {
    return false;
  }

  public boolean isEntferneGebieteOhneVorperiodenWerte() {
    return false;
  }
}
