#!/usr/bin/env python3

# Use the proper idiom in the main module ...
# NOTE: See https://docs.python.org/3.13/library/multiprocessing.html#the-spawn-and-forkserver-start-methods
if __name__ == "__main__":
    # NOTE: The following articles are worth a read:
    #         * https://getoutside.ordnancesurvey.co.uk/guides/beginners-guide-to-grid-references/
    #         * https://www.ordnancesurvey.co.uk/documents/resources/guide-coordinate-systems-great-britain.pdf
    # NOTE: I downloaded the "GB Overview Maps" dataset from the Ordnance
    #       Survey, see:
    #         * https://www.ordnancesurvey.co.uk/business-government/products/gb-overview
    #       This gave me the "Over_gb.zip" file that is used here.

    # Import standard modules ...
    import io
    import json
    import os
    import zipfile

    # Import special modules ...
    try:
        import PIL
        import PIL.Image
        PIL.Image.MAX_IMAGE_PIXELS = 1024 * 1024 * 1024                         # [px]
        import PIL.TiffTags
    except:
        raise Exception("\"PIL\" is not installed; run \"pip install --user Pillow\"") from None

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

    # Initialize dictionary ...
    meta = {}

    # Make folders if they are missing ...
    for dname in ["overview/colour", "overview/greyscale"]:
        if not os.path.exists(dname):
            os.makedirs(dname)

    # Load dataset ...
    with zipfile.ZipFile("Over_gb.zip", mode = "r") as zObj:
        # Loop over members ...
        for tif in zObj.namelist():
            # Skip this member if it is not a data TIF ...
            if not tif.lower().endswith(".tif"):
                continue

            # Extract view name ...
            view = os.path.basename(tif).removesuffix(".tif")

            # Deduce colour and greyscale PNG names ...
            png1 = f"overview/colour/{view}.png"
            png2 = f"overview/greyscale/{view}.png"

            # Read data TIF into RAM so that it becomes seekable ...
            # NOTE: https://stackoverflow.com/a/12025492
            tObj = io.BytesIO(zObj.read(tif))

            # Open image as RGB (even if it is paletted) ...
            with PIL.Image.open(tObj) as iObj:
                img = iObj.convert("RGB")
                exif = iObj.getexif()

            # Loop over data TIF metadata and populate the dictionary with the
            # data TIF's extent ...
            # NOTE: The tie point is the upper-left corner of the data TIF and
            #       Cartopy wants the lower-left corner.
            dx, dy = None, None                                                 # [m/px], [m/px]
            xmin, xmax, ymin, ymax = None, None, None, None                     # [m], [m], [m], [m]
            for key, val in exif.items():
                if PIL.TiffTags.TAGS[key] == "ModelPixelScaleTag":
                    dx, dy = val[0], val[1]                                     # [m/px], [m/px]
                if PIL.TiffTags.TAGS[key] == "ModelTiepointTag":
                    xmin, ymax = val[3], val[4]                                 # [m], [m]
            if dx is None or dy is None:
                raise Exception("failed to extract \"ModelPixelScaleTag\"") from None
            if xmin is None or ymax is None:
                raise Exception("failed to extract \"ModelTiepointTag\"") from None
            xmax = xmin + img.size[0] * dx                                      # [m]
            ymin = ymax - img.size[1] * dy                                      # [m]
            meta[view] = {
                   "colour" : png1,
                "greyscale" : png2,
                   "extent" : [xmin, xmax, ymin, ymax],
            }

            # Check if the PNG is missing ...
            if not os.path.exists(png1):
                print(f"Making \"{png1}\" ...")

                # Save PNG ...
                img.save(png1, optimize = True)
                pyguymer3.image.optimise_image(
                    png1,
                      strip = True,
                    timeout = 3600.0,   # NOTE: Would normally be "60.0".
                )

            # Check if the PNG is missing ...
            if not os.path.exists(png2):
                print(f"Making \"{png2}\" ...")

                # Save PNG ...
                img.convert("L").save(png2, optimize = True)
                pyguymer3.image.optimise_image(
                    png2,
                      strip = True,
                    timeout = 3600.0,   # NOTE: Would normally be "60.0".
                )

        # Save JSON ...
        with open("overview.json", mode = "wt", encoding = "utf-8") as fObj:
            json.dump(
                meta,
                fObj,
                ensure_ascii = False,
                      indent = 4,
                   sort_keys = True,
            )
