import time

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

from plot_helpers import CO, bold_ticks


def fig6_3():
    # this includes Fig 6.3, Table 6.1, and Fig 6.4

    # Integrate f(x) over [a, b] using midpoint rule
    #
    # Inputs:
    #       a = left endpoint of interval
    #       b = right endpoint of interval
    #       n = number of subintervals
    #

    a = 0
    b = 1

    exact = (np.exp(3) - 1) / 3
    n = 40
    interv = np.array([500, 1000, 2000, 4000, 8000, 16000, 32000, 64000])
    nk = len(interv)
    M = np.zeros(nk)
    err = np.zeros(nk)

    for k in range(nk):
        n = int(interv[k])
        tic = time.perf_counter()
        M[k] = midpt(a, b, n)
        print(f"Elapsed time: {time.perf_counter() - tic:.6f} seconds")
        err[k] = abs(exact - M[k])

    # table 6.1
    print("\n RIE = relative iterative error \n")
    print(" k \t  n  \t\t I_M \t \t Error \t\t RIE")
    R = np.zeros(nk - 1)
    for k in range(nk):
        if k == 0:
            print(f" {1:d} \t {interv[k]:d}\t {M[k]:19.15f} \t {err[k]:5.1e}")
            # print('\\, %i \\, & ...')
        else:
            R[k - 1] = abs((M[k] - M[k - 1]) / M[k])
            print(
                f" {k + 1:d} \t {interv[k]:d} \t {M[k]:19.15f} "
                f"\t {err[k]:5.1e}  \t {R[k - 1]:5.1e}"
            )
            # print('\\, %i \\, & ...')
    print()

    # fig 6.3
    fig1, ax1 = plt.subplots(figsize=(8.8, 3.3))
    fig1.subplots_adjust(left=0.08, right=0.98, bottom=0.22, top=0.98)
    ax1.set_prop_cycle(cycler(color=CO))

    n = 3
    xd = np.linspace(a, b, n + 1)
    h = xd[1] - xd[0]
    for in_ in range(n):
        ax1.plot(
            [xd[in_], xd[in_ + 1]],
            [f(xd[in_] + 0.5 * h), f(xd[in_] + 0.5 * h)],
            "--r",
            linewidth=2,
        )
        ax1.plot(
            [xd[in_], xd[in_]],
            [0, f(xd[in_] + 0.5 * h)],
            "--r",
            linewidth=2,
        )
    ax1.plot([b, b], [0, f(xd[n - 1] + 0.5 * h)], "--r", linewidth=2)

    nx = 100
    x = np.linspace(a, b, nx)
    y = np.zeros(nx)
    for ix in range(nx):
        y[ix] = f(x[ix])

    ax1.plot(x, y, linewidth=1.6)
    # ax1.grid(True)
    ax1.set_xlabel("x-axis")
    ax1.set_ylabel("y-axis")
    ax1.set_xlim(0, 1)
    ax1.set_ylim(0, 20)
    ax1.set_xticks([0, 1 / 6, 1 / 3, 1 / 2, 2 / 3, 5 / 6, 1])
    ax1.set_xticklabels(["0", "1/6", "1/3", "1/2", "2/3", "5/6", "1"])
    # ax1.yaxis.grid(False, which="minor")
    bold_ticks(ax1, 14)
    for spine in ax1.spines.values():
        spine.set_visible(True)

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

    # fig 6.4
    fig2, ax2 = plt.subplots(figsize=(8.8, 3.3))
    fig2.subplots_adjust(left=0.10, right=0.98, bottom=0.22, top=0.98)
    ax2.set_prop_cycle(cycler(color=CO))

    ax2.loglog(interv, err, "--ob", markersize=8, linewidth=1.6)
    ax2.loglog(interv[1:nk], R, "--*r", markersize=8, linewidth=1.6)
    ax2.grid(True)
    ax2.set_xlim(1e3, 1e5)
    ax2.set_ylim(1e-10, 1e-5)
    ax2.set_yticks([1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5])
    ax2.set_xlabel("n-axis")
    ax2.set_ylabel("Error")
    ax2.legend(
        [" Error", " RIE"],
        loc="upper right",
        prop={"size": 14, "weight": "bold"},
    )
    bold_ticks(ax2, 14)

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


def f(x):
    y = np.exp(3 * x)
    return y


### composite midpoint: n = number of subintervals
def midpt(a, b, n):
    xd = np.linspace(a, b, n + 1)
    h = xd[1] - xd[0]
    s = 0.0
    for j in range(n):
        s = s + f(xd[j] + 0.5 * h)
    s = h * s
    return s


if __name__ == "__main__":
    fig6_3()
