#!/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__":
    # NOTE: "The Database of British and Irish Hills" can be visited here:
    #         * http://www.hills-database.co.uk/
    #       ... and the links to download the database can be found here:
    #         * http://www.hills-database.co.uk/downloads.html
    # NOTE: https://en.wikipedia.org/wiki/List_of_P600_mountains_in_the_British_Isles

    # Import standard modules ...
    import csv
    import json
    import os
    import pathlib
    import zipfile

    # Import special modules ...
    try:
        import cartopy
        cartopy.config.update(
            {
                "cache_dir" : pathlib.PosixPath("~/.local/share/cartopy").expanduser(),
            }
        )
    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

    # 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

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

    # Start session ...
    with pyguymer3.start_session() as sess:
        # Check if the database is missing ...
        if not os.path.exists("hillcsv.zip"):
            # Download the database ...
            pyguymer3.download_file(sess, "http://www.hills-database.co.uk/hillcsv.zip", "hillcsv.zip")

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

    # Initialize counter ...
    n = 0                                                                       # [#]

    # Initialize lists ...
    x = []                                                                      # [°]
    y = []                                                                      # [°]
    z = []                                                                      # [m]
    xRaw = []                                                                   # [°]
    yRaw = []                                                                   # [°]

    # Open output file ...
    with open("british-hills-P600.txt", "wt", encoding = "utf-8") as fObjOut:
        # Open input file ...
        with zipfile.ZipFile("hillcsv.zip", "r") as fObjIn:
            # Loop over members ...
            for fname in fObjIn.namelist():
                # Skip those that are not CSVs ...
                if not fname.endswith(".csv"):
                    continue

                # Read CSV dataset as a list of strings ...
                rows = fObjIn.read(fname).decode("ascii").splitlines()

                # Loop over rows ...
                for row in csv.DictReader(rows):
                    # Append to lists ...
                    xRaw.append(float(row["Longitude"]))                        # [°]
                    yRaw.append(float(row["Latitude"]))                         # [°]

                    # Skip this row if the prominence is too small ...
                    if float(row["Drop"]) < 600.0:
                        continue

                    # Increment counter ...
                    n += 1                                                      # [#]

                    # Append to lists ...
                    x.append(float(row["Longitude"]))                           # [°]
                    y.append(float(row["Latitude"]))                            # [°]
                    z.append(float(row["Drop"]))                                # [m]

                    # Write summary ...
                    fObjOut.write(f'"{row["Name"]}" is {float(row["Metres"]):,.1f}m ASL with a prominence of {float(row["Drop"]):,.1f}m at ({float(row["Latitude"]):f}°,{float(row["Longitude"]):f}°).\n')

    # Print summary ...
    print(f"There are {n:,d} P600 mountains in The British Isles.")

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

    # Load tile metadata ...
    with open("OrdnanceSurveyBackgroundImages/miniscale.json", "rt", encoding = "utf-8") as fObj:
        meta = json.load(fObj)

    # Convert lists to arrays and find the sorted keys ...
    x = numpy.array(x)                                                          # [°]
    y = numpy.array(y)                                                          # [°]
    z = numpy.array(z)                                                          # [m]
    k = numpy.argsort(z)
    xRaw = numpy.array(xRaw)                                                    # [°]
    yRaw = numpy.array(yRaw)                                                    # [°]

    # Find middle of points and the furthest distance ...
    midLon, midLat, maxDist = pyguymer3.geo.find_middle_of_locs(
        xRaw,
        yRaw,
        pad = 12.0 * 1852.0,
    )                                                                           # [°], [°], [m]

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

    # Create axis ...
    ax = pyguymer3.geo.add_axis(
        fg,
        debug = False,
         dist = maxDist,
          lat = midLat,
          lon = midLon,
    )

    # Add background image ...
    ax.imshow(
        matplotlib.pyplot.imread(f'OrdnanceSurveyBackgroundImages/{meta["MiniScale_(mono)_R22"]["greyscale"]}'),
             cmap = "gray",
           extent = meta["MiniScale_(mono)_R22"]["extent"],
           origin = "upper",
        transform = cartopy.crs.OSGB(),
             vmax = 1.0,
             vmin = 0.0,
    )

    # Plot data (layering them correctly) ...
    # NOTE: As of 5/Dec/2023, the default "zorder" of the coastlines is 1.5, the
    #       default "zorder" of the gridlines is 2.0 and the default "zorder" of
    #       the scattered points is 1.0.
    sc = ax.scatter(
        x[k],
        y[k],
                 c = z[k],
              cmap = matplotlib.colormaps["turbo"],
        edgecolors = "black",
         linewidth = 0.1,
                 s = 10.0,
         transform = cartopy.crs.PlateCarree(),
              vmin = 600.0,
            zorder = 5.0,
    )

    # Add colour bar ...
    cb = fg.colorbar(sc, ax = ax, orientation = "vertical")

    # Configure axis ...
    ax.set_title("P600 Mountains In The British Isles")

    # Configure colour bar ...
    cb.set_label("Prominence [m]")

    # Configure figure ...
    fg.tight_layout()

    # Save figure ...
    fg.savefig("british-hills-P600.png")
    matplotlib.pyplot.close(fg)

    # Optimize PNG ...
    pyguymer3.image.optimise_image("british-hills-P600.png", strip = True)
