#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id$
#
# Project:  GDAL/OGR Test Suite
# Purpose:  Test read functionality for S104 driver.
# Author:   Even Rouault <even dot rouault at spatialys.com>
#
###############################################################################
# Copyright (c) 2023, Even Rouault <even dot rouault at spatialys.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
###############################################################################

import os
import struct

import pytest

from osgeo import gdal

pytestmark = pytest.mark.require_driver("S104")


###############################################################################


def test_s104_basic():
    filename = "data/s104/test_s104_v1.1.h5"
    ds = gdal.Open(filename)
    assert ds.RasterCount == 0
    assert ds.RasterXSize == 3
    assert ds.RasterYSize == 2
    assert ds.GetSpatialRef().GetAuthorityCode(None) == "4326"
    assert ds.GetGeoTransform() == pytest.approx((1.8, 0.4, 0.0, 48.75, 0.0, -0.5))
    assert ds.GetMetadata_Dict() == {
        "AREA_OR_POINT": "Point",
        "dateTimeOfFirstRecord": "20190606T120000Z",
        "dateTimeOfLastRecord": "20190606T120000Z",
        "geographicIdentifier": "Somewhere",
        "issueDate": "2023-12-31",
        "maxDatasetHeight": "2",
        "minDatasetHeight": "1",
        "numberOfTimes": "1",
        "producer": "Generated by autotest/gdrivers/data/s104/generate_test.py (not strictly fully S104 compliant)",
        "timeRecordInterval": "3600",
        "VERTICAL_DATUM_ABBREV": "MLLW",
        "VERTICAL_DATUM_MEANING": "meanLowerLowWater",
    }

    assert ds.GetSubDatasets() == [
        (
            f'S104:"{filename}":Group_001',
            "Values at timestamp 20190606T120000Z",
        )
    ]

    with pytest.raises(
        Exception, match="Cannot find /WaterLevel/WaterLevel.01/invalid group"
    ):
        gdal.Open(f'S104:"{filename}":invalid')

    ds = gdal.Open(f'S104:"{filename}":Group_001')

    band = ds.GetRasterBand(1)
    assert band.GetDescription() == "waterLevelHeight"
    assert band.GetNoDataValue() == -123
    assert band.GetUnitType() == "metre"
    assert struct.unpack("f" * 6, band.ReadRaster()) == (
        3.0,
        4.0,
        5.0,
        -123.0,
        1.0,
        2.0,
    )

    band = ds.GetRasterBand(2)
    assert band.GetDescription() == "waterLevelTrend"
    assert band.GetNoDataValue() == 0
    assert struct.unpack("B" * 6, band.ReadRaster()) == (3, 2, 1, 0, 1, 2)

    rat = band.GetDefaultRAT()
    assert rat is not None
    assert rat.GetRowCount() == 4
    assert rat.GetColumnCount() == 3

    assert rat.GetNameOfCol(0) == "code"
    assert rat.GetTypeOfCol(0) == gdal.GFT_Integer

    assert rat.GetNameOfCol(1) == "label"
    assert rat.GetTypeOfCol(1) == gdal.GFT_String

    assert rat.GetNameOfCol(2) == "definition"
    assert rat.GetTypeOfCol(2) == gdal.GFT_String

    assert rat.GetValueAsInt(1, 0) == 1
    assert rat.GetValueAsString(1, 1) == "Decreasing"

    assert rat.GetValueAsInt(2, 0) == 2
    assert rat.GetValueAsString(2, 1) == "Increasing"

    assert rat.GetValueAsInt(3, 0) == 3
    assert rat.GetValueAsString(3, 1) == "Steady"

    assert "MD_" in ds.GetFileList()[1]

    del ds
    assert not os.path.exists(f"{filename}.aux.xml")


###############################################################################


def test_s104_north_up_no():
    filename = "data/s104/test_s104_v1.1.h5"
    ds = gdal.OpenEx(f'S104:"{filename}":Group_001', open_options=["NORTH_UP=NO"])
    assert ds.RasterCount == 2
    assert ds.RasterXSize == 3
    assert ds.RasterYSize == 2
    assert ds.GetSpatialRef().GetAuthorityCode(None) == "4326"
    assert ds.GetGeoTransform() == pytest.approx((1.8, 0.4, 0.0, 47.75, 0.0, 0.5))

    band = ds.GetRasterBand(1)
    assert band.GetDescription() == "waterLevelHeight"
    assert band.GetNoDataValue() == -123
    assert band.GetUnitType() == "metre"
    assert struct.unpack("f" * 6, band.ReadRaster()) == (
        -123.0,
        1.0,
        2.0,
        3.0,
        4.0,
        5.0,
    )

    band = ds.GetRasterBand(2)
    assert band.GetDescription() == "waterLevelTrend"
    assert band.GetNoDataValue() == 0
    assert struct.unpack("B" * 6, band.ReadRaster()) == (
        0,
        1,
        2,
        3,
        2,
        1,
    )

    del ds
    assert not os.path.exists("data/s104/test_s104_v2.1.h5.aux.xml")


###############################################################################


def test_s104_multidim():

    filename = "data/s104/test_s104_v1.1.h5"
    ds = gdal.OpenEx(filename, gdal.OF_MULTIDIM_RASTER)
    rg = ds.GetRootGroup()
    ar = rg.OpenMDArrayFromFullname("/WaterLevel/WaterLevel.01/Group_001/values")
    assert ar.GetSpatialRef().GetAuthorityCode(None) == "4326"

    assert ar.GetDimensions()[0].GetName() == "Y"
    y = ar.GetDimensions()[0].GetIndexingVariable()
    y_data = struct.unpack("d" * y.GetDimensions()[0].GetSize(), y.Read())
    assert y_data[0] == 48.0
    assert y_data[-1] == 48.5

    assert ar.GetDimensions()[1].GetName() == "X"
    x = ar.GetDimensions()[1].GetIndexingVariable()
    x_data = struct.unpack("d" * x.GetDimensions()[0].GetSize(), x.Read())
    assert x_data[0] == 2.0
    assert x_data[-1] == 2.8
