#ifndef BOXINGTIMER_H
#define BOXINGTIMER_H

#include <QTimer>
#include <QString>
#include <QStringList>

#ifdef QT_DEBUG
    #include <QDebug>
#endif

/**
 * @defgroup QML What interacts with view
 */

class QSound;
class BoxingSettings;

/**
 * @class BoxingTimer
 * @author Claudio Maradonna <claudio@unitoo.pw>
 *
 * @brief Boxing timer class
 *
 * Inherit QTimer class and add some properties to handle rest and rounds for training
 */
class BoxingTimer : public QTimer {
        Q_OBJECT
        Q_ENUMS(Status)

        /** \cond */
        Q_PROPERTY(QString remainingTimeToString READ remainingTimeToString NOTIFY remainingTimeToStringChanged)
        Q_PROPERTY(QString roundsToString READ roundsToString NOTIFY roundsToStringChanged)
        Q_PROPERTY(Status status READ getStatus WRITE setStatus NOTIFY statusChanged)
        Q_PROPERTY(bool isActive READ isActive NOTIFY activeChanged)
        Q_PROPERTY(QString preset READ getPreset NOTIFY presetChanged)
        /** \endcond */

    public:

        /**
         * @addtogroup QML
         * @fn void restore()
         *
         * @author Claudio Maradonna <claudio@unitoo.pw>
         * @brief Start or restore the timer
         */
        Q_INVOKABLE void restore();

        /**
         * @addtogroup QML
         * @fn void loadPreset(const QString &preset)
         * @param preset a const QString
         *
         * @brief Load the preset to change settings of timer
         */
        Q_INVOKABLE void loadPreset(const QString &preset);

        /**
         * @author Claudio Maradonna <claudio@unitoo.pw>
         *
         * @brief Default constructor
         * @details mRound set to 0 with a very coarse timer. Load default settings.
         */
        explicit BoxingTimer();

        /**
         * @fn const QString roundsToString()
         * @author Claudio Maradonna <claudio@unitoo.pw>
         *
         * @brief  Convert round and total rounds for view
         * @return the number as const QString of actual round and total rounds for QML
         */
        const QString roundsToString();

        /**
         * @fn const QString remainingTimeToString()
         * @author Claudio Maradonna <claudio@unitoo.pw>
         *
         * @brief Convert remaining milliseconds in human readable time
         * @return the remaining time as const QString of remaining milliseconds
         */
        const QString remainingTimeToString();

        /**
         * @enum Status
         *
         * @brief Define the status of the timer
         * Some statuses are not saved, they are used to activate something
         */
        enum class Status : short {
            Default = 0,
            Start,
            Rest,
            Pause,
            Reset,
            Stop
        };

        /**
         * @fn Status getStatus()
         *
         * @return actual status - enum value
         */
        Status getStatus() { return this->mStatus; }

        /**
         * @fn void setStatus(const Status &status)
         * @param status const Status
         *
         * @return Setter for status
         */
        void setStatus(const Status &status);

        /**
         * @fn const QString getPreset()
         *
         * @return the loaded preset for timer
         */
        const QString getPreset();

    public slots:
        /**
         * @fn void applyStatus()
         *
         * @brief Apply status and exec relative functions
         */
        void applyStatus();

        /**
         * @fn void updateRemainingMilliseconds()
         *
         * @brief Switch milliseconds from round to rest and back
         */
        void updateRemainingMilliseconds();

    protected:
        /**
         * @fn void stop()
         *
         * @brief Override of stop function to emit statusChanged() signal
         */
        void stop();

        /**
         * @fn void start(const int &milliseconds)
         *
         * @brief Override of start function to emit statusChanged() signal
         */
        void start(const int &milliseconds);

    private:
        int mRound;

        int mRoundsMilliseconds;
        int mRemainingMilliseconds;

        int mInnerTime;
        int mNumberOfInnerTimers;
        int mInnerRemainingMilliseconds;

        void setRemainingMilliseconds(const int &milliseconds);
        void setRound(const int &round);

        QSound *playBell;
        QSound *restBell;
        QSound *stopBell;
        QSound *innerBell;

        /**
         * @fn void songsBell()
         *
         * @brief Play the bell if status changes
         */
        void songsBell();

        Status mStatus;
        Status mOldStatus;

        BoxingSettings *settings;

        /**
         * @fn void nextRound()
         *
         * @brief Set round to next or eventually stop the timer when reached last round
         */
        void nextRound();

        /**
         * @fn void updateInnerRemainingMilliseconds()
         *
         * @brief Update remaining milliseconds of inner timer
         */
        void updateInnerRemainingMilliseconds();

        /**
         * @fn void setInnerTimers()
         *
         * @brief Setup inner timers from settings
         */
        void setInnerTimers();

    signals:
        void remainingTimeToStringChanged();
        void roundsToStringChanged();

        void statusChanged();
        void presetChanged();
        void activeChanged();
};

Q_DECLARE_METATYPE(BoxingTimer::Status)

#endif // BOXINGTIMER_H
