import numpy as np


class Bezier:
    def TwoPoints(t, P1, P2):
        """
        Returns a point between P1 and P2, parametised by t.
        INPUTS:
            t     float/int; a parameterisation.
            P1    numpy array; a point.
            P2    numpy array; a point.
        OUTPUTS:
            Q1    numpy array; a point.
        """
        if not isinstance(P1, np.ndarray) or not isinstance(P2, np.ndarray):
            raise TypeError("Points must be an instance of the numpy.ndarray!")
        if not isinstance(t, (int, float)):
            raise TypeError("Parameter t must be an int or float!")

        Q1 = (1 - t) * P1 + t * P2
        return Q1

    def Points(t, points):
        """
        Returns a list of points interpolated by the Bezier process
        INPUTS:
            t            float/int; a parameterisation.
            points       list of numpy arrays; points.
        OUTPUTS:
            newpoints    list of numpy arrays; points.
        """
        newpoints = []
        for i1 in range(0, len(points) - 1):
            newpoints += [Bezier.TwoPoints(t, points[i1], points[i1 + 1])]
        return newpoints

    def Point(t, points):
        """
        Returns a point interpolated by the Bezier process
        INPUTS:
            t            float/int; a parameterisation.
            points       list of numpy arrays; points.
        OUTPUTS:
            newpoint     numpy array; a point.
        """
        newpoints = points
        while len(newpoints) > 1:
            newpoints = Bezier.Points(t, newpoints)
        return newpoints[0]

    def Curve(t_values, points):
        """
        Returns a point interpolated by the Bezier process
        INPUTS:
            t_values     list of floats/ints; a parameterisation.
            points       list of numpy arrays; points.
        OUTPUTS:
            curve        list of numpy arrays; points.
        """

        if not hasattr(t_values, "__iter__"):
            raise TypeError(
                "`t_values` Must be an iterable of integers or floats, of length greater than 0 ."
            )
        if len(t_values) < 1:
            raise TypeError(
                "`t_values` Must be an iterable of integers or floats, of length greater than 0 ."
            )
        if not isinstance(t_values[0], (int, float)):
            raise TypeError(
                "`t_values` Must be an iterable of integers or floats, of length greater than 0 ."
            )

        curve = np.array([[0.0] * len(points[0])])
        for t in t_values:
            curve = np.append(curve, [Bezier.Point(t, points)], axis=0)

        curve = np.delete(curve, 0, 0)
        return curve
