#pragma once

#include <psemek/async/executor.hpp>
#include <psemek/util/thread.hpp>
#include <psemek/util/synchronyzed_queue.hpp>

#include <vector>
#include <string>
#include <mutex>
#include <condition_variable>

namespace psemek::async
{

	struct threadpool
		: executor
	{
		threadpool(std::string const & name)
			: threadpool(name, std::max(1u, std::thread::hardware_concurrency()))
		{}

		threadpool(std::string const & name, std::size_t thread_count);

		~threadpool() override { stop(); }

		std::size_t thread_count() const { return threads_.size(); }

		void post(task t) override;

		void post_at(clock::time_point time, task t) override;

		void stop() override;

		void clear() override;

		void wait() override;

		void wait_for(clock::duration period) override;

		void wait_until(clock::time_point time) override;

		std::size_t task_count() const override;

	private:
		std::vector<util::thread> threads_;
		util::synchronized_queue<task> task_queue_;

		std::size_t working_count_;
		mutable std::mutex working_count_mutex_;
		std::condition_variable working_count_cv_;
	};

}
