#pragma once

inline static t_size GetOptimalWorkerThreadCount() throw() {
	return pfc::getOptimalWorkerThreadCount();
}

//! IMPORTANT: all classes derived from CVerySimpleThread must call WaitTillThreadDone() in their destructor, to avoid object destruction during a virtual function call!
class CVerySimpleThread : private pfc::thread {
public:
#ifdef _WIN32
	void StartThread(int winPriority) {
		StartThread(pfc::thread::argWinPriority(winPriority));
	}
#endif
	void StartThread( pfc::thread::arg_t const & arg = pfc::thread::argCurrentThread() ) {
        pfc::thread::start( arg );
	}

	bool IsThreadActive() const {
		return this->pfc::thread::isActive();
	}
	void WaitTillThreadDone() {
		this->pfc::thread::waitTillDone();
	}
protected:
	CVerySimpleThread() {}
	virtual void ThreadProc() = 0;
private:

	void threadProc() {
		this->ThreadProc();
	}

	PFC_CLASS_NOT_COPYABLE_EX(CVerySimpleThread)
};

//! IMPORTANT: all classes derived from CSimpleThread must call AbortThread()/WaitTillThreadDone() in their destructors, to avoid object destruction during a virtual function call!
class CSimpleThread : private completion_notify_receiver, private pfc::thread {
public:
#ifdef _WIN32
	void StartThread(int winPriority) {
		StartThread(pfc::thread::argWinPriority(winPriority));
	}
#endif
	void StartThread(pfc::thread::arg_t const & arg = pfc::thread::argCurrentThread() ) {
		AbortThread();
		m_abort.reset();
		m_ownNotify = create_task(0);
        this->pfc::thread::start( arg );
	}
	void AbortThread() {
		m_abort.abort();
		CloseThread();
	}
	bool IsThreadActive() const {
		return this->pfc::thread::isActive();
	}
	void WaitTillThreadDone() {
		CloseThread();
	}
protected:
	CSimpleThread() {}
	~CSimpleThread() {AbortThread();}

	virtual unsigned ThreadProc(abort_callback & p_abort) = 0;
	//! Called when the thread has completed normally, with p_code equal to ThreadProc retval. Not called when AbortThread() or WaitTillThreadDone() was used to abort the thread / wait for the thread to finish.
	virtual void ThreadDone(unsigned p_code) {};
private:
	void CloseThread() {
		this->pfc::thread::waitTillDone();
		orphan_all_tasks();
	}

	void on_task_completion(unsigned p_id,unsigned p_status) {
		if (IsThreadActive()) {
			CloseThread();
			ThreadDone(p_status);
		}
	}
	void threadProc() {
		unsigned code = ~0;
		try {
			code = ThreadProc(m_abort);
		} catch(...) {}
		if (!m_abort.is_aborting()) m_ownNotify->on_completion_async(code);
	}
	abort_callback_impl m_abort;
	completion_notify_ptr m_ownNotify;

	PFC_CLASS_NOT_COPYABLE_EX(CSimpleThread);
};

