#pragma once

#include <mutex>
#include <cstdint>
#include <condition_variable>

#include <iostream>

#include "flags_iface.hpp"

class Flags : public FlagsIface {
public:
    Flags() : flags_{0} {
    }

    virtual void set_flag(uint32_t mask) override 
    {
        {
            std::lock_guard<std::mutex> guard(mutex_);
            flags_ |= mask;
        }
        flag_cond_.notify_all();
    }

    virtual uint32_t get_flag(uint32_t mask) override {
        uint32_t out;
        {
            std::lock_guard<std::mutex> guard(mutex_);
            out = flags_ & mask;
        }
        return out;
    }

    virtual uint32_t get_flags() override {
        uint32_t out;
        {
            std::lock_guard<std::mutex> guard(mutex_);
            out = flags_;
        }

        return out;
    }

    virtual void clear_flags(uint32_t mask) override
    {
       std::lock_guard<std::mutex> guard(mutex_);
       flags_ &= ~mask;
    }
    
    /**
     * @brief Данная реализация блочит потоки pnet. 
     * Нужно разбираться.
     * 
     */
    virtual uint32_t wait_flags(uint32_t mask) override
    {
        uint32_t out;
        std::unique_lock<std::mutex> lk(mutex_);
        flag_cond_.wait(lk, [this, mask]{return static_cast<bool>(flags_ & mask);});
        out = flags_ & mask;
        lk.unlock();
        return out;
    }
private:
    uint32_t flags_;
    std::mutex mutex_;
    std::condition_variable flag_cond_;
};