import numpy as np 


def _strided_app(a, L, S):  # Window len = L, Stride len/stepsize = S
    """returns an array that is strided
    """
    nrows = ((a.size-L)//S)+1
    n = a.strides[0]
    r =  np.lib.stride_tricks.as_strided(
        a, 
        shape=(nrows, L), 
        strides=(S*n, n),
        writeable=False)
    last = r.shape[0]*r.shape[1]
    l = r.tolist()
    if last < len(a):
        l.append(a[last:])
    return l
    

def apply_rolling_data(values : np.ndarray, function, window, step=1):
    """Perform a rolling window analysis at the column `col` from `data`

    Given a dataframe `data` with time series, call `function` at
    sections of length `window` at the data of column `col`. Append
    the results to `data` at a new columns with name `label`.

    Parameters:
    
    data: 1-D Time series of data
    function: Function to be called to calculate the rolling window
        analysis, the function must receive as input an array or
        pandas series. Its output must be either a number or a pandas
        series
    window: length of the window to perform the analysis
    step: step to take between two consecutive windows

    Returns:
    -------
        data: Columns generated by the function applied

    """

    x = _strided_app(values, window, step)

    return np.vstack([function(np.array(b)) for b in x])
    
