# vim: set et sw=4 sts=4 fileencoding=utf-8:
#
# The colorzero color library
#
# Copyright (c) 2016-2021 Dave Jones <dave@waveform.org.uk>
#
# SPDX-License-Identifier: BSD-3-Clause

"Define the tuples used to represent various color systems."

from collections import namedtuple, OrderedDict

from .attr import Red, Green, Blue, Hue, Lightness, Saturation, Luma


class RGB(tuple):
    "Named tuple representing red, green, and blue."
    # NOTE: This source mostly generated by namedtuple(..., verbose=True)
    # XXX When py3.6+ required, replace with derivative of typing.NamedTuple

    __slots__ = ()

    _fields = ('r', 'g', 'b')

    def __new__(cls, r, g, b):
        return tuple.__new__(cls, (r, g, b))

    def _replace(self, **kw):
        "Return a new RGB object replacing specified fields with new values"
        result = tuple.__new__(RGB, map(kw.pop, 'rgb', self))
        if kw:
            raise ValueError(
                'Got unexpected field names: {!r}'.format(list(kw)))
        return result

    def __repr__(self):
        "Return a nicely formatted representation string"
        return (
            self.__class__.__name__ +
            '(r={self.r:g}, g={self.g:g}, b={self.b:g})'.format(self=self))

    def _asdict(self):
        "Return a new OrderedDict which maps field names to their values."
        return OrderedDict(zip(self._fields, self))

    def __getnewargs__(self):
        "Return self as a plain tuple.  Used by copy and pickle."
        return tuple(self)

    @property
    def r(self):
        "Return the red value as a :class:`Red` instance"
        # pylint: disable=invalid-name
        return Red(self[0])

    @property
    def red(self):
        "Return the red value as a :class:`Red` instance"
        return Red(self[0])

    @property
    def g(self):
        "Return the green value as a :class:`Green` instance"
        # pylint: disable=invalid-name
        return Green(self[1])

    @property
    def green(self):
        "Return the green value as a :class:`Green` instance"
        return Green(self[1])

    @property
    def b(self):
        "Return the blue value as a :class:`Blue` instance"
        # pylint: disable=invalid-name
        return Blue(self[2])

    @property
    def blue(self):
        "Return the blue value as a :class:`Blue` instance"
        return Blue(self[2])


class HLS(tuple):
    "Named tuple representing hue, lightness, and saturation."
    # NOTE: This source mostly generated by namedtuple(..., verbose=True)
    # XXX When py3.6+ required, replace with derivative of typing.NamedTuple

    __slots__ = ()

    _fields = ('h', 'l', 's')

    def __new__(cls, h, l, s):
        return tuple.__new__(cls, (h, l, s))

    def _replace(self, **kw):
        "Return a new HLS object replacing specified fields with new values"
        result = tuple.__new__(HLS, map(kw.pop, 'hls', self))
        if kw:
            raise ValueError('Got unexpected field names: {!r}'.format(list(kw)))
        return result

    def __repr__(self):
        "Return a nicely formatted representation string"
        return (
            self.__class__.__name__ +
            '(h={self.h:g}, l={self.l:g}, s={self.s:g})'.format(self=self))

    def _asdict(self):
        "Return a new OrderedDict which maps field names to their values."
        return OrderedDict(zip(self._fields, self))

    def __getnewargs__(self):
        "Return self as a plain tuple.  Used by copy and pickle."
        return tuple(self)

    @property
    def h(self):
        "Return the hue value as a :class:`Hue` instance"
        # pylint: disable=invalid-name
        return Hue(self[0])

    @property
    def hue(self):
        "Return the hue value as a :class:`Hue` instance"
        return Hue(self[0])

    @property
    def l(self):
        "Return the lightness value as a :class:`Lightness` instance"
        # pylint: disable=invalid-name
        return Lightness(self[1])

    @property
    def lightness(self):
        "Return the lightness value as a :class:`Lightness` instance"
        return Lightness(self[1])

    @property
    def s(self):
        "Return the saturation value as a :class:`Saturation` instance"
        # pylint: disable=invalid-name
        return Saturation(self[2])

    @property
    def saturation(self):
        "Return the saturation value as a :class:`Saturation` instance"
        return Saturation(self[2])


class HSV(tuple):
    'Named tuple representing hue, saturation, and value ("brightness").'
    # XXX When py3.6+ required, replace with derivative of typing.NamedTuple

    __slots__ = ()

    _fields = ('h', 's', 'v')

    def __new__(cls, h, s, v):
        return tuple.__new__(cls, (h, s, v))

    def _replace(self, **kw):
        "Return a new HSV object replacing specified fields with new values"
        result = tuple.__new__(HSV, map(kw.pop, 'hsv', self))
        if kw:
            raise ValueError(
                'Got unexpected field names: {!r}'.format(list(kw)))
        return result

    def __repr__(self):
        "Return a nicely formatted representation string"
        return (
            self.__class__.__name__ +
            '(h={self.h:g}, s={self.s:g}, v={self.v:g})'.format(self=self))

    def _asdict(self):
        "Return a new OrderedDict which maps field names to their values."
        return OrderedDict(zip(self._fields, self))

    def __getnewargs__(self):
        "Return self as a plain tuple.  Used by copy and pickle."
        return tuple(self)

    @property
    def h(self):
        "Return the hue value as a :class:`Hue` instance"
        # pylint: disable=invalid-name
        return Hue(self[0])

    @property
    def hue(self):
        "Return the hue value as a :class:`Hue` instance"
        return Hue(self[0])

    @property
    def s(self):
        "Return the saturation value as a :class:`Saturation` instance"
        # pylint: disable=invalid-name
        return Saturation(self[1])

    @property
    def saturation(self):
        "Return the saturation value as a :class:`Saturation` instance"
        return Saturation(self[1])

    @property
    def v(self):
        "Return the brightness value"
        return self[2]

    @property
    def value(self):
        "Return the brightness value"
        return self[2]


class YUV(tuple):
    "Named tuple representing luma and two chroma offsets"
    # XXX When py3.6+ required, replace with derivative of typing.NamedTuple

    __slots__ = ()

    _fields = ('y', 'u', 'v')

    def __new__(cls, y, u, v):
        return tuple.__new__(cls, (y, u, v))

    def _replace(self, **kw):
        "Return a new YUV object replacing specified fields with new values"
        result = tuple.__new__(YUV, map(kw.pop, 'yuv', self))
        if kw:
            raise ValueError(
                'Got unexpected field names: {!r}'.format(list(kw)))
        return result

    def __repr__(self):
        "Return a nicely formatted representation string"
        return (
            self.__class__.__name__ +
            '(y={self.y:g}, u={self.u:g}, v={self.v:g})'.format(self=self))

    def _asdict(self):
        "Return a new OrderedDict which maps field names to their values."
        return OrderedDict(zip(self._fields, self))

    def __getnewargs__(self):
        "Return self as a plain tuple.  Used by copy and pickle."
        return tuple(self)

    @property
    def y(self):
        "Return the luma value as a :class:`Luma` instance"
        # pylint: disable=invalid-name
        return Luma(self[0])

    @property
    def luma(self):
        "Return the luma value as a :class:`Luma` instance"
        return Luma(self[0])

    @property
    def u(self):
        "Return the first chroma offset"
        # pylint: disable=invalid-name
        return self[1]

    @property
    def v(self):
        "Return the second chroma offset"
        # pylint: disable=invalid-name
        return self[2]


class CMY(namedtuple('CMY', ('c', 'm', 'y'))):
    "Named tuple representing cyan, magenta, and yellow."
    # XXX When py3.6+ required, replace with derivative of typing.NamedTuple

    @property
    def cyan(self):
        # pylint: disable=missing-docstring
        return self.c

    @property
    def magenta(self):
        # pylint: disable=missing-docstring
        return self.m

    @property
    def yellow(self):
        # pylint: disable=missing-docstring
        return self.y


class CMYK(namedtuple('CMYK', ('c', 'm', 'y', 'k'))):
    "Named tuple representing cyan, magenta, yellow, and black."
    # XXX When py3.6+ required, replace with derivative of typing.NamedTuple

    @property
    def cyan(self):
        # pylint: disable=missing-docstring
        return self.c

    @property
    def magenta(self):
        # pylint: disable=missing-docstring
        return self.m

    @property
    def yellow(self):
        # pylint: disable=missing-docstring
        return self.y

    @property
    def black(self):
        # pylint: disable=missing-docstring
        return self.k


YIQ = namedtuple('YIQ', ('y', 'i', 'q'))
XYZ = namedtuple('XYZ', ('x', 'y', 'z'))
Luv = namedtuple('Luv', ('l', 'u', 'v'))
Lab = namedtuple('Lab', ('l', 'a', 'b'))
