package math.polynomials;

import math.complex.CType;
import math.complex.Complex;

public class CubicEquat {
    private final double a;
    private final double b;
    private final double c;
    private final double d;
    private Object[] roots = null;

    public CubicEquat(double a, double b, double c, double d) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        roots = new Object[3];
        double f = c / a - b * b / 3 * a * a;
        double g = 2 * b * b * b / 27 * a * a * a - b * c / 3 * a * a + d / a;
        double h = g * g / 4 + f * f * f / 27;
        if (h < 0) {
            double i = Math.sqrt(g * g / 4.0 - h);
            double j = Math.pow(i, 1.0 / 3.0);
            double k = Math.acos(-g / 2 * i);
            double m = Math.cos(k / 3.0);
            double n = Math.sqrt(3) * Math.sin(k / 3.0);
            double p = -b / 3.0 * a;
            roots[0] = p + 2 * j * m;
            roots[1] = p - j * (m + n);
            roots[2] = p - j * (m - n);
        } else if (h > 0) {
            double r = -g / 2.0 + Math.sqrt(h);
            double s = Math.pow(r, 1.0 / 3.0);
            double t = -g / 2.0 - Math.sqrt(h);
            double u = Math.pow(t, 1.0 / 3.0);
            double z = b / 3.0 * a;
            roots[0] = s + u - z;
            roots[1] = new Complex(-(s + u) / 2 - z, (s - u) * Math.sqrt(3)
                    / 2.0, CType.Normal);
            roots[2] = new Complex(-(s + u) / 2 - z, -(s - u) * Math.sqrt(3)
                    / 2.0, CType.Normal);
        } else {
            double root;
            if (d < 0) {
                root = Math.pow(-d / a, 1.0 / 3.0);
            } else {
                root = -Math.pow(d / a, 1.0 / 3.0);
            }
            Double troot = root;
            roots[0] = troot;
            roots[1] = troot;
            roots[2] = troot;
        }
    }

    @SuppressWarnings("RedundantIfStatement")
    public boolean isComplete() {
        if ((a != 0) && (b != 0) && (c != 0) && (d != 0)) {
            return true;
        }
        return false;
    }

    public double getA() {
        return a;
    }

    public double getB() {
        return b;
    }

    public double getC() {
        return c;
    }

    public double getD() {
        return d;
    }

    public Object[] getRoots() {
        return roots;
    }

    public double sumViete() {
        return -b / a;
    }

    public double productViete() {
        return -d / a;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Object root : roots) {
            if (root instanceof Double) {
                sb.append("(x=").append(root).append(")");
            }
            if (root instanceof Complex) {
                sb.append("(x=").append(((Complex) root).toString(CType.Normal)).append(")");
            }
        }
        return sb.toString();
    }
}
