// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef BASEKIT_THREADS_EVENT_MANUAL_RESET_H
#define BASEKIT_THREADS_EVENT_MANUAL_RESET_H

#include "time/timestamp.h"

#include <memory>

namespace BaseKit {

//! Manual-reset event synchronization primitive
/*!
    Manual-reset event synchronization primitive allows multiple threads to wait for some event occurred
    and signal all waiting threads at the time. If the event is in the signaled state no thread will wait
    for it until the event is reset.

    Thread-safe.

    https://en.wikipedia.org/wiki/Event_(synchronization_primitive)
*/
class EventManualReset
{
public:
    //! Default class constructor
    /*!
        \param signaled - Signaled event initial state (default is false)
    */
    explicit EventManualReset(bool signaled = false);
    EventManualReset(const EventManualReset&) = delete;
    EventManualReset(EventManualReset&& event) = delete;
    ~EventManualReset();

    EventManualReset& operator=(const EventManualReset&) = delete;
    EventManualReset& operator=(EventManualReset&& event) = delete;

    //! Reset the event
    /*!
        If the event is in the signaled state then it will be reset to non signaled state.
        As the result other threads that wait for the event will be blocked.

        Will not block.
    */
    void Reset();

    //! Signal one of waiting thread about event occurred
    /*!
        If some threads are waiting for the event all of them will be signaled and continued.

        Will not block.
    */
    void Signal();

    //! Try to wait the event without block
    /*!
        Will not block.

        \return 'true' if the event was occurred before and no other threads were signaled, 'false' if the event was not occurred before
    */
    bool TryWait();

    //! Try to wait the event for the given timespan
    /*!
        Will block for the given timespan in the worst case.

        \param timespan - Timespan to wait for the event
        \return 'true' if the event was occurred, 'false' if the event was not occurred
    */
    bool TryWaitFor(const Timespan& timespan);
    //! Try to wait the event until the given timestamp
    /*!
        Will block until the given timestamp in the worst case.

        \param timestamp - Timestamp to stop wait for the event
        \return 'true' if the event was occurred, 'false' if the event was not occurred
    */
    bool TryWaitUntil(const UtcTimestamp& timestamp)
    { return TryWaitFor(timestamp - UtcTimestamp()); }

    //! Try to wait the event with block
    /*!
        Will block.
    */
    void Wait();

private:
    class Impl;

    Impl& impl() noexcept { return reinterpret_cast<Impl&>(_storage); }
    const Impl& impl() const noexcept { return reinterpret_cast<Impl const&>(_storage); }

    static const size_t StorageSize = 128;
    static const size_t StorageAlign = 8;
    alignas(StorageAlign) std::byte _storage[StorageSize];
};

/*! \example threads_event_manual_reset.cpp Manual-reset event synchronization primitive example */

} // namespace BaseKit

#endif // BASEKIT_THREADS_EVENT_MANUAL_RESET_H
