package dji.v5.ux.core.base.charts.util;

public class FloatUtils {
    public static final int[] POW10 = new int[]{1, 10, 100, 1000, 10000, 100000, 1000000};

    private FloatUtils() {
        //do nothing
    }

    public static float nextUpF(float f) {
        if (!Float.isNaN(f) && f != Float.POSITIVE_INFINITY) {
            f += 0.0F;
            return Float.intBitsToFloat(Float.floatToRawIntBits(f) + (f >= 0.0F ? 1 : -1));
        } else {
            return f;
        }
    }

    public static float nextDownF(float f) {
        if (!Float.isNaN(f) && f != Float.NEGATIVE_INFINITY) {
            if (f == 0.0F) {
                return -1.4E-45F;
            } else {
                return Float.intBitsToFloat(Float.floatToRawIntBits(f) + (f > 0.0F ? -1 : 1));
            }
        } else {
            return f;
        }
    }

    public static double nextUp(double d) {
        if (!Double.isNaN(d) && d != Double.POSITIVE_INFINITY) {
            d += 0.0;
            return Double.longBitsToDouble(Double.doubleToRawLongBits(d) + (long)(d >= 0.0 ? 1 : -1));
        } else {
            return d;
        }
    }

    public static double nextDown(double d) {
        if (!Double.isNaN(d) && d != Double.NEGATIVE_INFINITY) {
            if (d == 0.0) {
                return -1.401298464324817E-45;
            } else {
                return Double.longBitsToDouble(Double.doubleToRawLongBits(d) + (long) (d > 0.0 ? -1 : 1));
            }
        } else {
            return d;
        }
    }

    public static boolean almostEqual(float a, float b, float absoluteDiff, float relativeDiff) {
        float diff = Math.abs(a - b);
        if (diff <= absoluteDiff) {
            return true;
        } else {
            a = Math.abs(a);
            b = Math.abs(b);
            float largest = a > b ? a : b;
            return diff <= largest * relativeDiff;
        }
    }

    public static float roundToOneSignificantFigure(double num) {
        float d = (float)Math.ceil((double)((float)Math.log10(num < 0.0 ? -num : num)));
        int power = 1 - (int)d;
        float magnitude = (float)Math.pow(10.0, (double)power);
        long shifted = Math.round(num * (double)magnitude);
        return (float)shifted / magnitude;
    }

    public static int formatFloat(char[] formattedValue, float value, int endIndex, int digits, char separator) {
        if (digits >= POW10.length) {
            formattedValue[endIndex - 1] = '.';
            return 1;
        } else {
            boolean negative = false;
            if (value == 0.0F) {
                formattedValue[endIndex - 1] = '0';
                return 1;
            } else {
                if (value < 0.0F) {
                    negative = true;
                    value = -value;
                }

                if (digits > POW10.length) {
                    digits = POW10.length - 1;
                }

                value *= (float)POW10[digits];
                long lval = (long)Math.round(value);
                int index = endIndex - 1;
                int charsNumber = 0;

                while(lval != 0L || charsNumber < digits + 1) {
                    int digit = (int)(lval % 10L);
                    lval /= 10L;
                    formattedValue[index--] = (char)(digit + 48);
                    ++charsNumber;
                    if (charsNumber == digits) {
                        formattedValue[index--] = separator;
                        ++charsNumber;
                    }
                }

                if (formattedValue[index + 1] == separator) {
                    formattedValue[index--] = '0';
                    ++charsNumber;
                }

                if (negative) {
                    formattedValue[index] = '-';
                    ++charsNumber;
                }

                return charsNumber;
            }
        }
    }

    public static void computeAutoGeneratedAxisValues(float start, float stop, int steps, AxisAutoValues outValues) {
        double range = (double)(stop - start);
        if (steps != 0 && !(range <= 0.0)) {
            double rawInterval = range / (double)steps;
            double interval = (double)roundToOneSignificantFigure(rawInterval);
            double intervalMagnitude = Math.pow(10.0, (double)((int)Math.log10(interval)));
            int intervalSigDigit = (int)(interval / intervalMagnitude);
            if (intervalSigDigit > 5) {
                interval = Math.floor(10.0 * intervalMagnitude);
            }

            double first = Math.ceil((double)start / interval) * interval;
            double last = nextUp(Math.floor((double)stop / interval) * interval);
            int valuesNum = 0;

            double intervalValue;
            for(intervalValue = first; intervalValue <= last; intervalValue += interval) {
                ++valuesNum;
            }

            outValues.valuesNumber = valuesNum;
            if (outValues.values.length < valuesNum) {
                outValues.values = new float[valuesNum];
            }

            intervalValue = first;

            for(int valueIndex = 0; valueIndex < valuesNum; ++valueIndex) {
                outValues.values[valueIndex] = (float)intervalValue;
                intervalValue += interval;
            }

            if (interval < 1.0) {
                outValues.decimals = (int)Math.ceil(-Math.log10(interval));
            } else {
                outValues.decimals = 0;
            }

        } else {
            outValues.values = new float[0];
            outValues.valuesNumber = 0;
        }
    }
}
