package net.heartshield.filter;

/**
 * Realtime batch-processing filter block interface.
 *
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-03-26
 */
public abstract class RFilterBlock implements IRFilterBlock {
    protected IRFilterBlock mConsumer;
    protected int mDownsamplingRatio = 1;
    protected int mUpsamplingRatio = 1;

    public void connect(IRFilterBlock consumer) {
        mConsumer = consumer;
    }

    /** batch-add an array and push results through consumers */
    @Override
    public void put(double[] x) {
        double[] res = this.batch(x);
        throwIfBadResultLength(x, res);
        if(mConsumer == null)
            throw new IllegalStateException("must connect a consumer to " + this.getClass().getName());
        mConsumer.put(res);
    }

    private void throwIfBadResultLength(double[] x, double[] res) {
        //if(x.length * mUpsamplingRatio != res.length * mDownsamplingRatio)

        // maybe it's one more sample that's been output
        double s1 = x.length * mUpsamplingRatio;
        double s2 = res.length * mDownsamplingRatio;

        if(mUpsamplingRatio == 1 && mDownsamplingRatio == 1 && res.length != x.length)
            throw new IllegalStateException("x.length=" + x.length + " != res.length=" + res.length + " from batch(x) in " + this.getClass().getName());

        if(Math.abs(s1 - s2) / Math.max(mUpsamplingRatio, mDownsamplingRatio) > 1.0)
            throw new IllegalStateException("x.length=" + x.length + " should yield " + ((double) (x.length * mUpsamplingRatio)) / mDownsamplingRatio + " samples, but got " + res.length);
    }

    /** batch-process an array and return array of output values */
    protected abstract double[] batch(double[] x);
}
