import config, filter, random

static V def _schneid_c_k(int k, int N, V const *alpha):
    if N == 1:
        if k >= 0 and k <= N: return 1.0 / sqrt(2)
        return 0.0
    V a = _schneid_c_k(k - 2, N - 2, alpha)
    V b = _schneid_c_k(k, N - 2, alpha)
    V c = _schneid_c_k(N - k, N - 2, alpha)
    V d = _schneid_c_k(N - k - 2, N - 2, alpha)
    V e = 1.0
    if k & 1: e = -1.0

    return \
          0.5 * (a + b) \
        + 0.5 * (a - b) * cos(alpha[(N - 1) / 2 - 1]) \
        + 0.5 * (c - d) * e * sin(alpha[(N - 1) / 2 - 1])

def scaling_to_wavelet_coefficients(int n, V *scaling, V *wavelet):
    V d = 1.0
    for int i = 0; i < n; i++:
        int j = 1 - i
        if j < 0: j += n
        wavelet[i] = scaling[j] * d
        d *= -1.0

static def _filter_recurse(Filter f, int n, V const *alpha):
    for int i = 0; i < f.hn; i++:
        f.h[i] = _schneid_c_k(i, 2 * n + 1, alpha)
    scaling_to_wavelet_coefficients(f.hn, f.h, f.g)

Filter *def schneid_get_filter(int n, V *alpha):
    Filter *f = ALLOCATE0(sizeof *f)
    f->hn = 2 * (n + 1)
    f->gn = 2 * (n + 1)
    f->h = malloc(f->hn * sizeof(V))
    f->g = malloc(f->gn * sizeof(V))
    _filter_recurse(*f, n, alpha)
    return f

def schneid_nosubsample_param(V const *indata, int n, instep,
    V *outlow, int lowstep, V *outhigh, int highstep, scale, pn, V const *alpha):

    Filter f
    f.hn = f.gn = 2 * (pn + 1)
    V h[f.hn] # scaling
    V g[f.gn] # wavelet
    f.h = h
    f.g = g

    _filter_recurse(f, pn, alpha)

    filter(indata, n, instep, g, f.gn, outlow, lowstep, 1 << scale)
    filter(indata, n, instep, h, f.hn, outhigh, highstep, 1 << scale)

V **def schneid(V const *s, int n, char const *key):
    """
    This expects a signal of n samples, and will return (full-length, not
    downsampled) low and high pass results for each subdivision level.

    0 2 4.../log2(n)\ * 2 - 2 are the low pass results
    1 3 5.../log2(n)\ * 2 - 1 the high pass results

    """
    int l = ceil(log2(n));
    V **r = ALLOCATE(l * 2 * sizeof(V *))

    int kn = strlen(key) / 2
    V *a = malloc(kn * sizeof *a)
    for int i = 0; i < kn; i++:
        a[i] = ((key[i * 2] - '0') * 10 + key[i * 2 + 1] - '0') / 99.0 * 2 * pi - pi

    V const *p = s
    for int i = 0; i < l; i++:
        r[i * 2] = ALLOCATE(n * sizeof(V))
        r[i * 2 + 1] = ALLOCATE(n * sizeof(V))
        schneid_nosubsample_param(p, n, 1, r[i * 2], 1, r[i * 2 + 1],
            1, i, kn, a)
        # right now, we always use the lowband for further analysis.
        p = r[i * 2]

    return r
