timer_event.h
#pragma once

#include <atomic>
#include <functional>
#include <memory>

#include "array_list.h"
#include "asio/steady_timer.hpp"
#include "asio/dispatch.hpp"

namespace flower {
constexpr uint16_t timer_max_count = std::numeric_limits<uint16_t>::max();

class timer_event final : public std::enable_shared_from_this<timer_event> {
public:
    using ptr = std::shared_ptr<timer_event>;
    using call_back = std::function<void(timer_event::ptr)>;
    using event_list = array_list<ptr>;

    timer_event() = delete;

    timer_event(asio::io_context& io, timer_event::event_list& event, uint32_t expires, uint32_t interval,
                int32_t count, call_back&& cb);

    ~timer_event() = default;

    void start_timer();

    void cancel();

    int32_t get_sn() {
        return sn_;
    }

    void set_sn(int32_t sn) {
        sn_ = sn;
    }

private:
    void execute();

    void recovery() {
        event_.remove(sn_);
    }

private:
    uint64_t interval_;
    int32_t count_;
    std::atomic_int32_t sn_;
    call_back call_back_;
    asio::steady_timer timer_;
    event_list& event_;
    bool is_forever_;
};
}  // namespace flower
timer_event.cpp
#include "timer_event.h"

#include "logger.h"

namespace flower {
timer_event::timer_event(asio::io_context& io, timer_event::event_list& event, uint32_t expires, uint32_t interval,
                         int32_t count, call_back&& cb)
    : interval_(interval)
    , count_(count)
    , call_back_(std::move(cb))
    , sn_(-1)
    , timer_(io, std::chrono::milliseconds(expires))
    , event_(event)
    , is_forever_(false) {
    if (count_ == 0) {
        is_forever_ = true;
    }
}

void timer_event::start_timer() {
    timer_.async_wait([this, self = shared_from_this()](asio::error_code ec) {
        if (ec) {
            return;
        }

        if (!call_back_) {
            recovery();
            return;
        }

        call_back_(shared_from_this());

        if (!is_forever_ && --count_ <= 0) {
            recovery();
            return;
        }

        timer_.expires_at(timer_.expiry() + std::chrono::milliseconds(interval_), ec);
        if (ec) {
            LOG_INFO("timer_event::start_timer what:{}", ec.message());
            return;
        }

        start_timer();
    });
}

void timer_event::cancel() {
    asio::error_code ec;
    timer_.cancel(ec);
    recovery();
}
}  // namespace flower