// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.npc.util;

public class RootSolver
{
    public static final double M_PI = 3.141592653589793;
    public static final double EQN_EPS = 1.0E-15;
    
    protected static boolean isZero(final double x) {
        return x > -1.0E-15 && x < 1.0E-15;
    }
    
    protected static double cubicRoot(final double x) {
        return (x > 0.0) ? Math.pow(x, 0.3333333333333333) : ((x < 0.0) ? (-Math.pow(-x, 0.3333333333333333)) : 0.0);
    }
    
    public static int solveQuadric(final double c2, final double c1, final double c0, final double[] results, final int resultIndex) {
        final double p = c1 / (2.0 * c2);
        final double q = c0 / c2;
        final double D = p * p - q;
        if (isZero(D)) {
            results[resultIndex] = -p;
            return 1;
        }
        if (D < 0.0) {
            return 0;
        }
        final double sqrt_D = Math.sqrt(D);
        results[resultIndex] = sqrt_D - p;
        results[resultIndex + 1] = -sqrt_D - p;
        return 2;
    }
    
    public static int solveCubic(final double c3, final double c2, final double c1, final double c0, final double[] results) {
        final double A = c2 / c3;
        final double B = c1 / c3;
        final double C = c0 / c3;
        final double sq_A = A * A;
        final double p = 0.3333333333333333 * (-0.3333333333333333 * sq_A + B);
        final double q = 0.5 * (0.07407407407407407 * A * sq_A - 0.3333333333333333 * A * B + C);
        final double cb_p = p * p * p;
        final double D = q * q + cb_p;
        int num;
        if (isZero(D)) {
            if (isZero(q)) {
                results[0] = 0.0;
                num = 1;
            }
            else {
                final double u = cubicRoot(-q);
                results[0] = 2.0 * u;
                results[1] = -u;
                num = 2;
            }
        }
        else if (D < 0.0) {
            final double phi = 0.3333333333333333 * Math.acos(-q / Math.sqrt(-cb_p));
            final double t = 2.0 * Math.sqrt(-p);
            results[0] = t * Math.cos(phi);
            results[1] = -t * Math.cos(phi + 1.0471975511965976);
            results[2] = -t * Math.cos(phi - 1.0471975511965976);
            num = 3;
        }
        else {
            final double sqrt_D = Math.sqrt(D);
            final double u2 = cubicRoot(sqrt_D - q);
            final double v = -cubicRoot(sqrt_D + q);
            results[0] = u2 + v;
            num = 1;
        }
        final double sub = 0.3333333333333333 * A;
        for (int i = 0; i < num; ++i) {
            final int n = i;
            results[n] -= sub;
        }
        return num;
    }
    
    public static int solveQuartic(final double c4, final double c3, final double c2, final double c1, final double c0, final double[] results) {
        final double A = c3 / c4;
        final double B = c2 / c4;
        final double C = c1 / c4;
        final double D = c0 / c4;
        final double sq_A = A * A;
        final double p = -0.375 * sq_A + B;
        final double q = 0.125 * sq_A * A - 0.5 * A * B + C;
        final double r = -0.01171875 * sq_A * sq_A + 0.0625 * sq_A * B - 0.25 * A * C + D;
        int num;
        if (isZero(r)) {
            final double coeff0 = q;
            final double coeff2 = p;
            final double coeff3 = 0.0;
            final double coeff4 = 1.0;
            num = solveCubic(coeff4, coeff3, coeff2, coeff0, results);
            results[num++] = 0.0;
        }
        else {
            double coeff0 = 0.5 * r * p - 0.125 * q * q;
            double coeff2 = -r;
            double coeff3 = -0.5 * p;
            final double coeff4 = 1.0;
            solveCubic(coeff4, coeff3, coeff2, coeff0, results);
            final double z = results[0];
            double u = z * z - r;
            double v = 2.0 * z - p;
            if (isZero(u)) {
                u = 0.0;
            }
            else {
                if (u <= 0.0) {
                    return 0;
                }
                u = Math.sqrt(u);
            }
            if (isZero(v)) {
                v = 0.0;
            }
            else {
                if (v <= 0.0) {
                    return 0;
                }
                v = Math.sqrt(v);
            }
            coeff0 = z - u;
            coeff2 = ((q < 0.0) ? (-v) : v);
            coeff3 = 1.0;
            num = solveQuadric(coeff3, coeff2, coeff0, results, 0);
            coeff0 = z + u;
            coeff2 = ((q < 0.0) ? v : (-v));
            coeff3 = 1.0;
            num += solveQuadric(coeff3, coeff2, coeff0, results, num);
        }
        final double sub = 0.25 * A;
        for (int i = 0; i < num; ++i) {
            final int n = i;
            results[n] -= sub;
        }
        return num;
    }
}
