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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

import javax.annotation.Nonnull;

/**
 *  on 04.01.2016.
 */
public enum SvgArtEinteilung {

  AEQUIDISTANT {
    @Override
    public List<Double> bestimmeGrenzenAufsteigend(Collection<Double> values, long anzahlTeile) {
      if (values.isEmpty()){
        return Collections.emptyList();
      }

      List<Double> result = new ArrayList<>();

      double minValue = Double.MAX_VALUE;
      double maxValue = Double.MIN_VALUE;

      for (Double aDouble : values) {
        if (minValue > aDouble) {
          minValue = aDouble;
        }
        if (maxValue < aDouble) {
          maxValue = aDouble;
        }
      }

      if (maxValue - minValue > 0 && anzahlTeile > 1) {

        double range = maxValue - minValue;
        double partSize = range / anzahlTeile;

        for (int i = 0; i < anzahlTeile-1; i++) {
          double grenzeNichtGerundet = minValue + partSize * (i + 1);
          double grenzeGerundet = Math.round(grenzeNichtGerundet * 1000d) / 1000d; // eine Nachkommastelle
          result.add(grenzeGerundet);
        }

      } else {
        result.add(minValue);
      }

      return result;
    }
  },
  DISKRIMINITATIV_AUFSTEIGEND {
    @Override
    public List<Double> bestimmeGrenzenAufsteigend(Collection<Double> values, long anzahlTeile) {
      return diskriminitativ(values, anzahlTeile, true);

    }


  },
  DISKRIMINITATIV_ABSTEIGEND {
    @Override
    public List<Double> bestimmeGrenzenAufsteigend(Collection<Double> values, long anzahlTeile) {
      return diskriminitativ(values, anzahlTeile, false);

    }


  };


  @Nonnull
  protected List<Double> diskriminitativ(Collection<Double> values, long anzahlTeile, boolean aufsteigend) {
    if (values.isEmpty()){
      return Collections.emptyList();
    }

    List<Double> verschiedeneWerte = new ArrayList<>(new HashSet<>(values));
    Collections.sort(verschiedeneWerte);

    long anzahlVerschiedenerWerte = verschiedeneWerte.size();

    List<Double> result = new ArrayList<>();

    long anzahl = Math.min(anzahlVerschiedenerWerte, anzahlTeile);

    if (anzahl > 1) {
      long anzahlRest = anzahl;
      while (!verschiedeneWerte.isEmpty()) {
        double anzahlProBucket = (1d * verschiedeneWerte.size()) / anzahlRest;
        int anzahlProBucketAufgerundet;
        if (aufsteigend){
          anzahlProBucketAufgerundet = (int) Math.ceil(anzahlProBucket);
        } else {
          anzahlProBucketAufgerundet = (int) Math.max(Math.floor(anzahlProBucket), 1d);
        }

        if (verschiedeneWerte.size() <= anzahlProBucketAufgerundet) {
          result.add(verschiedeneWerte.remove(0));
          verschiedeneWerte.clear();
        } else {
          for (int i = 0; i < anzahlProBucketAufgerundet - 1; i++) {
            verschiedeneWerte.remove(0);
          }
          result.add(verschiedeneWerte.remove(0));

        }
        anzahlRest--;
      }
      result.remove(result.size()-1); // letztes Element ist überflüssig
    } else {
      double minValue = Double.MAX_VALUE;
      for (Double aDouble : verschiedeneWerte) {
        if (minValue > aDouble) {
          minValue = aDouble;
        }
      }

      result.add(minValue);
    }

    return result;
  }
  public abstract List<Double> bestimmeGrenzenAufsteigend(Collection<Double> values, long anzahlTeile);
}
