// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  Medusa Slockbower
//
//  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.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

///
/// \file fennec/threading/mutex.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///


#ifndef FENNEC_THREADING_MUTEX_H
#define FENNEC_THREADING_MUTEX_H

#include <pthread.h>
#include <errno.h>

#include <fennec/lang/assert.h>

namespace fennec
{

///
/// \brief Basic Mutual Exclusion Support Class
class mutex {

// Definitions =========================================================================================================
public:

	/// \name Definitions
	/// @{

	using handle_t = pthread_mutex_t;

	/// @}


// Constructors & Destructors ==========================================================================================
public:

	/// \name Constructors & Destructor
	/// @{

	///
	/// \brief Mutex Constructor
	/// \details Initializes a mutex handle.
	mutex()
		: _handle() {
		assertf((pthread_mutex_init(&_handle, nullptr) == 0), "Failed to initialize mutex.")
	}

	///
	/// \brief Mutex Destructor
	/// \details Cleans up the underlying handle.
	~mutex() {
		assertf((pthread_mutex_destroy(&_handle) == 0), "Failed to destroy mutex.");
	}

	///
	/// \brief Copy Constructor
	/// \details Deleted, no semantics for copying a mutex.
	mutex(const mutex&) = delete;

	/// @}


// Assignment ==========================================================================================================
public:

	/// \name Assignment
	/// @{

	///
	/// \brief Copy Assignment
	/// \details Deleted, no semantics for copying a mutex.
	/// \returns Deleted
	mutex& operator=(const mutex&) = delete;

	/// @}


// Locking =============================================================================================================
public:

	/// \name Locking
	/// @{

	///
	/// \brief Lock the mutex.
	/// \details Blocks if unable to acquire lock.
	void lock() {
		assertf(pthread_mutex_lock(&_handle) == 0, "Error on lock()!");
	}

	///
	/// \brief Try locking the mutex.
	/// \returns \emph{true} on success, \emph{false} otherwise.
	bool try_lock() {
		const int res = pthread_mutex_trylock(&_handle);
		assertf(res == EBUSY or res == 0, "Error on trylock()!");
		return res == 0;
	}

	///
	/// \brief Release the lock.
	/// \details Asserts that the current thread does not hold a lock on the mutex.
	void unlock() {
		assertf(pthread_mutex_unlock(&_handle) == 0, "Error on unlock()!");
	}

	/// @}


// Private Member Variables ============================================================================================
private:
	pthread_mutex_t _handle;
};

}

#endif // FENNEC_THREADING_MUTEX_H