# Source code for atom.tuple

    # --------------------------------------------------------------------------------------
    # Copyright (c) 2013-2025, Nucleic Development Team.
    #
    # Distributed under the terms of the Modified BSD License.
    #
    # The full license is in the file LICENSE, distributed with this software.
    # --------------------------------------------------------------------------------------
    from typing import Tuple as TTuple

    from .catom import DefaultValue, Member, Validate
    from .instance import Instance
    from .typing_utils import extract_types, is_optional

    class Tuple(Member):
        """A member which allows tuple values.

        If item validation is used, then assignment will create a copy of
        the original tuple before validating the items, since validation
        may change the item values.

        """

        __slots__ = ("item",)

        def __init__(self, item=None, default=()):
            """Initialize a Tuple.

            Parameters
            ----------
            item : Member, type, or tuple of types, optional
                A member to use for validating the types of items allowed in
                the tuple. This can also be a type object or a tuple of types,
                in which case it will be wrapped with an Instance member. If
                this is not given, no item validation is performed.

            default : tuple, optional
                The default tuple of values.

            """
            if item is not None and not isinstance(item, Member):
                opt, types = is_optional(extract_types(item))
                item = Instance(types, optional=opt)
            self.item = item
            self.set_default_value_mode(DefaultValue.Static, default)
            self.set_validate_mode(Validate.Tuple, item)

        def set_name(self, name):
            """Set the name of the member.

            This method ensures that the item member name is also updated.

            """
            super(Tuple, self).set_name(name)
            if self.item is not None:
                self.item.set_name(name + "|item")

        def set_index(self, index):
            """Assign the index to this member.

            This method ensures that the item member index is also updated.

            """
            super(Tuple, self).set_index(index)
            if self.item is not None:
                self.item.set_index(index)

        def clone(self):
            """Create a clone of the tuple.

            This will clone the internal tuple item if one is in use.

            """
            clone = super(Tuple, self).clone()
            item = self.item
            if item is not None:
                clone.item = item_clone = item.clone()
                mode, _ctxt = self.validate_mode
                clone.set_validate_mode(mode, item_clone)
            else:
                clone.item = None
            return clone

    class FixedTuple(Member):
        """A member which allows tuple values with a fixed number of items.

        Items are always validated and can be of different types.
        Assignment will create a copy of the original tuple before validating the
        items, since validation may change the item values.

        """

        #: Members used to validate each element of the tuple.
        items: TTuple[Member, ...]

        __slots__ = ("items",)

        def __init__(self, *items, default=None):
            """Initialize a Tuple.

            Parameters
            ----------
            items : Iterable[Member | type | tuple[type, ...]]
                A member to use for validating the types of items allowed in
                the tuple. This can also be a type object or a tuple of types,
                in which case it will be wrapped with an Instance member.

            default : tuple, optional
                The default tuple of values.

            """
            mitems = []
            for i in items:
                if not isinstance(i, Member):
                    opt, types = is_optional(extract_types(i))
                    i = Instance(types, optional=opt)
                mitems.append(i)

            self.items = mitems

            if default is None:
                self.set_default_value_mode(DefaultValue.NonOptional, None)
            else:
                self.set_default_value_mode(DefaultValue.Static, default)
            self.set_validate_mode(Validate.FixedTuple, tuple(mitems))

        def set_name(self, name):
            """Set the name of the member.

            This method ensures that the item member name is also updated.

            """
            super().set_name(name)
            for i, item in enumerate(self.items):
                item.set_name(name + f"|item_{i}")

        def set_index(self, index):
            """Assign the index to this member.

            This method ensures that the item member index is also updated.

            """
            super().set_index(index)
            for item in self.items:
                item.set_index(index)

        def clone(self):
            """Create a clone of the tuple.

            This will clone the internal tuple item if one is in use.

            """
            clone = super().clone()
            clone.items = items_clone = tuple(i.clone() for i in self.items)
            mode, _ = self.validate_mode
            clone.set_validate_mode(mode, items_clone)
            return clone