#!/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(),
            }
        )
    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 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

    # List countries to find the antipodes of ...
    avoids = [
        "United Kingdom",
        "United States of America",
    ]

    # List global quadrants ...
    quads = [
        shapely.geometry.polygon.Polygon(
            [
                (   0.0,   0.0),
                (   0.0,  90.0),
                ( 180.0,  90.0),
                ( 180.0,   0.0),
                (   0.0,   0.0),
            ]
        ),
        shapely.geometry.polygon.Polygon(
            [
                (   0.0,   0.0),
                (   0.0,  90.0),
                (-180.0,  90.0),
                (-180.0,   0.0),
                (   0.0,   0.0),
            ]
        ),
        shapely.geometry.polygon.Polygon(
            [
                (   0.0,   0.0),
                (   0.0, -90.0),
                ( 180.0, -90.0),
                ( 180.0,   0.0),
                (   0.0,   0.0),
            ]
        ),
        shapely.geometry.polygon.Polygon(
            [
                (   0.0,   0.0),
                (   0.0, -90.0),
                (-180.0, -90.0),
                (-180.0,   0.0),
                (   0.0,   0.0),
            ]
        ),
    ]

    # Define function ...
    def flip_geom(geomIN, /):
        # Create list to hold its transposed coordinates ...
        coords = []

        # Loop over coordinates in the external ring, transpose them and add
        # them to the list ...
        for coord in geomIN.exterior.coords:
            x, y = coord                                                        # [°], [°]
            if geomIN.bounds[0] <= 0.0 and geomIN.bounds[2] <= 0.0:
                coords.append((x + 180.0, -y))
            elif geomIN.bounds[0] >= 0.0 and geomIN.bounds[2] >= 0.0:
                coords.append((x - 180.0, -y))
            else:
                raise Exception("the geom crosses the anti-meridian") from None

        # Check that coordinates were added ...
        if len(coords) == 0:
            raise Exception("no coords were added") from None

        # Return polygon from the transposed coordinates of the geometry ...
        return shapely.geometry.polygon.Polygon(coords)

    # Create figure ...
    fg = matplotlib.pyplot.figure(figsize = (12.8, 7.2))

    # Create axis ...
    ax = pyguymer3.geo.add_axis(fg)

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

    # Find file containing all the country shapes ...
    sfile = cartopy.io.shapereader.natural_earth(
          category = "cultural",
              name = "admin_0_countries",
        resolution = "10m",
    )

    # Loop over records ...
    for record in cartopy.io.shapereader.Reader(sfile).records():
        # Create short-hand ...
        neName = pyguymer3.geo.getRecordAttribute(record, "NAME")

        # Set country opacity ...
        alpha = 0.25
        if neName in avoids:
            alpha = 0.5

        # Create list to hold the transposed polygons ...
        polys = []

        # Loop over Polygons ...
        for geom in pyguymer3.geo.extract_polys(record.geometry):
            # Find bounds ...
            xmin, ymin, xmax, ymax = geom.bounds                                # [°], [°], [°], [°]

            # Check if this Polygon needs splitting ...
            # NOTE: See https://en.wikipedia.org/wiki/180th_meridian#Software_representation_problems
            if not (xmin < 0.0 and xmax < 0.0) and not (xmin > 0.0 and xmax > 0.0):
                # Loop over quadrants ...
                for quad in quads:
                    # Find intersection of Polygon with quadrant ...
                    tmp = geom.intersection(quad)

                    # Skip this intersection if it is empty ...
                    if tmp.is_empty:
                        continue

                    # Loop over Polygons ...
                    for poly in pyguymer3.geo.extract_polys(tmp):
                        # Add flipped sub-intersection to list ...
                        polys.append(flip_geom(poly))
            else:
                # Add flipped geometry to list ...
                polys.append(flip_geom(geom))

        # Fill the country in ...
        if len(polys) > 0:
            ax.add_geometries(
                polys,
                cartopy.crs.PlateCarree(),
                    alpha = alpha,
                edgecolor = "red",
                facecolor = "red",
                linewidth = 0.5,
            )

    # Configure figure ...
    fg.tight_layout()

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

    # Optimize PNG ...
    pyguymer3.image.optimise_image(
        "find_antipode.png",
        strip = True,
    )
