/* 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/>.
 */

#pragma once

#include "eventia/private/context.hpp"
#include "eventia/timer.hpp"
#include "oro/dboperation.hpp"
#include "oro/source.hpp"

namespace oro {
	class Api;
	class OriginsDB;
	struct Header;
	struct Shops;
	struct Icons;
	struct Items;
	struct Creators;
} //namespace oro

namespace duck {

class EventiaThreadPool;

struct TimerSettings {
	TimerSettings (
		double min_wait,
		double extra_delay,
		double err_timeout,
		oro::SourceFormat store_mode,
		unsigned int err_retries
	) :
		min_wait(min_wait),
		extra_delay(extra_delay),
		err_timeout(err_timeout),
		src_store_mode(store_mode),
		err_retries(err_retries)
	{ }

	double min_wait;
	double extra_delay;
	double err_timeout;
	oro::SourceFormat src_store_mode;
	unsigned int err_retries;
};

class TimerBase : public eve::Timer {
public:
	TimerBase (
		const eve::Context& ctx,
		oro::DBOperation type,
		const TimerSettings& settings,
		EventiaThreadPool* pool,
		oro::Api* oro_api,
		oro::OriginsDB* db
	);
	virtual ~TimerBase() noexcept = default;

	virtual void on_timer() override;

protected:
	void set_next_timer (const oro::Header& header);
	void update_db (const oro::Shops& shops, const oro::Header& header, const oro::Source& source);
	void update_db (const oro::Items& items, const oro::Header& header, const oro::Source& source);
	void update_db (const oro::Icons& icons, const oro::Header& header, const oro::Source& source);
	void update_db (const oro::Creators& creators, const oro::Header& header, const oro::Source& source);
	EventiaThreadPool& pool();
	oro::Api& oro_api();
	oro::OriginsDB& db();
	void reset_db_access_time (oro::DBOperation op);

protected:
	double error_timeout() const noexcept;
	unsigned int error_retries() const noexcept;

private:
	virtual void fetch_data(oro::SourceFormat store_mode) = 0;

	double m_extra_delay;
	double m_min_wait;
	double m_err_timeout;
	EventiaThreadPool* m_pool;
	oro::Api* m_oro_api;
	oro::OriginsDB* m_db;
	oro::SourceFormat m_source_store_mode;
	unsigned int m_err_retries;
};

} //namespace duck
