# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_meta.ipynb.

# %% auto 0
__all__ = ['ModuleEnumMeta']

# %% ../nbs/03_meta.ipynb 6
import copy
from enum import EnumMeta, _EnumDict, member

# %% ../nbs/03_meta.ipynb 8
from typing import (Type, TypeGuard)

# %% ../nbs/03_meta.ipynb 10
#| export


# %% ../nbs/03_meta.ipynb 12
from nlit import MIXINS, ASMEMBER, MODULE, DEFAULT, _MEMBER_NAMES_, _MEMBER_MAP_

# %% ../nbs/03_meta.ipynb 14
from .cons import TORCH_NN, _MODULE, _DEFAULT
from .atyp import T, P, Mixin
from .util import enumdict, evalue, missing

# %% ../nbs/03_meta.ipynb 16
class ModuleEnumMeta(EnumMeta):
    def _check_for_existing_members_(class_name, bases):
        '''Check for existing members in base classes.'''
        
    @classmethod
    def duplicate(mcls: Type[T], v: T, *args: P.args, **kwargs: P.kwargs):
        '''Duplicate a value within the enumeration dictionary.'''
        mixins: list[Mixin] = kwargs.get(MIXINS, getattr(mcls, MIXINS, []))
        asmemb = kwargs.get(ASMEMBER, False)
        copied = copy.deepcopy(evalue(v))
        for (mixtype, hook) in mixins:
            if not isinstance(copied, mixtype): continue
            copied = hook(copied, *args, **kwargs)
        return member(copied) if asmemb else copied
        
    @classmethod
    def __copydict__(mcls: Type[T], clsdict: _EnumDict, *args: P.args, **kwargs: P.kwargs) -> _EnumDict:
        '''Create a deep copy of the enumeration dictionary.'''
        newdict = enumdict(clsdict._cls_name)
        for k, v in clsdict.items(): 
            newdict[k] = mcls.duplicate(v, *args, **kwargs)
        return newdict
    
    @classmethod
    def __prepare__(mcls: Type[T], name: str, bases: tuple, **kwargs) -> _EnumDict:
        '''Prepare the enumeration dictionary before class creation.'''
        clsdict = enumdict(name)
        return clsdict
    
    def __new__(mcls: Type[T], name, bases, clsdict, **kwargs):
        '''Create a new enumeration class.'''
        newcls = super().__new__(mcls, name, bases, clsdict)
        setattr(newcls, _MODULE, kwargs.get(MODULE, None))
        setattr(newcls, _DEFAULT, kwargs.get(DEFAULT, None))
        return newcls

    def _default_(cls: Type[T]) -> T:
        '''Get the default value for the enumeration class.'''
        keys = getattr(cls, _MEMBER_NAMES_, [None])
        return getattr(cls, _DEFAULT, keys[0])
    
    def _module_(cls: Type[T]) -> str:
        '''Get the module name for the enumeration class.'''
        return getattr(cls, _MODULE, TORCH_NN)
    
    @classmethod
    def _missing_(cls: Type[T], val: str | T, default = None) -> T:
        '''Method called for missing members during lookup.

        Parameters
        ----------
        cls : Enum
            The enumeration class.
        
        val : str
            The value to check for in the enum members.
        

        Returns
        -------
        Enum member or default
            The matched enum member or the default value.
        '''
        if default is None: default = cls._default_()
        return missing(cls, val, default)
    
    def __contains__(self: T, key: str) -> TypeGuard[T]:
        '''Check if the key exists in the enumeration's members.'''
        
        attrs = (_MEMBER_MAP_, _MEMBER_NAMES_)
        for (attr, case) in zip(attrs, (True, False)):
            for mem in getattr(self, attr, []):
                if case and (str(mem).casefold() == key.casefold()) or (mem == key):
                    return True
        return False
    
    def __call__(self: T, key: str | None = None, default = None) -> T:
        '''Get the enum member for the given key.'''
        if key is None: key = self._default_()
        if key not in self: key = self._missing_(key, default)
        return self[key]

# %% ../nbs/03_meta.ipynb 18
#| export
