
package de.ivu.elect.sitzberechnung.math;

import java.math.BigDecimal;
import java.math.RoundingMode;

public interface FractionConverter {

  default Fraction asFractionConverted(Long zahl) {
    return asFractionConverted(zahl, 1L);
  }

  default Fraction asFractionConverted(BigDecimal zahl) {
    BigDecimal nachkommastellen = zahl.remainder(BigDecimal.ONE).movePointRight(zahl.scale());
    Fraction fractionAusNachkommastellen = asFractionConverted(nachkommastellen.longValueExact(), 100L);

    BigDecimal vorkommastellen = zahl.setScale(0, RoundingMode.DOWN);
    long longAusVorkommastellen = vorkommastellen.longValueExact();

    return fractionAusNachkommastellen.add(longAusVorkommastellen).reduce();
  }

  default Fraction asFractionConverted(Fraction fraction) {
    return asFractionConverted(fraction.getNumerator(), fraction.getDenominator());
  }

  default Fraction asFractionConverted(Fraction zaehler, Long nenner) {
    if (zaehler == null || nenner == null) {
      return convert(Fraction.ZERO);
    }

    return asFractionConverted(zaehler.getNumerator(), Math.multiplyExact(zaehler.getDenominator(), nenner));
  }

  default Fraction asFractionConverted(Long zaehler, Fraction nenner) {
    if (zaehler == null || nenner == null) { // ELECT-8884
      return convert(Fraction.ZERO);
    }

    return asFractionConverted(Math.multiplyExact(zaehler, nenner.getDenominator()), nenner.getNumerator());
  }

  default Fraction asFractionConverted(Long zaehler, Long nenner) {
    return convert(zaehler == null || zaehler.compareTo(0L) == 0 || nenner == null || nenner.compareTo(0L) == 0 ? Fraction.ZERO : Fraction.getFraction(zaehler, nenner));
  }

  Fraction convert(Fraction fraction);

  static FractionConverter convertingExakt() {
    return fraction -> fraction;
  }

  static FractionConverter convertingNachkommastellenMaxRundungKeine(int anzahlNachkommastellenMax) {
    return fraction -> {
      if (fraction == null) {
        return null;
      }

      if (fraction.getNumerator() == 0 || fraction.getDenominator() == 0) {
        return Fraction.ZERO;
      }

      BigDecimal scale = BigDecimal.TEN.pow(anzahlNachkommastellenMax);

      BigDecimal valueNachkommastellenMaxPlusEinsGerundet = fraction.toBigDecimal(anzahlNachkommastellenMax + 1, RoundingMode.DOWN);
      long valueNachkommastellenMaxUngerundet = valueNachkommastellenMaxPlusEinsGerundet.multiply(scale).longValue(); // Die eine gerundete Nachkommastelle "abschneiden"...

      return Fraction.getFraction(valueNachkommastellenMaxUngerundet, scale.longValue()).reduce();
    };
  }
}
