#pragma once

#include "coroutine.h"

#include <util/generic/list.h>
#include <util/generic/vector.h>

namespace NSrvKernel {

/**
 * Class representing some storage of async tasks.
 *
 * Usefull when you need to remove finished coro tasks rapidly.
 **/
class TCleanableCoroStorage : public TNonCopyable {
public:
    ~TCleanableCoroStorage() {
        Cancel();
        Join();
    }

    /**
     * Create TCoroutine and insert it into storage.
     **/
    template <class F, class... Args>
    void Emplace(const char* name, TContExecutor* exec, F&& f, Args&&... args) {
        RunningTasks_.emplace_front();
        RunningTasks_.front() = TCoroutine{name, exec,
            [&toDelete = ToDelete_, &running = RunningTasks_,
             f = std::move(f), it = RunningTasks_.cbegin()]
            (auto&&... args) mutable {
                f(std::forward<decltype(args)>(args)...);
                toDelete.splice(toDelete.cbegin(), running, it);
            }, std::forward<Args>(args)...};
    }

    /**
     * Cancel all running coroutines.
     **/
    void Cancel() noexcept {
        for (auto& task : RunningTasks_) {
            task.Cancel();
        }
    }

    /**
     * Join all running coroutines.
     **/
    void Join() noexcept {
        while (!RunningTasks_.empty()) {
            RunningTasks_.back().Join();
        }
    }

    /**
     * Remove all finished coro tasks from storage.
     **/
    void EraseFinished() noexcept {
        ToDelete_.clear();
    }

    /**
     * Get number of currently running coroutines."
     **/
    size_t Size() const noexcept {
        return RunningTasks_.size();
    }

private:
    TList<TCoroutine> ToDelete_;
    TList<TCoroutine> RunningTasks_;
};

}  // namespace NSrvKernel
