package net.heartshield.control;

import com.google.gson.annotations.SerializedName;

import net.heartshield.data.Measurement;
import net.heartshield.sensors.IntensityDetector;

/**
 * Coordinates sensors and returns measurement data.
 *
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-04-07
 */
public interface IMeasurementController {
    enum State {
        /** inactive */
        STOPPED,
        /** waiting for user to place finger on camera */
        WAITING,
        /** waiting for camera signal to normalize */
        //CALIBRATING,
        /** capturing heart activity */
        SAMPLING,
        /** one of the sensors failed during measurement */
        FAILED
    }

    void start();
    void stop() throws FramesDroppedException;

    Measurement getMeasurement();

    State getState();

    class FramesDroppedException extends Exception {
        private int mDroppedCount;

        FramesDroppedException(int droppedCount) {
            super(droppedCount + " frames dropped.");
            this.mDroppedCount = droppedCount;
        }
    }

    /** events will arrive on the UI thread. */
    interface Listener {
        void onState(State state);

        void onFrame(double timeSinceStart, double timeSinceLock, double[] rgb, IntensityDetector.ImageSummary summary);
    }
    void setListener(Listener listener);

    double getLockTime();
    void setQualityLockTime(double timeSinceStart);

    enum FailureReason {
        NONE,
        CAMERA_FRAMES_DROPPED,
        CAMERA_FAIL,
        ACCELERO_FAIL,
        AUDIO_FAIL
    }

    /** type/purpose of the measurement */
    enum MeasurementMode {
        @SerializedName("risk")
        RISK,
        @SerializedName("endothelial_function")
        ENDOTHELIAL_FUNCTION,
        @SerializedName("vital_check")
        VITAL_CHECK,
        @SerializedName("paced_breathing")
        PACED_BREATHING,
        @SerializedName("sweep_breathing")
        SWEEP_BREATHING
    }

    FailureReason getFailureReason();
    void setUnderTest(boolean underTest);

    void setMode(MeasurementMode mode);
}
