"""
Recommendation ITU-T H.273 Transfer Characteristics
===================================================

Define the *Recommendation ITU-T H.273* transfer functions that do not belong
in another specification or standard, or have been modified for inclusion.

-   :func:`colour.models.oetf_H273_Log`
-   :func:`colour.models.oetf_inverse_H273_Log`
-   :func:`colour.models.oetf_H273_LogSqrt`
-   :func:`colour.models.oetf_inverse_H273_LogSqrt`
-   :func:`colour.models.oetf_H273_IEC61966_2`
-   :func:`colour.models.oetf_inverse_H273_IEC61966_2`
-   :func:`colour.models.eotf_H273_ST428_1`
-   :func:`colour.models.eotf_inverse_H273_ST428_1`

References
----------
-   :cite:`InternationalTelecommunicationUnion2021` : International
    Telecommunication Union. (2021). Recommendation ITU-T H.273 -
    Coding-independent code points for video signal type identification.
    https://www.itu.int/rec/T-REC-H.273-202107-I/en
-   :cite:`SocietyofMotionPictureandTelevisionEngineers2019` : Society of
    Motion Picture and Television Engineers. (2019). ST 428-1:2019 - D-Cinema
    Distribution Master — Image Characteristic. doi:10.5594/SMPTE.ST428-1.2019
"""

from __future__ import annotations

import numpy as np

from colour.algebra import spow
from colour.hints import (  # noqa: TC001
    Domain1,
    Range1,
)
from colour.models.rgb.transfer_functions import (
    eotf_DCDM,
    eotf_inverse_DCDM,
    eotf_inverse_sRGB,
    eotf_sRGB,
)
from colour.utilities import as_float, as_float_array, from_range_1, to_domain_1

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"

__all__ = [
    "oetf_H273_Log",
    "oetf_inverse_H273_Log",
    "oetf_H273_LogSqrt",
    "oetf_inverse_H273_LogSqrt",
    "oetf_H273_IEC61966_2",
    "oetf_inverse_H273_IEC61966_2",
    "eotf_H273_ST428_1",
    "eotf_inverse_H273_ST428_1",
]


def oetf_H273_Log(L_c: Domain1) -> Range1:
    """
    Apply the *Recommendation ITU-T H.273* opto-electronic transfer function
    (OETF) for logarithmic encoding with 100:1 dynamic range.

    Parameters
    ----------
    L_c
        Scene *luminance* :math:`L_c`.

    Returns
    -------
    :class:`numpy.ndarray`
        Electrical signal :math:`V`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`InternationalTelecommunicationUnion2021`

    Warnings
    --------
    -   The function is clamped to domain [0.01, np.inf].

    Examples
    --------
    >>> oetf_H273_Log(0.18)  # doctest: +ELLIPSIS
    0.6276362525516...
    >>> oetf_H273_Log(0.01)  # doctest: +ELLIPSIS
    0.0
    >>> oetf_H273_Log(0.001)  # doctest: +ELLIPSIS
    0.0
    >>> oetf_H273_Log(1.0)  # doctest: +ELLIPSIS
    1.0
    """

    L_c = to_domain_1(L_c)

    V = np.where(
        L_c >= 0.01,
        # L_c in [0.01, 1] range
        1 + np.log10(L_c) / 2,
        # L_c in [0, 0.01] range
        0,
    )

    return as_float(from_range_1(V))


def oetf_inverse_H273_Log(V: Domain1) -> Range1:
    """
    Apply the *Recommendation ITU-T H.273* inverse opto-electronic transfer
    function (OETF) for logarithmic encoding with 100:1 dynamic range.

    Parameters
    ----------
    V
        Electrical signal :math:`V`.

    Returns
    -------
    :class:`numpy.ndarray`
        Scene *luminance* :math:`L_c`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`InternationalTelecommunicationUnion2021`

    Warnings
    --------
    -   The function is clamped to domain
        [:func:`colour.models.oetf_H273_Log` (0.01), np.inf].

    Examples
    --------
    >>> oetf_inverse_H273_Log(0.6276362525516)  # doctest: +ELLIPSIS
    0.17999999...
    >>> oetf_inverse_H273_Log(0.0)  # doctest: +ELLIPSIS
    0.01
    >>> oetf_inverse_H273_Log(1.0)  # doctest: +ELLIPSIS
    1.0
    """

    V = to_domain_1(V)

    L_c = np.where(
        oetf_H273_Log(0.01) <= V,
        # L_c in [0.01, 1] range
        spow(10, (V - 1) * 2),
        # L_c in [0, 0.01] range
        0,
    )

    return as_float(from_range_1(L_c))


def oetf_H273_LogSqrt(L_c: Domain1) -> Range1:
    """
    Apply the *Recommendation ITU-T H.273* opto-electronic transfer function
    (OETF) for logarithmic encoding (100\\*Sqrt(10):1 range).

    Parameters
    ----------
    L_c
        Scene *luminance* :math:`L_c`.

    Returns
    -------
    :class:`numpy.ndarray`
        Electrical signal :math:`V`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`InternationalTelecommunicationUnion2021`

    Warnings
    --------
    -   The function is clamped to domain
        [:func:`colour.models.oetf_H273_LogSqrt` (sqrt(10) / 1000),
        np.inf].

    Examples
    --------
    >>> oetf_H273_LogSqrt(0.18)  # doctest: +ELLIPSIS
    0.702109002041...
    >>> oetf_H273_LogSqrt(0.003162277660168)  # doctest: +ELLIPSIS
    0.0
    >>> oetf_H273_LogSqrt(0.0001)  # doctest: +ELLIPSIS
    0.0
    >>> oetf_H273_LogSqrt(1.0)  # doctest: +ELLIPSIS
    1.0
    """

    L_c = to_domain_1(L_c)

    V = np.where(
        L_c >= np.sqrt(10) / 1000,
        # L_c in [sqrt(10)/1000, 1] range
        1 + np.log10(L_c) / 2.5,
        # L_c in [0, sqrt(10)/1000] range
        0,
    )

    return as_float(from_range_1(V))


def oetf_inverse_H273_LogSqrt(V: Domain1) -> Range1:
    """
    Apply the *Recommendation ITU-T H.273* inverse opto-electronic transfer
    function (OETF) for logarithmic encoding (100\\*Sqrt(10):1 range).

    Parameters
    ----------
    V
        Electrical signal :math:`V`.

    Returns
    -------
    :class:`numpy.ndarray`
        Scene *luminance* :math:`L_c`.

    Notes
    -----
    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    :cite:`InternationalTelecommunicationUnion2021`

    Warnings
    --------
    -   The function is clamped to domain [sqrt(10) / 1000, np.inf].

    Examples
    --------
    >>> oetf_inverse_H273_LogSqrt(0.702109002041)  # doctest: +ELLIPSIS
    0.1799999999...
    >>> oetf_inverse_H273_LogSqrt(0.0)  # doctest: +ELLIPSIS
    0.00316227766...
    >>> oetf_inverse_H273_LogSqrt(1.0)  # doctest: +ELLIPSIS
    1.0
    """

    V = to_domain_1(V)

    L_c = np.where(
        oetf_H273_LogSqrt(np.sqrt(10) / 1000) <= V,
        # L_c in [sqrt(10)/1000, 1] range
        spow(10, (V - 1) * 2.5),
        # L_c in [0, sqrt(10)/1000] range
        0,
    )

    return as_float(from_range_1(L_c))


def oetf_H273_IEC61966_2(L_c: Domain1) -> Range1:
    """
    Apply the *Recommendation ITU-T H.273* opto-electronic transfer function
    (OETF) for *IEC 61966-2* family of transfer functions (*2-1 sRGB*, *2-1
    sYCC*, *2-4 xvYCC*).

    Parameters
    ----------
    L_c
        Scene *luminance* :math:`L_c`.

    Returns
    -------
    :class:`numpy.ndarray`
        Electrical signal :math:`V`.

    Notes
    -----
    Usage in :cite:`InternationalTelecommunicationUnion2021` is as follows:

    -   For *IEC 61966-2-1 sRGB (MatrixCoefficients=0)*, the function is
        only defined for :math:`L_c` in [0-1] range.
    -   For *IEC 61966-2-1 sYCC (MatrixCoefficients=5)* and *IEC 61966-2-4
        xvYCC*, the function is defined for any real-valued :math:`L_c`.

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    -   :cite:`InternationalTelecommunicationUnion2021`

    Examples
    --------
    >>> oetf_H273_IEC61966_2(0.18)  # doctest: +ELLIPSIS
    0.4613561295004...
    >>> oetf_H273_IEC61966_2(-0.18)  # doctest: +ELLIPSIS
    -0.4613561295004...
    """

    L_c = as_float_array(L_c)

    V = np.where(
        L_c >= 0,
        eotf_inverse_sRGB(L_c),
        -eotf_inverse_sRGB(-L_c),
    )

    return as_float(V)


def oetf_inverse_H273_IEC61966_2(
    V: Domain1,
) -> Range1:
    """
    Apply the *Recommendation ITU-T H.273* inverse opto-electronic
    transfer function (OETF) for the *IEC 61966-2* family of transfer
    functions (*2-1 sRGB*, *2-1 sYCC*, *2-4 xvYCC*).

    Parameters
    ----------
    V
        Electrical signal :math:`V`.

    Returns
    -------
    :class:`numpy.ndarray`
        Scene *luminance* :math:`L_c`.

    Notes
    -----
    Usage in :cite:`InternationalTelecommunicationUnion2021` is
    specified as follows:

    -   For *IEC 61966-2-1 sRGB (MatrixCoefficients=0)*, the function is
        only defined for :math:`L_c` in [0-1] range.
    -   For *IEC 61966-2-1 sYCC (MatrixCoefficients=5)* and *IEC
        61966-2-4 xvYCC*, the function is defined for any real-valued
        :math:`L_c`.

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_c``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    -   :cite:`InternationalTelecommunicationUnion2021`

    Examples
    --------
    >>> oetf_inverse_H273_IEC61966_2(0.461356129500)  # doctest: +ELLIPSIS
    0.1799999999...
    >>> oetf_inverse_H273_IEC61966_2(-0.461356129500)  # doctest: +ELLIPSIS
    -0.1799999999...
    """

    V = as_float_array(V)

    L_c = np.where(
        V >= 0,
        eotf_sRGB(V),
        -eotf_sRGB(-V),
    )

    return as_float(L_c)


def eotf_H273_ST428_1(V: Domain1) -> Range1:
    """
    Apply the *SMPTE ST 428-1 (2019)* electro-optical transfer function
    (EOTF) as specified in *ITU-T H.273*.

    Parameters
    ----------
    V
        Electrical signal :math:`V`.

    Returns
    -------
    :class:`numpy.ndarray`
        Output display *Luminance* :math:`L_o` of the image.

    Notes
    -----
    -   The function specified in
        :cite:`InternationalTelecommunicationUnion2021` divides
        :math:`L_o` by 48, contrary to what is specified in
        :cite:`SocietyofMotionPictureandTelevisionEngineers2019` and
        :func:`colour.models.eotf_DCDM`.

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_o``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    -   :cite:`InternationalTelecommunicationUnion2021`,
        :cite:`SocietyofMotionPictureandTelevisionEngineers2019`

    Examples
    --------
    >>> eotf_H273_ST428_1(0.5000483377172)  # doctest: +ELLIPSIS
    0.1799999...
    """

    V = to_domain_1(V)

    return as_float(from_range_1(eotf_DCDM(V) / 48))


def eotf_inverse_H273_ST428_1(
    L_o: Domain1,
) -> Range1:
    """
    Apply the *SMPTE ST 428-1 (2019)* inverse electro-optical transfer function
    (EOTF) as specified in *ITU-T H.273*.

    Parameters
    ----------
    L_o
        Output display *Luminance* :math:`L_o` of the image.

    Returns
    -------
    :class:`numpy.ndarray`
        Electrical signal :math:`V`.

    Notes
    -----
    -   The function specified in
        :cite:`InternationalTelecommunicationUnion2021` multiplies :math:`L_o`
        by 48, contrary to what is specified in
        :cite:`SocietyofMotionPictureandTelevisionEngineers2019` and
        :func:`colour.models.eotf_inverse_DCDM`.

    +------------+-----------------------+---------------+
    | **Domain** | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``L_o``    | 1                     | 1             |
    +------------+-----------------------+---------------+

    +------------+-----------------------+---------------+
    | **Range**  | **Scale - Reference** | **Scale - 1** |
    +============+=======================+===============+
    | ``V``      | 1                     | 1             |
    +------------+-----------------------+---------------+

    References
    ----------
    -   :cite:`InternationalTelecommunicationUnion2021`,
        :cite:`SocietyofMotionPictureandTelevisionEngineers2019`

    Examples
    --------
    >>> eotf_inverse_H273_ST428_1(0.18)  # doctest: +ELLIPSIS
    0.5000483...
    """

    L_o = to_domain_1(L_o)

    return as_float(from_range_1(eotf_inverse_DCDM(L_o * 48)))
