#pragma once

#include <vector>
#include <cassert>
#include <memory>
#include "storage/locking/lock_status.hpp"

namespace tx
{

template <class T>
class LockStore
{
    class LockHolder
    {
    public:
        LockHolder() noexcept = default;

        template <class... Args>
        LockHolder(T* lock, Args&&... args) noexcept : lock(lock)
        {
            assert(lock != nullptr);
            auto status = lock->lock(std::forward<Args>(args)...);

            if(status != LockStatus::Acquired)
                lock = nullptr;
        }

        LockHolder(const LockHolder&) = delete;
        LockHolder(LockHolder&& other) noexcept : lock(other.lock)
        {
            other.lock = nullptr;
        }

        ~LockHolder()
        {
            if(lock != nullptr)
                lock->unlock();
        }

        bool active() const { return lock != nullptr; }

    private:
        T* lock {nullptr};
    };

public:
    template <class... Args>
    void take(T* lock, Args&&... args)
    {
        auto holder = LockHolder(lock, std::forward<Args>(args)...);

        if(!holder.active())
            return;

        locks.emplace_back(LockHolder(lock, std::forward<Args>(args)...));
    }

private:
    std::vector<LockHolder> locks;
};

};