#include "RenderThread.h"

#include "../logging/Logger.h"

#include <chrono>
#include <mutex>
#include <thread>

RenderThread::RenderThread(SystemFrameExchange& frameExchange, Config config) :
	mFrameExchange(frameExchange),
	mConfig(config)
{
}

RenderThread::RenderThread(SystemFrameExchange& frameExchange, InputFrameMailbox* inputMailbox, Config config) :
	mFrameExchange(frameExchange),
	mInputMailbox(inputMailbox),
	mConfig(config)
{
}

RenderThread::~RenderThread()
{
	Stop();
}

bool RenderThread::Start(std::string& error)
{
	if (mThread.joinable())
		return true;

	{
		std::lock_guard<std::mutex> lock(mStartupMutex);
		mStarted = false;
		mStartupError.clear();
	}

	mStopping.store(false, std::memory_order_release);
	mThread = std::thread([this]() { ThreadMain(); });

	std::unique_lock<std::mutex> lock(mStartupMutex);
	if (!mStartupCondition.wait_for(lock, std::chrono::seconds(3), [this]() {
		return mStarted || !mStartupError.empty();
	}))
	{
		error = "Timed out starting render thread.";
		return false;
	}
	if (!mStartupError.empty())
	{
		error = mStartupError;
		lock.unlock();
		if (mThread.joinable())
			mThread.join();
		return false;
	}
	return true;
}

void RenderThread::Stop()
{
	mStopping.store(true, std::memory_order_release);
	if (mThread.joinable())
		mThread.join();
}

void RenderThread::SignalStarted()
{
	std::lock_guard<std::mutex> lock(mStartupMutex);
	mStarted = true;
	mStartupCondition.notify_all();
}

void RenderThread::SignalStartupFailure(const std::string& error)
{
	RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Error, "render-thread", error);
	std::lock_guard<std::mutex> lock(mStartupMutex);
	mStartupError = error;
	mStartupCondition.notify_all();
}
