/**
* File:   environment.h
* Author: Alexander Ksenofontov <aksenofo@yahoo.ru>
*
* Created on August 17, 2016, 16:13 PM
*/

#pragma once

#include <atomic>
#include <thread>
#include <atomic>
#include <libtorrent/session.hpp>

extern std::atomic<uint32_t> torrent_to_http_switch_timeout_milisec;

struct tor_info{
	tor_info()
	: progress_(0.0)
	, added_(false)
	, done_(false)
	, abort_timeout_(false)
	, abort_(false)
	{}

	double progress_;
	bool   added_;
	bool   done_;
	bool   abort_timeout_;
	bool   abort_;
};

inline
std::ostream& operator <<(std::ostream& os, const tor_info& ti) {
	os << "progress:" << ti.progress_ 
	   << " added:" << ti.added_ 
	   << " done:" << ti.done_ 
	   << " abort_timeout:" << ti.abort_timeout_ 
	   << " abort:" << ti.abort_;
	return os;
}

typedef
std::tuple<
	std::chrono::steady_clock::time_point,  // last time activity
	std::shared_ptr<tor_info>,
	std::shared_ptr<std::pair<std::mutex, std::condition_variable>>
> info_t;


class Environment {
public:
	Environment(int listen_port);

	virtual ~Environment();

	Environment(const Environment&) = delete;
	Environment& operator = (const Environment&) = delete;

	void port_stop() { stop_ = true; }

	libtorrent::sha1_hash add(const libtorrent::add_torrent_params& atp);
	void remove(const libtorrent::sha1_hash& hash);

	template <typename function>
	bool wait_for_event(const libtorrent::sha1_hash& id, function fn) {
		auto it(ids_.find(id));
		if (it != ids_.end()) {
			auto& sync_pair(std::get<2>(it->second));
			std::unique_lock<std::mutex> lk(sync_pair->first);
			sync_pair->second.wait(lk);
			auto rc(fn(it->second));
			return stop_ ? false : rc;
		}
		else 
			return false;
	}

private:
	
	void start();

	bool find(const libtorrent::sha1_hash& hash, std::mutex** mtx, 
		      std::condition_variable** cv, tor_info** ti, 
		      std::chrono::steady_clock::time_point** last_time_activity);
	
	void fill_tor_status(const libtorrent::sha1_hash& hash, tor_info& ti);

	std::atomic<bool> stop_;

private:

	libtorrent::session* torrent_session_;

	std::thread* thread_;

	std::mutex  ids_mutex_;
	std::map<libtorrent::sha1_hash, info_t> ids_;

};