# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/07_zero.ipynb.

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

# %% ../nbs/07_zero.ipynb 6
from itertools import accumulate

# %% ../nbs/07_zero.ipynb 8
from typing import Self, Union

# %% ../nbs/07_zero.ipynb 10
#| export

# %% ../nbs/07_zero.ipynb 12
#| export

# %% ../nbs/07_zero.ipynb 14
#| export


# %% ../nbs/07_zero.ipynb 16
def _shape(shape: tuple = ()) -> tuple:
    '''Ensure that the input is in the form of a tuple.

    Parameters
    ----------
    shape : tuple, optional
        The shape to be converted into a tuple format. If not a tuple, it will be wrapped in one.

    Returns
    -------
    tuple
        The input shape converted into a tuple format.

    '''
    if isinstance(shape, tuple): return shape
    return (shape, )

def _genzeros(shape: tuple = ()) -> list[float]:
    '''Generate a nested list of zeros based on the specified shape.

    Parameters
    ----------
    shape : tuple, optional
        The shape of the nested list to be generated.

    Returns
    -------
    list[float]
        A nested list of zeros with the given shape.
    '''
    if len(shape) == 0: return 0
    if len(shape) == 1: return [0] * shape[0]
    return [_genzeros(shape[1:]) for _ in range(shape[0])]

def _acczeros(shape: tuple = ()) -> list[float]:
    '''Accumulate zeros in a list based on the specified shape.

    Parameters
    ----------
    shape : tuple, optional
        The shape to generate the accumulated zeros for.

    Returns
    -------
    list[float]
        A list of accumulated zeros according to the specified shape.
    '''
    shape = _shape(shape)
    aggfn = lambda x, y: [x] * y
    accum = list(accumulate(shape[::-1], aggfn, initial=0))
    return accum[-1]

# %% ../nbs/07_zero.ipynb 17
def _format_list(
    data: list, prefix: Union[int, str] = 'array('
) -> str:
    '''Format a list into a string with specified indentation and prefix.

    Parameters
    ----------
    data : list
        The list to be formatted.
        
    prefix : Union[int, str], optional
        The prefix to be used for formatting. It can be either a string prefix or 
        an integer representing the indentation level.

    Returns
    -------
    str
        The formatted string representation of the list.
    '''
    indent = len(prefix) if isinstance(prefix, str) else prefix     
    catchr, sepchr = '\n', '], '
    lines = str(data).split(sepchr)
    
    first = lines[0] if len(lines) > 0 else ''
    numbk = first.count('[')
    
    for i in range(len(lines)):
        isfirst, islast = i == 0, i == len(lines) - 1
        # re-add the split character
        if not islast: lines[i] += sepchr
        
        # first line is indented by the characters of `prefix`
        if isfirst: continue
        
        # current number of brackets
        bkcnt = lines[i].count('[')
        # how many brackets are missing (the indent position)
        index = (numbk - bkcnt) + indent
        lines[i] = ' ' * (index)  + lines[i]
        
        # check if next line is last of current level
        if (not islast and bkcnt == 1 and not lines[i + 1].count('[') == 1):
            lines[i] += '\n'
        
    datastr = catchr.join(lines)#.rstrip(sepchr)
    return datastr


# %% ../nbs/07_zero.ipynb 18
class empty(list):
    '''A class representing an empty array with a specified shape.

    Attributes
    ----------
    zeros : list
        A list of zeros according to the specified shape.
        
    shape : tuple
        The shape of the empty array.

    Methods
    -------
    __repr__()
        Return the string representation of the empty array.
    '''
    def __init__(self, shape: tuple= ()):
        shape = _shape(shape)
        zeros = _acczeros(shape)
        super().__init__(zeros)
        self.zeros = zeros
        self.shape = shape
        
    @property
    def ndim(self: Self) -> int:
        '''The number of dimensions of the empty array.'''
        return len(self.shape)
    
    def __repr__(self) -> str: 
        return f'array({_format_list(self.zeros)})'
