package net.heartshield.filter;

import net.heartshield.signal.DVec;

/**
 * Window-based almost-realtime processing of a signal.
 * Outputs one sample per window (is downsampling).
 *
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-05-16
 */
public class WindowedDownsampler extends RFilterBlock {
    protected int mDelay;
    protected double[] mBuf;

    protected int N; // left samples
    protected int M; // modulus

    /**
     * @param win window size in samples
     */
    public WindowedDownsampler(int win) {
        mDelay = win;
        mBuf = new double[win];

        if(win <= 0)
            throw new IllegalArgumentException("ratio must be >= 1");
        M = win;
        N = M;
    }

    protected double processWindow(double[] buf, int start) {
        // simple downsampler
        return buf[start + mDelay];
    }

    @Override
    protected double[] batch(double[] x) {
        /*
         * N  left samples  1 <= N <= M
         * L  input length  0 < L
         * M  modulus       1 <= M
         *
         *      N      ||        L
         * +---+---+---++---+---+---+---+---+
         * |   |   |   ||   |   |   |   |   |
         * +---+---+---++---+---+---+---+---+
         */

        int L = x.length;

        double[] buf = DVec.stack(mBuf, x);

        // too short to give even a single sample
        if(N + L <= M) {
            N += L;
            mBuf = DVec.get(buf, buf.length - mDelay, buf.length);
            return new double[0];
        }

        int start = M - N;
        int outLen = (N + L - 1) / M;

        double[] ret = new double[outLen];

        int j = 0;
        for(int i = start; i < L; i += M)
            ret[j++] = processWindow(buf, i);

        N = (N + L - 1) % M + 1;

        mBuf = DVec.get(buf, buf.length - mDelay, buf.length);
        return ret;
    }
}
