#ifndef _MARIONETTE_H
#define _MARIONETTE_H

#include <boost/asio/signal_set.hpp>
#include <cstdint>
#include <atomic>
#include <exception>
#include <functional>
#include <memory>
#include <optional>
#include <spinscale/component.h>
#include <spinscale/co/nonViralTaskNursery.h>
#include <marionette/marionetteThread.h>
#include <user/smoHooks.h>

namespace sscl {

class PuppeteerThread;

} // namespace sscl

namespace smo {
namespace mrntt {

class MarionetteComponent
:	public sscl::pptr::PuppeteerComponent
{
public:
	MarionetteComponent(const std::shared_ptr<sscl::PuppeteerThread> &thread)
	:	sscl::pptr::PuppeteerComponent(thread)
	{}
	~MarionetteComponent() = default;

	void holdInitializeCReq(
		std::function<void(std::exception_ptr &exceptionPtr)> completion);
	void holdFinalizeCReq(
		std::function<void(std::exception_ptr &exceptionPtr)> completion);

	MrnttNonViralPostingInvoker initializeCReq(
		std::exception_ptr &exceptionPtr,
		std::function<void()> callback);

	MrnttNonViralPostingInvoker finalizeCReq(
		std::exception_ptr &exceptionPtr,
		std::function<void()> callback);

	void exceptionInd();

	void handleLoopExceptionHook() override;

	static void preJoltHook(sscl::PuppeteerThread &thr);

protected:
	void postJoltHook() override;
	void tryBlock1Hook() override;
	void preLoopHook() override;
	void postLoopHook() override;
	void postTryBlock1CatchHook() override;
	void handleTryBlock1TypedException(const std::exception& e) override;
	void handleTryBlock1UnknownException() override;

private:
	std::unique_ptr<boost::asio::signal_set> signals;
	bool callShutdownSalmanoff = false;
	sscl::co::NonViralTaskNursery taskNursery;
};

extern std::shared_ptr<sscl::PuppeteerThread> thread;
extern MarionetteComponent mrntt;
extern stim_buff::SmoThreadingModelDesc smoThreadingModelDesc;

void initializeSmoThreadingModelDesc(
	const std::shared_ptr<sscl::ComponentThread>& componentThread);

const stim_buff::SmoThreadingModelDesc& getSmoThreadingModelDesc();

void marionetteInitializeReqCb(bool success);
void marionetteFinalizeReqCb(bool success);

} // namespace mrntt
} // namespace smo

#endif
