package net.heartshield.control;

import junit.framework.TestCase;

import net.heartshield.data.Measurement;
import net.heartshield.data.MeasurementTest;
import net.heartshield.sensors.DummySensorFactory;
import net.heartshield.sensors.IntensityDetector;
import net.heartshield.util.JsonUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-04-14
 */
public class MeasurementControllerTest extends TestCase {
    public void testStateMachine() throws IOException {
        final Measurement origMeasurement = MeasurementTest.measurement1();
        DummySensorFactory factory = new DummySensorFactory(origMeasurement);
        IDevice mockDevice = new MockDevice();

        MeasurementController controller = new MeasurementController(null, mockDevice, factory, null);

        final List<IMeasurementController.State> states = new ArrayList<>();

        controller.setListener(new IMeasurementController.Listener() {
            @Override
            public void onState(IMeasurementController.State state) {
                states.add(state);
            }

            @Override
            public void onFrame(double timeSinceStart, double timeSinceLock, double[] rgb, IntensityDetector.ImageSummary summary) {

            }
        });


        controller.start(); // start() of mock sensor (DummyIntensityDetector) automatically replays
        try {
            controller.stop();
        } catch (IMeasurementController.FramesDroppedException e) {
            // not supposed to happen - we do not test dropped frames
            throw new RuntimeException(e);
        }

        Measurement m = controller.getMeasurement();

        List<double[]> origPpg = origMeasurement.series.ppgData;
        List<double[]> ppg = m.series.ppgData;

        assertEquals(origPpg.size(), ppg.size());

        final double TOL = 1e-4; // why 0.033360999 at i=0 ??? python export resampling is not too accurately spaced?
        final double FPS = 30.0;

        for(int i = 0; i < ppg.size(); i++) {
            for(int j = 1; j < 4; j++)
                if(Math.abs(origPpg.get(i)[j] - ppg.get(i)[j]) > TOL)
                    throw new IllegalStateException("replay and captured PPG disagree at i,j=" + i + "," + j);

            // note: cannot properly check time, as in reality, original PPG is unevenly spaced and misses some beats

            if(i < ppg.size() - 1)
                if(Math.abs((ppg.get(i+1)[0] - ppg.get(i)[0]) - 1.0/FPS) > TOL)
                    throw new IllegalStateException("time not spaced " + (1.0/FPS) + " sec, but rather " + (ppg.get(i+1)[0] - ppg.get(i)[0]) + " sec at i=" + i);
        }

        String mj = m.serialize(JsonUtil.Target.LOCAL);
        String oj = origMeasurement.serialize(JsonUtil.Target.LOCAL);


        List<IMeasurementController.State> expectedStates = Arrays.asList(
                IMeasurementController.State.WAITING,
                IMeasurementController.State.SAMPLING,
                IMeasurementController.State.WAITING,
                IMeasurementController.State.STOPPED
        );

        assertEquals(expectedStates, states);

        //assertEquals(oj, mj); // not exactly true, lets see
        // TODO: flatten the correct aspects, e.g. ppg_data timestamps are misaligned

        //assertEquals(origMeasurement, m); // TODO: this only compares IDs - and even those will mismatch
    }
}
