module log

import sync

// ThreadSafeLog embeds Log, and adds a mutex field.
// It uses the mutex to synchronise accesses to the embedded Log.
pub struct ThreadSafeLog {
	Log
pub mut:
	mu sync.Mutex
}

// new_thread_safe_log returns a new log structure, whose methods are safe
// to call by multiple threads.
pub fn new_thread_safe_log() &ThreadSafeLog {
	mut x := &ThreadSafeLog{
		level: .info
	}
	x.mu.init()
	return x
}

// free frees the given ThreadSafeLog instance.
[unsafe]
pub fn (mut x ThreadSafeLog) free() {
	unsafe {
		x.Log.free()
		x.mu.destroy()
		// C.printf(c'ThreadSafeLog free(x), x: %p\n', x)
	}
}

// set_level changes the log level
pub fn (mut x ThreadSafeLog) set_level(level Level) {
	x.mu.@lock()
	x.Log.set_level(level)
	x.mu.unlock()
}

// debug logs a debug message
pub fn (mut x ThreadSafeLog) debug(s string) {
	x.mu.@lock()
	x.Log.debug(s)
	x.mu.unlock()
}

// info logs an info messagep
pub fn (mut x ThreadSafeLog) info(s string) {
	x.mu.@lock()
	x.Log.info(s)
	x.mu.unlock()
}

// warn logs a warning message
pub fn (mut x ThreadSafeLog) warn(s string) {
	x.mu.@lock()
	x.Log.warn(s)
	x.mu.unlock()
}

// error logs an error message
pub fn (mut x ThreadSafeLog) error(s string) {
	x.mu.@lock()
	x.Log.error(s)
	x.mu.unlock()
}

// fatal logs a fatal message, and panics
[noreturn]
pub fn (mut x ThreadSafeLog) fatal(s string) {
	x.mu.@lock()
	defer {
		// TODO: Log.fatal() is marked as noreturn, but this defer is allowed.
		// Think whether it should be, or if it should be a compiler notice at least,
		// since it would not be reached at all (.fatal() panics).
		x.mu.unlock()
	}
	x.Log.fatal(s)
}
