#pragma once

#include <chrono>
#include <iostream>
#include <chrono>
#include <thread>
#include <list>
#include <functional>
#include <atomic>
#include <mutex>
namespace tools
{

namespace tim
{
    
	struct tim_task
	{
		std::function<void()> task;
		int delay;
		std::chrono::high_resolution_clock::time_point tp;
	};

	class timer
	{
	public:
		timer()
			: m_stopflag(false)
		{}

		~timer()
		{
			m_stopflag = true;
			if (m_bgtask.joinable())
				m_bgtask.join();
		}

		void stop()
		{
			m_stopflag = true;
			if (m_bgtask.joinable())
				m_bgtask.join();
			//m_tasks.clear();
		}

		void run()
		{
			m_stopflag = false;
			if (!m_bgtask.joinable())
			m_bgtask = std::thread(&timer::internal_work, this);
		}

		void add_task(std::function<void()> func, int delay_ms)
		{
			tim_task tmp;
			tmp.task = func;
			tmp.delay = delay_ms;
			tmp.tp = std::chrono::high_resolution_clock::now();
			std::lock_guard<std::mutex> lk(m_mutex);
			m_tasks.push_back(tmp);
		}
		void clear_task()
		{
			std::lock_guard<std::mutex> lk(m_mutex);
			m_tasks.clear();
		}
	private:
		std::atomic<bool> m_stopflag;
		std::thread m_bgtask;
		std::mutex	m_mutex;
		void internal_work()
		{
			while (!m_stopflag)
			{
				std::this_thread::sleep_for(std::chrono::milliseconds(5));
				if (m_stopflag)	break;
				std::list<tim_task>::iterator it;
				std::vector<std::function<void()>> _task;
				m_mutex.lock();
				for (it = m_tasks.begin(); it != m_tasks.end();)
				{
					auto now = std::chrono::high_resolution_clock::now();
					auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(now - it->tp).count();
					if (it->delay < tmp)
					{
						//it->task();
						_task.push_back(it->task);
						m_tasks.erase(it++);
					}
					else
					{
						++it;
					}
				}
				m_mutex.unlock();
				for (int i = 0; i< _task.size();++i)
				{
					_task.at(i)();
				}
			}
		}

		std::list<tim_task> m_tasks;
	};

};

};