"""
Digital Cinema Distribution Master (DCDM)
=========================================

Define the *DCDM* electro-optical transfer function (EOTF) and its
inverse.

-   :func:`colour.models.eotf_inverse_DCDM`
-   :func:`colour.models.eotf_DCDM`

References
----------
-   :cite:`DigitalCinemaInitiatives2007b` : Digital Cinema Initiatives. (2007).
    Digital Cinema System Specification - Version 1.1.
    http://www.dcimovies.com/archives/spec_v1_1/\
DCI_DCinema_System_Spec_v1_1.pdf
-   :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 typing

import numpy as np

from colour.algebra import spow

if typing.TYPE_CHECKING:
    from colour.hints import ArrayLike, NDArrayFloat, NDArrayReal

from colour.utilities import as_float, as_float_array, as_int

__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__ = [
    "eotf_inverse_DCDM",
    "eotf_DCDM",
]


def eotf_inverse_DCDM(XYZ: ArrayLike, out_int: bool = False) -> NDArrayReal:
    """
    Apply the *DCDM* inverse electro-optical transfer function (EOTF).

    Parameters
    ----------
    XYZ
        *CIE XYZ* tristimulus values.
    out_int
        Whether to return value as integer code value or float equivalent
        of a code value at a specified bit-depth.

    Returns
    -------
    :class:`numpy.ndarray`
        Non-linear *CIE XYZ'* tristimulus values.

    Warnings
    --------
    *DCDM* is an absolute transfer function.

    Notes
    -----
    -   *DCDM* is an absolute transfer function, thus the domain and range
        values for the *Reference* and *1* scales are only indicative that
        the data is not affected by scale transformations.

    +----------------+-----------------------+---------------+
    | **Domain \\***  | **Scale - Reference** | **Scale - 1** |
    +================+=======================+===============+
    | ``XYZ``        | ``UN``                | ``UN``        |
    +----------------+-----------------------+---------------+

    +----------------+-----------------------+---------------+
    | **Range \\***   | **Scale - Reference** | **Scale - 1** |
    +================+=======================+===============+
    | ``XYZ_p``      | ``UN``                | ``UN``        |
    +----------------+-----------------------+---------------+

    \\* This definition has an output int switch, thus the domain-range
    scale information is only specified for the floating point mode.

    References
    ----------
    :cite:`DigitalCinemaInitiatives2007b`

    Examples
    --------
    >>> eotf_inverse_DCDM(0.18)  # doctest: +ELLIPSIS
    0.1128186...
    >>> eotf_inverse_DCDM(0.18, out_int=True)
    462
    """

    XYZ = as_float_array(XYZ)

    XYZ_p = spow(XYZ / 52.37, 1 / 2.6)

    if out_int:
        return as_int(np.round(4095 * XYZ_p))

    return as_float(XYZ_p)


def eotf_DCDM(
    XYZ_p: ArrayLike,
    in_int: bool = False,
) -> NDArrayFloat:
    """
    Apply the *DCDM* electro-optical transfer function (EOTF).

    Parameters
    ----------
    XYZ_p
        Non-linear *CIE XYZ'* tristimulus values.
    in_int
        Whether to treat the input value as integer code value or float
        equivalent of a code value at a specified bit-depth.

    Returns
    -------
    :class:`numpy.ndarray`
        *CIE XYZ* tristimulus values.

    Warnings
    --------
    *DCDM* is an absolute transfer function.

    Notes
    -----
    -   *DCDM* is an absolute transfer function, thus the domain and range
        values for the *Reference* and *1* scales are only indicative that
        the data is not affected by scale transformations.

    +----------------+-----------------------+---------------+
    | **Domain \\***  | **Scale - Reference** | **Scale - 1** |
    +================+=======================+===============+
    | ``XYZ_p``      | ``UN``                | ``UN``        |
    +----------------+-----------------------+---------------+

    +----------------+-----------------------+---------------+
    | **Range \\***   | **Scale - Reference** | **Scale - 1** |
    +================+=======================+===============+
    | ``XYZ``        | ``UN``                | ``UN``        |
    +----------------+-----------------------+---------------+

    \\* This definition has an input int switch, thus the domain-range
    scale information is only specified for the floating point mode.

    References
    ----------
    :cite:`DigitalCinemaInitiatives2007b`

    Examples
    --------
    >>> eotf_DCDM(0.11281860951766724)  # doctest: +ELLIPSIS
    0.18...
    >>> eotf_DCDM(462, in_int=True)  # doctest: +ELLIPSIS
    0.18...
    """

    XYZ_p = as_float_array(XYZ_p)

    if in_int:
        XYZ_p = XYZ_p / 4095

    XYZ = 52.37 * spow(XYZ_p, 2.6)

    return as_float(XYZ)
