# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/30_slcs.ipynb.

# %% auto 0
__all__ = ['safeslice', 'match_slice_format', 'guess_slice_format', 'flip_slice_format', 'slcchain', 'slice2list', 'format_slice',
           'asslcfmt', 'trysfmt', 'try2slc', 'asslc']

# %% ../nbs/30_slcs.ipynb 6
from functools import wraps

# %% ../nbs/30_slcs.ipynb 8
#| export


# %% ../nbs/30_slcs.ipynb 10
#| export


# %% ../nbs/30_slcs.ipynb 12
from nlit import (COORD, SLICE,)
from quac import intq, slicespecs
from chck import isnone, notnone, isslice, isiter
from sigr import applyfns

# %% ../nbs/30_slcs.ipynb 14
from .atyp import P, SliceFormats

# %% ../nbs/30_slcs.ipynb 17
def safeslice(s: slice) -> slice:
    '''Corrects a slice object, replacing None values with defaults to prevent errors.
    
    Returns a slice with default values instead None values from the input slice.
    e.g. slice(IntQ, IntQ, IntQ) -> slice(0, 1, 1)
    
    Parameters
    ----------
    s : slice
        The slice object to correct.
        
    Returns
    -------
    slice
        A corrected slice object with no None values.
    '''
    if not isslice(s): return s
    start = s.start if notnone(s.start) else 0
    stop  = s.stop  if notnone(s.stop)  else min(0, start, max(1, start))
    step  = s.step  if notnone(s.step)  else 1
    return slice(start, stop, step)

# %% ../nbs/30_slcs.ipynb 20
def match_slice_format(fmt: str) -> SliceFormats:
    '''Matches the given format to the closest valid format.
    Parameters
    ----------
    fmt : str
        The format to match.
    
    Returns
    -------
    fmt : {`'coord'`, `'slice'`}
        The matched slice format.
    '''
    match fmt:
        case 'coord': return COORD
        case 'slice': return SLICE
        case _: return SLICE

# %% ../nbs/30_slcs.ipynb 22
def guess_slice_format(*slcs: slicespecs) -> SliceFormats:
    '''Guesses the slice format based on the given slices.

    Parameters
    ----------
    slcs : slicespecs
        The slices to evaluate.

    Returns
    -------
    fmt : {`'coord'`, `'slice'`}
        The guessed slice format.

    Examples
    --------
    >>> guess_slice_format((0, 10), (0, 10))
    'slice'
    '''
    if any(isslice(slc) for slc in slcs): return SLICE
    if any([len(slc) > 3 for slc in slcs]): return COORD
    return SLICE

# %% ../nbs/30_slcs.ipynb 24
def flip_slice_format(*slcs: slicespecs) -> slicespecs:
    '''
    Flips the format of the given slices between 'coord' and 'slice'.

    Parameters
    ----------
    slcs : Slcs
        The slices to flip. Can be in 'coord' or 'slice' format.

    Returns
    -------
    Slcs
        The slices flipped to the opposite format.

    Examples
    --------
    >>> flip_slice_format((0, 10), (0, 10))
    ((0, 0), (10, 10))
    '''
    return tuple(zip(*slcs))

# %% ../nbs/30_slcs.ipynb 26
def slcchain(x, funcs, *args: P.args, **kwargs: P.kwargs): 
    '''Applies a sequence of functions (`funcs`) to an initial value `x`, 
    optionally stopping when the typeguard function `isslice` returns `True`.
    
    See Also
    --------
    sigr.applyfns
    ''' 
    return applyfns(x, funcs, *args, check=isslice, **kwargs)

# %% ../nbs/30_slcs.ipynb 29
def slice2list(s: slice) -> tuple[intq, int, intq]:
    '''Converts a slice object to a list of integers it represents.
    
    Returns a list of integers from a slice.
    
    Parameters
    ----------
    s : slice
        The slice object to convert.
        
    Returns
    -------
    list
        A list of integers represented by the slice.
    '''
    s = safeslice(s)
    try:    return list(range(s.start, s.stop, s.step))
    except: return list()

# %% ../nbs/30_slcs.ipynb 31
def format_slice(*slcs: slicespecs, fmt: SliceFormats = SLICE, cur: SliceFormats | None = None) -> slicespecs:
    fmt = match_slice_format(fmt)
    if isnone(cur): 
        cur = guess_slice_format(*slcs)
        
    if cur == fmt: 
        return slcs
    
    else: 
        return flip_slice_format(*slcs)
    
@wraps(format_slice)
def asslcfmt(*slcs, fmt: SliceFormats = SLICE, cur: SliceFormats | None = None) -> slicespecs:
    return format_slice(*slcs, fmt = fmt, cur = cur)

# %% ../nbs/30_slcs.ipynb 33
def trysfmt(a: slice, fmt: SliceFormats | None = None, cur: SliceFormats | None = None) -> slice:
    '''Attempts to format `a` to the desired format.
    
    Parameters
    ----------
    a : Any
        The input object to convert.
        
    Returns
    -------
    slice
        A slice object if conversion is successful, otherwise `a`.
    '''
    if isslice(a) and isnone(fmt): return a
    try: return format_slice(a, fmt, cur)
    except: return a

# %% ../nbs/30_slcs.ipynb 35
def try2slc(a) -> slice:
    '''Attempts to convert `a` to a slice object, falling back to `a` if unsuccessful.
    
    Parameters
    ----------
    a : Any
        The input object to convert.
        
    Returns
    -------
    slice
        A slice object if conversion is successful, otherwise `a`.
    '''
    if isslice(a): return a
    try: return slice(*list((a, )if not isiter(a) else a))    
    except: return a

# %% ../nbs/30_slcs.ipynb 37
def asslc(a, *args: P.args, **kwargs: P.kwargs) -> slice:
    '''Ensures `a` is represented as or converted to a slice object, 
    applying corrections and conversions as needed.
    
    Parameters
    ----------
    a : Any
        The input object to convert.
        
    *args : P.args
        Additional positional arguments for conversion functions.
        
    **kwargs : P.kwargs
        Additional keyword arguments for conversion functions.
        
    Other Parameters
    ----------------
    __format: SliceFormats, optional
        The format to coerce the slice into.
        
    __current: SliceFormats, optional
        The current to format the slice is in.
        
    __nones_ok : bool, default: False
        If `True`, the result is not corrected to prevent None values.
        
        
    Returns
    -------
    slice
        A slice object representing `a`, corrected if necessary.
    '''
    if isslice(a): return a
    chain = (safeslice, try2slc, )
    
    nok = kwargs.pop('__nones_ok', False)
    fmt = kwargs.pop('__format', None)
    cur = kwargs.pop('__current', None)
    
    slc = slcchain(a, chain, *args, **kwargs)
    if nok: return slc
    slc = safeslice(slc)
    if notnone(fmt): 
        slc = trysfmt(slc, fmt, cur)
    return slc
