package net.heartshield.signal;

import junit.framework.TestCase;

import net.heartshield.filter.LineChart;
import net.heartshield.filter.PlotFilter;
import net.heartshield.signal.DVec;
import net.heartshield.signal.IVec;
import net.heartshield.signal.Signal;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-03-12
 */
public class SignalTests extends TestCase {
    private static final double EPS = 1e-6;

    public void setUp() throws Exception {
        super.setUp();
    }
    public void tearDown() throws Exception {
        super.tearDown();
    }

    public void testDiff() {
        double[] a = new double[]{ 1., 2., 5. };
        double[] d = DVec.diff(a);
        double[] expect_d = new double[]{ 1., 3. };

        if(!IVec.all(DVec.eqt(d, expect_d, EPS)))
            throw new IllegalStateException("test failed");
    }

    public void testLocalmax() {
        double[] a   = new double[]{ 1., 2., 5., 3., 0., 4., -1. };
        int[] expect_lm = new int[]{ 0,  0,  1,  0,  0,  1,   0 };
        int[] lm = Signal.heartbeat_localmax(a);
        //System.out.println("heartbeat_localmax="+ IVec.toString(lm));

        if(!IVec.all(IVec.eq(lm, expect_lm)))
            throw new IllegalStateException("test failed");
    }

    public void testRunningMean() {
        double[] a        = new double[]{ 1., 2.,  4.,  3.,  2., 1. };
        double[] expect_m = new double[]{  1.5, 3., 3.5, 2.5, 1.5 };
        double[] m = Signal.running_mean(a, 2);
        //System.out.println("heartbeat_localmax="+ IVec.toString(lm));

        if(!IVec.all(DVec.eqt(m, expect_m, EPS)))
            throw new IllegalStateException("test failed");
    }

    public void testPercentile() {
        double[] a        = new double[]{ 10,  7,  4, 3,  2,  1 };
        double[] q = new double[]{        0.0, 100.0, 60.0, 80.0, 50.0, 66.666666666 };
        double[] expect_p = new double[]{ 1.0,  10.0,  4.0,  7.0,  3.5,  4.99999999 };

        double[] p = new double[q.length];

        for(int i = 0; i < q.length; i++)
            p[i] = Signal.percentile(a, q[i]);

        if(!IVec.all(DVec.eqt(p, expect_p, EPS)))
            throw new IllegalStateException("test failed");
    }

    private static final double FPS = 30.0;

    /** rough detrending as done by PlotFilter (more for visuals and is not precise [optimized for less filter delay]) */
    private Series plotDetrend(Series series) {
        final int PLOT_SAMPLES = 100;
        final double TOTAL_TIME = 15.0;

        PlotFilter pf = new PlotFilter(FPS, (int) (TOTAL_TIME * FPS + 1), PLOT_SAMPLES);
        for(int i = 0; i < series.x.length; i++)
            pf.addUneven(series.t[i], series.x[i]);

        PlotFilter.Series ser = pf.getRecentSeries(pf.size());
        // to do: why is getPlotTimes() off by a few samples?! (time starts at 0.1 sec)
        double[] times = ser.t;
        //double[] frames = pf.getEvenFrames();
        double[] frames = ser.x;

        return new Series(times, frames);
    }

    public void testDetrend1() {
        Series series = new Series("data/1480348240_B319CE46_meta.ppg_raw_even.json");

        Series detrended = plotDetrend(series);

        detrended.t = DVec.get(detrended.t, (int) (5.0 * FPS), detrended.t.length);
        detrended.x = DVec.get(detrended.x, (int) (5.0 * FPS), detrended.x.length);

        //LineChart lc = LineChart.plot(series.t, series.x);
        LineChart lc = LineChart.plot(detrended.t, detrended.x);
        lc.showChart();
        lc.waitChart();
    }

    public void testBeatDetector() {
        Series series = new Series("data/1480348240_B319CE46_meta.ppg_raw_even.json");

        Series detrended = plotDetrend(series);

        //double[] sig = detrended.x;
        double[] sig = DVec.get(detrended.x, 0, 450);

        Double bpm = Signal.calculateBpm(FPS, sig);

        assertNotNull(bpm);
        System.out.println("bpm = " + bpm);
        // full one: bpm = 80.49580151495677
        // [:600]: bpm = 70.47058823529389
        // [:450]: bpm = 69.34362934362998
    }

    public void testInterp() {
        double[] xp = new double[]{ 1., 2.,  3. };
        double[] fp = new double[]{ 1., 2.,  2. };
        double[] x        = new double[]{ 0.5, 1.5, 2.5, 3.5 };
        double[] expect_y = new double[]{ 1. , 1.5, 2. , 2. };
        double[] y = Signal.interp(x, xp, fp);

        System.out.println("interp(x,xp,fp)="+ DVec.toString(y));

        if(!IVec.all(DVec.eqt(y, expect_y, EPS)))
            throw new IllegalStateException("test failed");
    }
}
