#ifndef FFSW_SPEW_THROTTLED_H
#define FFSW_SPEW_THROTTLED_H

#include <stddef.h>         // for size_t
#include <pthread.h>        // for pthread_mutex_lock, pthread_mute...
#include "common/tick.h"    // for tickns

struct spew_throttle {
    pthread_mutex_t mx;
    const tickns_t period;
    tickns_t last_suppressed;
    size_t n_suppressed;
};

// To avoid the "static variable defined locally" warning
#ifndef    __CHECKER__
#define init_throttle(__spew_throttle,wait_time)      \
    static struct spew_throttle __spew_throttle = {   \
        .mx = PTHREAD_MUTEX_INITIALIZER,              \
        .period = (wait_time),                        \
        .last_suppressed = 0,                         \
        .n_suppressed = 0,                            \
    };
#else
#define init_throttle(obj,wait_time)                  \
    struct spew_throttle obj = {                      \
        .mx = PTHREAD_MUTEX_INITIALIZER,              \
        .period = (wait_time),                        \
        .last_suppressed = 0,                         \
        .n_suppressed = 0,                            \
    };
#endif // __CHECKER__

#define spew_throttled(wait_time, level, format, ...)  \
    ({                                                     \
        init_throttle(__spew_throttle, wait_time);         \
        CHECK0(pthread_mutex_lock(&__spew_throttle.mx));   \
        tickns_t __now = tickns();                           \
        if (__now >= (__spew_throttle.last_suppressed) + ( __spew_throttle.period)) {     \
            __spew_throttle.last_suppressed = __now;         \
            spew(level,format " (suppressed:%zu)", ##__VA_ARGS__, __spew_throttle.n_suppressed); \
            __spew_throttle.n_suppressed  = 0;             \
        }                                                  \
        else {                                             \
            __spew_throttle.n_suppressed += 1;             \
        }                                                  \
        CHECK0(pthread_mutex_unlock(&__spew_throttle.mx)); \
    })

#endif // FFSW_SPEW_THROTTLED_H
