/*
 * thread.cpp
 *
 *  Created on: Sep 14, 2023
 *      Author: Dario
 */


#include <sta/tacos/thread.hpp>
#include <sta/debug/assert.hpp>
#include <sta/debug/debug.hpp>
#include <sta/rtos/system/events.hpp>

#include <functional>
#include <cstring>


namespace sta
{
	namespace tacos
	{
		TacosThread::TacosThread(const char* name, osPriority_t prio)
				: RtosThread(RtosHandle<osThreadId_t>(Handle::Deferred(&instance_))),
				  instance_{ NULL },
				  attribs_{ .name = name, .priority = prio },
				  running_{false}
		{}

		TacosThread::TacosThread()
				: RtosThread(RtosHandle<osThreadId_t>(Handle::Deferred(&instance_))),
				  instance_{ NULL },
				  attribs_{ },
				  running_{false}
		{}

		void TacosThread::entry_point(void* arg)
		{
			STA_ASSERT(arg != nullptr);

			TacosThread* instance = reinterpret_cast<TacosThread*>(arg) ;
			instance->loop();
		}

		void TacosThread::start()
		{
			STA_ASSERT(!isRunning());

			// If this is the first time starting the thread, it has to be started via rtos first.
			if (instance_ == NULL)
			{
				instance_ = osThreadNew(entry_point, this, &attribs_);

				STA_ASSERT(instance_ != NULL);
			}

			// Send a thread start signal.
			sysNotify(STA_RTOS_THREAD_FLAG_START);
		}

		bool TacosThread::isRunning()
		{
			return running_;
		}

		osThreadId_t TacosThread::getInstance()
		{
			STA_ASSERT(isRunning());

			return instance_;
		}

		const char* TacosThread::getName() const
		{
			return attribs_.name;
		}

		void TacosThread::init() {}

		void TacosThread::loop()
		{
			// Infinite loop allowing quick restarts of this thread after termination.
			while (true)
			{
				// The thread has to wait until the system startup has been completed.
				rtos::waitForStartupEvent();

				// Wait for a thread start flag.
				wait(STA_RTOS_THREAD_FLAG_START);

				// Call user-defined initialization code.
				running_ = true;
				init();

				// Run the thread until the termination flag is set. Reset this
				while (!isTerminationRequested())
				{
					func();
				}

				// Clear the termination request flag for this thread.
				deleteTerminationRequest();

				// Call user-defined cleanup code.
				cleanup();
				running_ = false;
			}

			osThreadExit();
		}

		void TacosThread::cleanup() {}

		bool TacosThread::operator==(const TacosThread& other) const
		{
			return std::strcmp(this->getName(), other.getName()) == 0;
		}

		bool TacosThread::operator<(const TacosThread& other) const
		{
			return std::strcmp(this->getName(), other.getName()) < 0;
		}

		TacosThread::~TacosThread(){}

	}  // namespace tacos
}  // namespace sta

