#!/usr/bin/env python3

# Use the proper idiom in the main module ...
# NOTE: See https://docs.python.org/3.12/library/multiprocessing.html#the-spawn-and-forkserver-start-methods
if __name__ == "__main__":
    # Import standard modules ...
    import pathlib

    # Import special modules ...
    try:
        import cartopy
        cartopy.config.update(
            {
                "cache_dir" : pathlib.PosixPath("~/.local/share/cartopy").expanduser(),
            }
        )
        import cartopy.geodesic
    except:
        raise Exception("\"cartopy\" is not installed; run \"pip install --user Cartopy\"") from None
    try:
        import matplotlib
        matplotlib.rcParams.update(
            {
                       "axes.xmargin" : 0.01,
                       "axes.ymargin" : 0.01,
                            "backend" : "Agg",                                  # NOTE: See https://matplotlib.org/stable/gallery/user_interfaces/canvasagg.html
                         "figure.dpi" : 300,
                     "figure.figsize" : (9.6, 7.2),                             # NOTE: See https://github.com/Guymer/misc/blob/main/README.md#matplotlib-figure-sizes
                          "font.size" : 8,
                "image.interpolation" : "none",                                 # NOTE: See https://matplotlib.org/stable/gallery/images_contours_and_fields/interpolation_methods.html
                     "image.resample" : False,
            }
        )
        import matplotlib.pyplot
    except:
        raise Exception("\"matplotlib\" is not installed; run \"pip install --user matplotlib\"") from None
    try:
        import numpy
    except:
        raise Exception("\"numpy\" is not installed; run \"pip install --user numpy\"") from None
    try:
        import shapely
        import shapely.geometry
    except:
        raise Exception("\"shapely\" is not installed; run \"pip install --user Shapely\"") from None

    # Import my modules ...
    try:
        import pyguymer3
        import pyguymer3.geo
        import pyguymer3.image
    except:
        raise Exception("\"pyguymer3\" is not installed; run \"pip install --user PyGuymer3\"") from None

    # **************************************************************************

    # Define point ...
    lon = -9.144020                                                             # [°]
    lat = 38.719144                                                             # [°]

    # Define buffering parameters ...
    dist = 1000.0e3                                                             # [m]
    nAng = 9

    # Create an array based off the scalars ...
    pnt = numpy.zeros((1, 2), dtype = numpy.float64)                            # [°]
    pnt[0, 0] = lon                                                             # [°]
    pnt[0, 1] = lat                                                             # [°]

    # **************************************************************************

    # Buffer point using Cartopy ...
    # NOTE: Cartopy does not close the loop, so I must use one fewer points
    #       during the buffer and then manually add the 12 o'clock position on
    #       the end.
    # NOTE: Cartopy just passes the list of point directly to Shapely when
    #       making a Tissot circle, see:
    #         * https://scitools.org.uk/cartopy/docs/latest/_modules/cartopy/mpl/geoaxes.html#GeoAxes.tissot
    ring1 = cartopy.geodesic.Geodesic().circle(
        lon,
        lat,
        dist,
        n_samples = nAng - 1,
    )                                                                           # [°]
    ring1 = numpy.concatenate([ring1, [ring1[0, :]]])                           # [°]
    poly1 = shapely.geometry.Polygon(ring1)

    # Buffer point using PyGuymer3 ...
    ring2 = pyguymer3.geo._buffer_points_crudely(                               # pylint: disable=W0212
        pnt,
        dist,
        nAng,
    )[0, :, :]                                                                  # [°]
    poly2 = shapely.geometry.Polygon(ring2)

    # **************************************************************************

    # Create figure ...
    fg = matplotlib.pyplot.figure()

    # Create axis ...
    ax1 = pyguymer3.geo.add_axis(
        fg,
        index = 1,
        ncols = 2,
        nrows = 2,
    )

    # Create axis ...
    ax2 = pyguymer3.geo.add_axis(
        fg,
        index = 2,
          lat = lat,
          lon = lon,
        ncols = 2,
        nrows = 2,
    )

    # Create axis ...
    ax3 = fg.add_subplot(
        2,
        2,
        (3, 4),
    )

    # Configure axis ...
    pyguymer3.geo.add_map_background(ax1, subName = "large8192px")

    # Configure axis ...
    pyguymer3.geo.add_map_background(ax2, subName = "large8192px")

    # Configure axis ...
    ax3.grid()
    ax3.set_aspect("equal")
    ax3.set_xlabel("Longitude [°]")
    ax3.set_xlim(-180.0, +180.0)
    ax3.set_xticks(range(-180, 225, 45))
    ax3.set_ylabel("Latitude [°]")
    ax3.set_ylim(-90.0, +90.0)
    ax3.set_yticks(range(-90, 135, 45))

    # Plot Cartopy buffer thrice ...
    ax1.plot(
        ring1[:, 0],
        ring1[:, 1],
            color = (1.0, 0.0, 0.0, 1.0),
        linestyle = "--",
           marker = "o",
        transform = cartopy.crs.PlateCarree(),
    )
    ax1.add_geometries(
        [poly1],
        cartopy.crs.PlateCarree(),
        edgecolor = "none",
        facecolor = (1.0, 0.0, 0.0, 0.5),
        linewidth = 1.0,
    )
    ax2.plot(
        ring1[:, 0],
        ring1[:, 1],
            color = (1.0, 0.0, 0.0, 1.0),
        linestyle = "--",
           marker = "o",
        transform = cartopy.crs.PlateCarree(),
    )
    ax2.add_geometries(
        [poly1],
        cartopy.crs.PlateCarree(),
        edgecolor = "none",
        facecolor = (1.0, 0.0, 0.0, 0.5),
        linewidth = 1.0,
    )
    ax3.plot(
        ring1[:, 0],
        ring1[:, 1],
            color = (1.0, 0.0, 0.0, 1.0),
        linestyle = "--",
           marker = "o",
    )

    # Plot PyGuymer3 buffer thrice ...
    ax1.plot(
        ring2[:, 0],
        ring2[:, 1],
            color = (0.0, 0.0, 1.0, 1.0),
        transform = cartopy.crs.PlateCarree(),
    )
    ax1.add_geometries(
        [poly2],
        cartopy.crs.PlateCarree(),
        edgecolor = "none",
        facecolor = (0.0, 0.0, 1.0, 0.5),
        linewidth = 1.0,
    )
    ax2.plot(
        ring2[:, 0],
        ring2[:, 1],
            color = (0.0, 0.0, 1.0, 1.0),
        transform = cartopy.crs.PlateCarree(),
    )
    ax2.add_geometries(
        [poly2],
        cartopy.crs.PlateCarree(),
        edgecolor = "none",
        facecolor = (0.0, 0.0, 1.0, 0.5),
        linewidth = 1.0,
    )
    ax3.plot(
        ring2[:, 0],
        ring2[:, 1],
        color = (0.0, 0.0, 1.0, 1.0),
    )

    # Configure figure ...
    fg.suptitle(f"({lon:.1f}°,{lat:.1f}°) buffered by {0.001 * dist:,.1f} km\nCartopy in red; PyGuymer3 in blue")
    fg.tight_layout()

    # Save figure ...
    fg.savefig("lisbon.png")
    matplotlib.pyplot.close(fg)

    # Optimise PNG ...
    pyguymer3.image.optimise_image("lisbon.png", strip = True)
