#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
#
# Project:  GDAL/OGR Test Suite
# Purpose:  Generate test_s102.h5
# Author:   Even Rouault <even dot rouault at spatialys.com>
#
###############################################################################
# Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
#
# SPDX-License-Identifier: MIT
###############################################################################

import os

import h5py
import numpy as np


def generate(
    filename,
    version,
    with_QualityOfSurvey=False,
    with_QualityOfCoverage=False,
    use_compound_type_for_Quality=False,
    nodata=1e6,
    with_uncertainty=True,
):
    f = h5py.File(os.path.join(os.path.dirname(__file__), f"{filename}.h5"), "w")
    BathymetryCoverage = f.create_group("BathymetryCoverage")
    BathymetryCoverage_01 = BathymetryCoverage.create_group("BathymetryCoverage.01")
    Group_001 = BathymetryCoverage_01.create_group("Group_001")

    if with_uncertainty:
        values_struct_type = np.dtype(
            [
                ("depth", "f4"),
                ("uncertainty", "f4"),
            ]
        )
    else:
        values_struct_type = np.dtype(
            [
                ("depth", "f4"),
            ]
        )
    values = Group_001.create_dataset("values", (2, 3), dtype=values_struct_type)
    data = np.array(
        [(0, 100), (1, 101), (2, 102), (1e6, 103), (4, 1e6), (5, 105)]
        if with_uncertainty
        else [(0,), (1,), (2,), (1e6,), (4,), (5,)],
        dtype=values_struct_type,
    ).reshape(values.shape)
    values[...] = data

    if with_uncertainty:
        Group_001.attrs["minimumUncertainty"] = np.float32(100)
        Group_001.attrs["maximumUncertainty"] = np.float32(105)
    Group_001.attrs["minimumDepth"] = np.float32(0)
    Group_001.attrs["maximumDepth"] = np.float32(5)

    BathymetryCoverage_01.attrs["gridOriginLongitude"] = np.float64(2)
    BathymetryCoverage_01.attrs["gridOriginLatitude"] = np.float64(48)
    BathymetryCoverage_01.attrs["gridSpacingLongitudinal"] = np.float64(0.4)
    BathymetryCoverage_01.attrs["gridSpacingLatitudinal"] = np.float64(0.5)
    BathymetryCoverage_01.attrs["numPointsLongitudinal"] = np.uint32(values.shape[1])
    BathymetryCoverage_01.attrs["numPointsLatitudinal"] = np.uint32(values.shape[0])

    group_f = f.create_group("Group_F")

    f.attrs["issueDate"] = "2023-12-31"
    f.attrs["geographicIdentifier"] = "Somewhere"
    f.attrs["verticalDatum"] = np.int16(12)
    if version >= "INT.IHO.S-102.2.2":
        f.attrs["horizontalCRS"] = np.int32(4326)
        f.attrs["verticalCS"] = np.int32(6498)  # Depth, metres, orientation down
        f.attrs["verticalCoordinateBase"] = np.int32(2)
        f.attrs["verticalDatumReference"] = np.int32(1)
    else:
        assert version == "INT.IHO.S-102.2.1"
        f.attrs["horizontalDatumReference"] = "EPSG"
        f.attrs["horizontalDatumValue"] = np.int32(4326)
    f.attrs["productSpecification"] = version
    f.attrs[
        "producer"
    ] = "Generated by autotest/gdrivers/data/s102/generate_test.py (not strictly fully S102 compliant)"
    f.attrs["metadata"] = f"MD_{filename}.xml"

    open(os.path.join(os.path.dirname(__file__), f.attrs["metadata"]), "wb").write(
        b"<nothing/>"
    )

    GroupFQuality_struct_type = np.dtype(
        [
            ("code", "S16"),
            ("name", "S16"),
            ("uom.name", "S16"),
            ("fillValue", "S16"),
            ("datatype", "S16"),
            ("lower", "S16"),
            ("upper", "S16"),
            ("closure", "S16"),
        ]
    )
    GroupFQuality = group_f.create_dataset(
        "BathymetryCoverage",
        (2,) if with_uncertainty else (1,),
        dtype=GroupFQuality_struct_type,
    )
    GroupFQuality[...] = np.array(
        [
            ("depth", "", "", str(nodata), "H5T_FLOAT", "", "", "geSemiInterval"),
            ("uncertainty", "", "", str(nodata), "H5T_FLOAT", "", "", "geSemiInterval"),
        ]
        if with_uncertainty
        else [("depth", "", "", str(nodata), "H5T_FLOAT", "", "", "geSemiInterval")],
        dtype=GroupFQuality_struct_type,
    )

    if with_QualityOfSurvey or with_QualityOfCoverage:
        quality_name = (
            "QualityOfSurvey" if with_QualityOfSurvey else "QualityOfBathymetryCoverage"
        )
        qualityGroup = f.create_group(quality_name)
        quality01Group = qualityGroup.create_group(quality_name + ".01")

        for attr_name in (
            "gridOriginLongitude",
            "gridOriginLatitude",
            "gridSpacingLongitudinal",
            "gridSpacingLatitudinal",
            "numPointsLongitudinal",
            "numPointsLatitudinal",
        ):
            quality01Group.attrs[attr_name] = BathymetryCoverage_01.attrs[attr_name]

        Group_001 = quality01Group.create_group("Group_001")

        if use_compound_type_for_Quality:
            # As found in product 102DE00CA22_UNC_MD.H5
            data_struct_type = np.dtype([("iD", "u4")])
            values = Group_001.create_dataset("values", (2, 3), dtype=data_struct_type)
            data = np.array(
                [(0), (1), (2), (1000000), (3), (2)],
                dtype=data_struct_type,
            ).reshape(values.shape)
            values[...] = data
        else:
            values = Group_001.create_dataset("values", (2, 3), dtype=np.uint32)
            data = np.array(
                [0, 1, 2, 1000000, 3, 2],
                dtype=np.uint32,
            ).reshape(values.shape)
            values[...] = data

        featureAttributeTable_struct_type = np.dtype(
            [
                ("id", "u4"),
                ("floatval", "f4"),
                ("strval", "S2"),
            ]
        )

        featureAttributeTable = qualityGroup.create_dataset(
            "featureAttributeTable", (5,), dtype=featureAttributeTable_struct_type
        )

        data = np.array(
            [
                (0, 1.5, "a"),
                (1, 2.5, "b"),
                (2, 3.5, "c"),
                (3, 4.5, "d"),
                (1000000, 5.5, "e"),
            ],
            dtype=featureAttributeTable_struct_type,
        )
        featureAttributeTable[...] = data

        GroupFQuality_struct_type = np.dtype(
            [
                ("code", "S16"),
                ("name", "S16"),
                ("uom.name", "S16"),
                ("fillValue", "S16"),
                ("datatype", "S16"),
                ("lower", "S16"),
                ("upper", "S16"),
                ("closure", "S16"),
            ]
        )
        GroupFQuality = group_f.create_dataset(
            quality_name, (1,), dtype=GroupFQuality_struct_type
        )
        GroupFQuality[...] = np.array(
            [("id", "", "", "0", "H5T_INTEGER", "1", "", "geSemiInterval")],
            dtype=GroupFQuality_struct_type,
        )


generate("test_s102_v2.1", "INT.IHO.S-102.2.1")
generate("test_s102_v2.2", "INT.IHO.S-102.2.2")

generate(
    "test_s102_v2.2_with_QualityOfSurvey_nodata_0",
    "INT.IHO.S-102.2.2",
    with_QualityOfSurvey=True,
    nodata=0,
)

generate(
    "test_s102_v3.0_with_QualityOfBathymetryCoverage",
    "INT.IHO.S-102.3.0.0",
    with_QualityOfCoverage=True,
    use_compound_type_for_Quality=True,
)

generate(
    "test_s102_v3.0_without_uncertainty_nodata_0",
    "INT.IHO.S-102.3.0.0",
    with_QualityOfCoverage=True,
    use_compound_type_for_Quality=True,
    with_uncertainty=False,
    nodata=0,
)
