#pragma once

// link: https://www.codeproject.com/Articles/25237/Bezier-Curves-Made-Simple

class BezierCurve
{
    static double FactorialLookup[33];

public:
    // just check if n is appropriate, then return the result
    static double factorial(int n)
    {
        return FactorialLookup[n];
    }

    static double Ni(int n, int i)
    {
        double ni;
        double a1 = factorial(n);
        double a2 = factorial(i);
        double a3 = factorial(n - i);
        ni = a1 / (a2 * a3);
        return ni;
    }

    // Calculate Bernstein basis
    static double Bernstein(int n, int i, double t)
    {
        double basis;
        double ti;
        double tni;

        if (t == 0.0 && i == 0)
            ti = 1.0;
        else
            ti = pow(t, i);

        if (n == i && t == 1.0)
            tni = 1.0;
        else
            tni = pow((1 - t), (n - i));

        //Bernstein basis
        basis = Ni(n, i) * ti * tni;
        return basis;
    }

    static glm::vec2 Bezier2D(const std::vector<glm::vec2>& b, double t)
    {
        double px = 0.0;
        double py = 0.0;
        const int npts = (int)b.size();
        for (int i = 0; i < npts; i++)
        {
            double basis = Bernstein(npts - 1, i, t);
            px += basis * b[i].x;
            py += basis * b[i].y;
        }
        return { px, py };
    }
};
