/*
    KStars UI tests for verifying correct counting of the capture module

    SPDX-FileCopyrightText: 2020 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#pragma once

#include <QObject>
#include <QQueue>

#include "config-kstars.h"
#include "test_ekos_debug.h"

#if defined(HAVE_INDI)
#include "ekos/ekos.h"
#include "ekos/capture/sequencejob.h"
#include "test_ekos_capture_helper.h"

class TestEkosCaptureCount : public QObject
{
        Q_OBJECT
    public:
        explicit TestEkosCaptureCount(QObject *parent = nullptr);

    protected:

        /**
         * @brief Setup capturing
         * @return true iff preparation was successful
         */
        bool prepareCapture();

        /**
         * @brief Setup capturing for tests with the scheduler
         * @param completionCondition completion condition for the scheduler
         * @return true iff preparation was successful
         */
        bool prepareScheduledCapture(Ekos::CompletionCondition completionCondition);

        /**
         * @brief Prepare the scheduler for the test.
         * @param sequenceFile File name of the capture sequence file
         * @param sequence filter and count as QString("<filter>:<count"), ... list
         * @param capturedFramesMap mapping from filter to existing frames per filter as QString("<filter>:<count"), ... list
         * @param completionCondition completion condition for the scheduler
         * @param iterations number of iterations to be executed (only relevant if completionCondition == FINISH_REPEAT)
         * @param rememberJobProgress should the scheduler use the option "Remember job progress"
         * @param exptime exposure time (identical for all frames)
         * @return true iff preparation was successful
         */
        bool setupScheduler(QString sequenceFile, QString sequence, QString capturedFramesMap,
                            Ekos::CompletionCondition completionCondition,
                            int iterations, bool rememberJobProgress, double exptime);

        /**
         * @brief Verify the counts that the scheduler displays in the job table
         * @param sequence filter and count as QString("<filter>:<count"), ... list
         * @param capturedFramesMap mapping from filter to existing frames per filter as QString("<filter>:<count"), ... list
         * @param completionCondition completion condition for the scheduler
         * @param iterations number of iterations to be executed (only relevant if completionCondition == FINISH_REPEAT)
         * @param rememberJobProgress should the scheduler use the option "Remember job progress"
         * @param exptime exposure time (identical for all frames)
         * @return true iff the displayed counts match the specification
         */
        bool verifySchedulerCounting(QString sequence, QString capturedFramesMap, Ekos::CompletionCondition completionCondition,
                                     int iterations, bool rememberJobProgress, double exptime);

        /**
         * @brief Execute capturing
         * @return true iff exactly the expected frames have been taken
         */
        bool executeCapturing();

        /**
         * @brief Helper function translating simple QString input into QTest test data rows
         * @param exptime exposure time of the sequence
         * @param sequence filter and count as QString("<filter>:<count"), ... list
         * @param capturedFramesMap mapping from filter to existing frames per filter as QString("<filter>:<count"), ... list
         * @param expectedFrames expected number of frames per filter as QString("<filter>:<count"), ... list
         * @param iterations number of iterations the capture sequence should be repeated
         */
        void prepareTestData(double exptime, QString sequence, QString capturedFramesMap, QString expectedFrames,
                             int iterations = 1);

        // mapping between image signature and number of images expected to be captured for this signature
        QMap<QString, int> m_expectedImages;
        /**
         * @brief Register that a new image has been captured
         */
        void captureComplete(const QVariantMap &metadata);

        // sequence of scheduler states that are expected
        QQueue<Ekos::SchedulerState> expectedSchedulerStates;
        /**
         * @brief Slot to receive a new scheduler state
         * @param status new capture status
         */
        void schedulerStateChanged(Ekos::SchedulerState status);

        // current scheduler status
        Ekos::SchedulerState m_SchedulerStatus;

        /**
         * @brief Retrieve the current capture status.
         */
        inline Ekos::SchedulerState getSchedulerStatus()
        {
            return m_SchedulerStatus;
        }


    protected slots:
        void initTestCase();
        void cleanupTestCase();

        void init();
        void cleanup();

    private:
        // current capture status
        Ekos::CaptureState m_CaptureStatus;

        // helper class
        TestEkosCaptureHelper *m_CaptureHelper = nullptr;

        QString target = "test";

        /**
         * @brief Fill the map of frames that have already been captured
         * @param expectedFrames comma separated list of <filter>:<count>
         * @param imagepath base directory holding all images
         * @return true if everything was successful
         */
        bool fillCapturedFramesMap(QString capturedFramesMap, QString imagepath);

        /**
         * @brief Determine the total count from a comma separated sequence of <filter>:<count>
         * @return sum of <count>
         */
        int totalCount(QString sequence);

        /**
         * @brief Determine the map filter --> counts from a comma separated sequence of <filter>:<count>
         * @param sequence
         * @return
         */
        QMap<QString, uint16_t> framesMap(QString sequence);

        /**
         * @brief Fill the map of frames that are expected to be captured
         * @param expectedFrames comma separated list of <filter>:<count>
         * @return true if everything was successful
         */
        bool setExpectedFrames(QString expectedFrames);


        /**
         * @brief Check if the expected number of frames are captured
         * @return true if yes
         */
        bool checkCapturedFrames();

    private slots:
        /**
         * @brief Test whether the capture module produces exactly the diff between the capture frames map and the defined frame counts.
         */
        void testCaptureWithCaptureFramesMap();

        /** @brief Test data for @see testCaptureWithCaptureFramesMap() */
        void testCaptureWithCaptureFramesMap_data();

        /**
         * @brief Test of appropriate captures controlled by the scheduler for fixed
         *        number of iterations.
         */
        void testSchedulerCapture();

        /** @brief Test data for @see testSchedulerCapture() */
        void testSchedulerCapture_data();

        /**
         * @brief Test of appropriate capturing for the scheduler using the
         *        "Repeat until terminated" option.
         */
        void testSchedulerCaptureInfiteLooping();

        /** @brief Test data for @see testSchedulerCaptureInfiteLooping() */
        void testSchedulerCaptureInfiteLooping_data();
};

#endif // HAVE_INDI
