#ifndef FZ_RUNDOWN_PROTECTION_HPP
#define FZ_RUNDOWN_PROTECTION_HPP

#include <atomic>
#include <libfilezilla/mutex.hpp>

namespace fz {

class rundown_protection
{
	using state_type = uint64_t;
	static_assert(std::atomic<state_type>::is_always_lock_free, "std::atomic<state_type> must be always lock free");

public:
	rundown_protection() = default;

	bool acquire() noexcept;
	void release() noexcept;
	bool acquire_enabled() const noexcept;
	void disable_acquire() noexcept;
	void wait_until_all_acquires_released() noexcept;

	state_type acquired_count()	const noexcept;

private:
	static constexpr int state_size = std::numeric_limits<state_type>::digits;
	static constexpr state_type DISABLED_BIT = state_type(1) << (state_size-1);
	static constexpr state_type COUNT_MASK  = ~DISABLED_BIT;

	std::atomic<state_type> state_{0};
	fz::mutex m_;
	fz::condition cv_;
};

}

#endif // FZ_RUNDOWN_PROTECTION_HPP
