/*
	Copyright (C) 2025 Mark Tyler

	This program 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.

	This program 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 this program in the file COPYING.
*/

#include "private.h"



mtKit::Thread::Thread ()
	:
	m_thread	( new std::thread ),
	m_mutex		( new std::mutex )
{
}

mtKit::Thread::~Thread ()
{
	join ();		// Wait for thread to stop
}

int mtKit::Thread::start ( CallbackFunc task )
{
	if ( ! task )
	{
		std::cerr << "mtKit::Thread::start: task cannot be NULL!\n";
		return 1;
	}

	// Stop the old thread
	join();

	std::lock_guard<std::mutex> lock( *m_mutex );

	try
	{
		m_thread.reset ( new std::thread( [this, task]()
		{
			try
			{
				task ();
			}
			catch (...)
			{
		// The worker thread task has thrown an exception.
		// If this is important to the caller, they must do a try catch
		// within task() and decide what to do.
			}

			std::lock_guard<std::mutex> lk (*m_mutex);

			m_status = THREAD_FINISHED;
		} ) );
	}
	catch (...)
	{
		std::cerr << "mtKit::Thread::start: error starting the"
			" thread!\n";
		return 1;
	}

	m_status = THREAD_RUNNING;

	return 0;
}

int mtKit::Thread::pause ()
{
	std::lock_guard<std::mutex> lock( *m_mutex );

	switch ( m_status )
	{
	case THREAD_RUNNING:
		m_status = THREAD_PAUSED;
		return 0;
	}

	return 1;
}

int mtKit::Thread::resume ()
{
	std::lock_guard<std::mutex> lock( *m_mutex );

	switch ( m_status )
	{
	case THREAD_PAUSED:
		m_status = THREAD_RUNNING;
		return 0;
	}

	return 1;
}

int mtKit::Thread::terminate ()
{
	std::lock_guard<std::mutex> lock( *m_mutex );

	switch ( m_status )
	{
	case THREAD_RUNNING:
	case THREAD_PAUSED:
		m_status = THREAD_TERMINATED;
		return 0;
	}

	return 1;
}

int mtKit::Thread::join ()
{
	std::unique_lock<std::mutex> lock( *m_mutex );

	if ( m_status == THREAD_PAUSED || m_status == THREAD_RUNNING )
	{
		// Signal to the thread to finish
		m_status = THREAD_TERMINATED;
	}

	if ( m_thread->joinable () )
	{
/* We must unlock the mutex now as the thread might want to lock the mutex, thus
creating a deadlock if we are forever waiting for it finish (it won't as it's
waiting to get the lock to finish). */
		lock.unlock();

		m_thread->join ();
		return 0;
	}

	// Thread not joinable
	return 0;
}

int mtKit::Thread::get_status ()
{
	std::lock_guard<std::mutex> lock( *m_mutex );

	return m_status;
}

int mtKit::Thread::is_running ()
{
	std::lock_guard<std::mutex> lock( *m_mutex );

	return THREAD_RUNNING == m_status;
}



/// ----------------------------------------------------------------------------



bool mtKit::Busy::aborted ()
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	return m_aborted;
}

bool mtKit::Busy::range_changed ()
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	return m_range_changed;
}

int mtKit::Busy::get_min ()
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	return m_min;
}

int mtKit::Busy::get_max ()
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	return m_max;
}

int mtKit::Busy::get_value ()
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	return m_val;
}

void mtKit::Busy::set_minmax ( int const min, int const max )
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	m_min = min;
	m_max = max;
	m_range_changed = true;
}

void mtKit::Busy::set_value ( int const val )
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	m_val = val;
}

void mtKit::Busy::set_aborted ()
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	m_aborted = true;
}

void mtKit::Busy::clear_range_changed ()
{
	std::lock_guard<std::mutex> lock ( m_mutex );

	m_range_changed = false;
}

