/* Copyright 2020, Michele Santullo
 * This file is part of orotool.
 *
 * Orotool is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Orotool is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Orotool.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "evloop.hpp"
#include "timer_oro_api.hpp"
#include "eventia/eventia.hpp"
#include "eventia/signal.hpp"
#include "eventia_thread_pool.hpp"
#include "oro/dboperation.hpp"
#include "app_config.hpp"
#include <iostream>

namespace duck {
namespace {
	//class KeepaliveTimer : public ev::timer {
	//public:
	//	KeepaliveTimer (ev::loop_ref& loop, RunningPool::subpool_type*) {
	//		this->set(loop);
	//		this->set<KeepaliveTimer, &KeepaliveTimer::on_timer_ev>(this);
	//		ev::timer::start(5.0, 5.0);
	//	}

	//	void on_timer_ev() {
	//	}
	//};

	class SignalInt : public eve::Signal {
	public:
		SignalInt (const eve::Context& ctx, eve::Eventia* even) :
			eve::Signal(SIGINT, ctx),
			m_eventia(even)
		{ }

		virtual void on_signal() override {
#if !defined(NDEBUG)
			std::cout << "SIGINT received!!\n";
#endif
			m_eventia->stop();
		}

	private:
		eve::Eventia* m_eventia;
	};

	struct TimerSettingsHelper : TimerSettings {
		TimerSettingsHelper (
			double ed,
			double et,
			oro::SourceFormat sf,
			unsigned int er
		) :
			TimerSettings {0.0, ed, et, sf, er}
		{
		}

		TimerSettings operator() (double mwait) const {
			TimerSettings ret = *static_cast<const TimerSettings*>(this);
			ret.min_wait = mwait;
			return ret;
		}
	};
} //unnamed namespace

void test(oro::Api* api, oro::OriginsDB* db, const AppConfig& app_conf) {
	typedef TimerOroApi<oro::DBOperation::Shops> TimerShops;
	typedef TimerOroApi<oro::DBOperation::Items> TimerItems;
	typedef TimerOroApi<oro::DBOperation::Icons> TimerIcons;
	typedef TimerOroApi<oro::DBOperation::Creators> TimerCreators;

	std::cout << "Running with " << app_conf.worker_threads() << " worker threads\n";
	eve::Eventia worker;
	EventiaThreadPool pool(&worker, app_conf.worker_threads());

	auto sig_int = worker.make_event<SignalInt>(&worker);

	const double w1 = static_cast<double>(app_conf.items_timeout());
	const double w2 = static_cast<double>(app_conf.icons_timeout());
	const double w3 = static_cast<double>(app_conf.shops_timeout());
	const double w4 = static_cast<double>(app_conf.creators_timeout());

	TimerSettingsHelper tset{
		static_cast<double>(app_conf.fetch_extra_delay()),
		static_cast<double>(app_conf.error_retry_timeout()),
		(app_conf.store_raw_json() ? app_conf.json_store_mode() : oro::SourceFormat::None),
		app_conf.max_connection_retries()
	};
	auto timer_items = worker.make_event<TimerItems>(tset(w1), &pool, api, db);
	auto timer_icons = worker.make_event<TimerIcons>(tset(w2), &pool, api, db);
	auto timer_shops = worker.make_event<TimerShops>(tset(w3), &pool, api, db);
	auto timer_creat = worker.make_event<TimerCreators>(tset(w4), &pool, api, db);

	try {
		pool.submit(worker.event_functor());
		worker.wait();
	}
	catch (...) {
		pool.wait();
		throw;
	}
#if !defined(NDEBUG)
	std::cout << "all tasks completed\n";
#endif
}
} //namespace duck
