import numpy as np
import matplotlib.pyplot as plt
from cycler import cycler


def fig5_12():
    # plots the B-spline function

    x0 = -3.0
    x1 = 3.0
    nx = 201
    x = np.linspace(x0, x1, nx)

    exact = np.zeros(nx)
    exactA = np.zeros(nx)
    exactB = np.zeros(nx)
    for ix in range(nx):
        exact[ix] = bspline(x[ix])
        exactA[ix] = bspline(x[ix] - 1)
        exactB[ix] = bspline(x[ix] + 1)

    plt.close("all")
    # get(gcf)
    fig, ax = plt.subplots(figsize=(9.0, 3.2))
    fig.subplots_adjust(left=0.09, right=0.97, bottom=0.24, top=0.98)
    co = np.array([
        [0, 0, 1],
        [0, 0.5, 0],
        [1, 0, 0],
        [0, 0.75, 0.75],
        [0.75, 0, 0.75],
        [0.75, 0.75, 0],
        [0.25, 0.25, 0.25],
    ])
    ax.set_prop_cycle(cycler(color=co))

    ax.plot(x, exactB, "--k", linewidth=1)
    ax.plot(x, exact, "b", linewidth=1.5)
    ax.plot(x, exactA, "--r", linewidth=1.5)

    ax.set_xlabel(" ")
    ax.set_ylabel("B-Spline")
    ax.set_xlim(x0, x1)
    ax.set_ylim(0, 0.71)
    ax.grid(True)
    ax.set_xticks(np.arange(-3, 4))
    ax.set_xticklabels([" ", " ", " ", " ", " ", " ", " "])
    yH = -0.08
    ax.text(-2.13, yH, r"$x_{i-2}$", fontsize=20, clip_on=False)
    ax.text(-1.15, yH, r"$x_{i-1}$", fontsize=20, clip_on=False)
    ax.text(-0.13, yH, r"$x_{i}$", fontsize=20, clip_on=False)
    ax.text(0.87, yH, r"$x_{i+1}$", fontsize=20, clip_on=False)
    ax.text(1.9, yH, r"$x_{i+2}$", fontsize=20, clip_on=False)

    ax.set_yticks([0, 1 / 6, 2 / 3])
    ax.set_yticklabels(["0", r"$1/6$", r"$2/3$"])
    ax.tick_params(labelsize=14)

    ax.legend(
        [r" $B_{i-1}$", r" $B_i$", r" $B_{i+1}$"],
        loc="upper left",
        prop={"size": 14, "weight": "bold"},
    )
    plt.show()

    # plt.savefig('/Users/mark/Desktop/bspline.eps')


def bspline(x):
    # Calculate the value of a cubic B-spline at point x
    x = abs(x)
    if x > 2:
        y = 0
    else:
        if x > 1:
            y = (2 - x) ** 3 / 6
        else:
            y = 2 / 3 - x ** 2 * (1 - x / 2)
    return y


if __name__ == "__main__":
    fig5_12()
