/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Worker.h
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#pragma once

#include <string>
#include <thread>
#include "Guards.h"

namespace dev
{

class Worker
{
protected:
	Worker(std::string const& _name = "anon", unsigned _idleWaitMs = 30): m_name(_name), m_idleWaitMs(_idleWaitMs) {}

	/// Move-constructor.
	Worker(Worker&& _m) { std::swap(m_name, _m.m_name); }

	/// Move-assignment.
	Worker& operator=(Worker&& _m) { std::swap(m_name, _m.m_name); return *this; }

	virtual ~Worker() { stopWorking(); }

	/// Allows changing worker name if work is stopped.
	void setName(std::string _n) { if (!isWorking()) m_name = _n; }

	/// Starts worker thread; causes startedWorking() to be called.
	void startWorking();
	
	/// Stop worker thread; causes call to stopWorking().
	void stopWorking();
	
	/// Returns if worker thread is present.
	bool isWorking() const { Guard l(x_work); return !!m_work; }
	
	/// Called after thread is started from startWorking().
	virtual void startedWorking() {}
	
	/// Called continuously following sleep for m_idleWaitMs.
	virtual void doWork() = 0;
	
	/// Called when is to be stopped, just prior to thread being joined.
	virtual void doneWorking() {}

private:
	std::string m_name;
	unsigned m_idleWaitMs = 0;
	
	mutable Mutex x_work;						///< Lock for the network existance.
	std::unique_ptr<std::thread> m_work;		///< The network thread.
	bool m_stop = false;
};

}