# Copyright (c) 2012-2025, OpenGeoSys Community (http://www.opengeosys.org)
#            Distributed under a Modified BSD License.
#            See accompanying file LICENSE.txt or
#            http://www.opengeosys.org/project/license
#
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from ogstools.ogs6py import Project
from collections.abc import Generator
from dataclasses import dataclass, field
from typing import Any
from lxml import etree as ET
[docs]
@dataclass
class Value:
    """Class to hold property values."""
    medium: str
    value: float | None 
[docs]
@dataclass
class Property:
    """Class to hold properties."""
    title: str
    symbol: str
    unit: str
    value: list[Value] = field(default_factory=list)
    def _dict(self) -> dict[str, Any]:
        a: dict[str, Any] = {
            "title": self.title,
            "symbol": self.symbol,
            "unit": self.unit,
        }
        for d in self.value:
            a[d.medium] = d.value
        return a 
[docs]
@dataclass
class PropertySet:
    """Class to hold a set of properties."""
    property: list[Property] = field(default_factory=list)
    def __len__(self) -> int:
        """Number of time steps"""
        return len(self.property)
    def __iter__(self) -> Generator:
        for v in self.property:
            yield v._dict() 
property_dict = {
    "Solid": {
        "density": {
            "title": "Solid density",
            "symbol": "$\\rho_\\text{s}$",
            "unit": "kg m$^{-3}$",
        },
        "specific_heat_capacity": {
            "title": "Specific heat capacity",
            "symbol": "$c_\\text{s}$",
            "unit": "J kg$^{-1}$ K$^{-1}$",
        },
        "thermal_expansivity": {
            "title": "Thermal expansivity",
            "symbol": "$a_s$",
            "unit": "K$^{-1}$",
        },
        "youngs_modulus": {
            "title": "Young's modulus",
            "symbol": "$E$",
            "unit": "Pa",
        },
        "poissons_ratio": {
            "title": "Poisson's ratio",
            "symbol": "$\\nu$",
            "unit": "1",
        },
    },
    "Medium": {
        "porosity": {"title": "Porosity", "symbol": r"$\phi$", "unit": "1"},
        "biot_coefficient": {
            "title": "Biot-Willis coefficient",
            "symbol": "$\\alpha_\\mathrm{B}$",
            "unit": "1",
        },
        "permeability": {
            "title": "Intrinsic permeability",
            "symbol": "$k$",
            "unit": "m$^2$",
        },
        "thermal_conductivity": {
            "title": "Thermal conductivity",
            "symbol": r"$\lambda$",
            "unit": "W m$^{-1}$ K$^{-1}$",
        },
        "vgsat_residual_liquid_saturation": {
            "title": "Saturation: Van Genuchten, \\\\ residual liquid saturation",
            "symbol": "$S^r_\\text{L}$",
            "unit": "1",
        },
        "vgsat_residual_gas_saturation": {
            "title": "Saturation: Van Genuchten, \\\\ residual gas saturation  ",
            "symbol": "$S^r_\\text{g}$",
            "unit": "1",
        },
        "vgsat_exponent": {
            "title": "Saturation: Van Genuchten, \\\\ exponent",
            "symbol": "$m$",
            "unit": "1",
        },
        "vgsat_p_b": {
            "title": "Saturation: Van Genuchten, \\\\ entry pressure",
            "symbol": "$p_b$",
            "unit": "Pa",
        },
        "vgrelperm_residual_liquid_saturation": {
            "title": "Relative permeability: Van Genuchten, \\\\ residual liquid saturation  ",
            "symbol": "$S^r_\\text{L}$",
            "unit": "1",
        },
        "vgrelperm_residual_gas_saturation": {
            "title": "Relative permeability: Van Genuchten, \\\\ residual gas saturation  ",
            "symbol": "$S^r_\\text{g}$",
            "unit": "1",
        },
        "vgrelperm_exponent": {
            "title": "Relative permeability: Van Genuchten, \\\\ exponent",
            "symbol": "$m$",
            "unit": "1",
        },
        "vgrelperm_minimum_relative_permeability_liquid": {
            "title": "Relative permeability: Van Genuchten, \\\\ minimmum relative permeability",
            "symbol": "$k^\\text{min}_r$",
            "unit": "1",
        },
    },
    "AqueousLiquid": {
        "viscosity": {
            "title": "Liquid phase viscosity",
            "symbol": r"$\mu_\mathrm{LR}$",
            "unit": "Pa s",
        },
        "density": {
            "title": "Liquid phase density",
            "symbol": "$\\rho_\\mathrm{LR}$",
            "unit": "kg m$^{-3}$",
        },
        "specific_heat_capacity": {
            "title": "Liquid specific heat capacity",
            "symbol": "$c_\\text{LR}$",
            "unit": "J kg$^{-1}$ K$^{-1}$",
        },
    },
}
location_pointer = {
    "Solid": "phases/phase[type='Solid']/",
    "Medium": "",
    "AqueousLiquid": "phases/phase[type='AqueousLiquid']/",
}
def _expand_tensors(
    obj: Project,
    numofmedia: int,
    multidim_prop: dict[Any, Any],
    root: ET.Element,
    location: str,
) -> None:
    for medium_id in range(numofmedia):
        medium = obj._get_medium_pointer(root, medium_id)
        const_props = medium.findall(
            f"./{location_pointer[location]}properties/property[type='Constant']/value"
        )
        tobedeleted = []
        for prop in const_props:
            proplist = prop.text.split(" ")
            tags = prop.getparent().getchildren()
            for tag in tags:
                if tag.tag == "name":
                    name = tag.text
                    multidim_prop[medium_id][name] = len(proplist)
            if multidim_prop[medium_id][name] > 1:
                properties_level = prop.getparent().getparent()
                tobedeleted.append(prop.getparent())
                taglist = ["name", "type", "value"]
                for i in range(multidim_prop[medium_id][name]):
                    textlist = [f"{name}{i}", "Constant", f"{proplist[i]}"]
                    elmnt = ET.SubElement(properties_level, "property")
                    for j, tag in enumerate(taglist):
                        subelmnt = ET.SubElement(elmnt, tag)
                        if textlist[j] is not None:
                            subelmnt.text = str(textlist[j])
    for element in tobedeleted:
        element.getparent().remove(element)
def _expand_van_genuchten(
    obj: Project, numofmedia: int, root: ET.Element, location: str
) -> None:
    for medium_id in range(numofmedia):
        medium = obj._get_medium_pointer(root, medium_id)
        sat_vg_props = medium.findall(
            f"./{location_pointer[location]}properties/property[type='SaturationVanGenuchten']"
        )
        relperm_vg_props = medium.findall(
            f"./{location_pointer[location]}properties/property[type='RelativePermeabilityVanGenuchten']"
        )
        vg_properties = [sat_vg_props, relperm_vg_props]
        tobedeleted = []
        for vg_property in vg_properties:
            for prop in vg_property:
                proplist = prop.getchildren()
                const_taglist = ["name", "type", "value"]
                prefix = ""
                for subprop in proplist:
                    if "SaturationVanGenuchten" in subprop.text:
                        prefix = "vgsat_"
                    elif "RelativePermeabilityVanGenuchten" in subprop.text:
                        prefix = "vgrelperm_"
                for subprop in proplist:
                    if subprop.tag not in ["name", "type"]:
                        const_textlist = [
                            prefix + subprop.tag,
                            "Constant",
                            subprop.text,
                        ]
                        elmnt = ET.SubElement(prop.getparent(), "property")
                        for i, tag in enumerate(const_taglist):
                            subelmnt = ET.SubElement(elmnt, tag)
                            if const_textlist[i] is not None:
                                subelmnt.text = str(const_textlist[i])
                tobedeleted.append(prop)
    for element in tobedeleted:
        element.getparent().remove(element)