/* GMM (C) 2018-2019 Stephane Charette <stephanecharette@gmail.com>
 * $Id: Log.hpp 2718 2019-02-07 07:08:42Z stephane $
 */

#pragma once

#include "GMM.hpp"


/// Returns the full path where the log file should be saved.
std::string get_log_filename(void);

/// Get access to the stream we're using to log messages.
std::ofstream &get_log_stream(void);

/// Provide a simple timestamp we can use while logging messages.
std::string get_log_timestamp(void);

/// Mutex to prevent multiple threads from clobbering each other during calls to @ref LOG_MSG().
extern CriticalSection logging_mutex;

/// Log a message.  Automatically adds std::endl at the end of the line.
#define LOG_MSG(msg)	\
	do					\
	{					\
		const ScopedLock log_msg_scope_lock(logging_mutex); \
		get_log_stream() << get_log_timestamp() << " " << msg << std::endl; \
	}					\
	while (false)

/// Log a message.
Lox::Exception log_exception( const std::exception *e, const std::string &filename, const int line_number );

/// Log a message, and show a window to the user letting them know something is wrong.
void log_and_show_exception( const std::exception *e, const std::string &filename, const int line_number );


#define LOG_SHOW_AND_THROW_LOX(ex)								\
	log_and_show_exception( &ex, __FILE__, __LINE__ );			\
	ex.shouldDisplay = false;									\
	throw ex

/// Catch C++ exceptions, log, and rethrow
#define CATCH_LOG_SHOW_AND_RETHROW									\
	catch ( const pqxx::pqxx_exception &e )							\
	{																\
		Lox::Exception ex( LOX_WHERE, e );							\
		log_and_show_exception( &ex, __FILE__, __LINE__ );			\
		ex.shouldDisplay = false;									\
		throw ex;													\
	}																\
	catch ( const Lox::Exception &e )								\
	{																\
		log_and_show_exception( &e, __FILE__, __LINE__ );			\
		e.shouldDisplay = false;									\
		throw e;													\
	}																\
	catch ( const std::exception &e )								\
	{																\
		const Lox::Exception ex( LOX_WHERE, e );					\
		log_and_show_exception( &ex, __FILE__, __LINE__ );			\
		ex.shouldDisplay = false;									\
		throw ex;													\
	}																\
	catch ( ... )													\
	{																\
		const Lox::Exception ex(LOX_WHERE, "unknown exception" );	\
		log_and_show_exception( &ex, __FILE__, __LINE__ );			\
		ex.shouldDisplay = false;									\
		throw ex;													\
	}

#define CATCH_AND_LOG												\
	catch ( const pqxx::pqxx_exception &e )							\
	{																\
		const Lox::Exception ex( LOX_WHERE, e );					\
		log_exception( &ex, __FILE__, __LINE__ );					\
	}																\
	catch ( const Lox::Exception &e )								\
	{																\
		log_exception( &e, __FILE__, __LINE__ );					\
	}																\
	catch ( const std::exception &e )								\
	{																\
		const Lox::Exception ex( LOX_WHERE, e );					\
		log_exception( &ex, __FILE__, __LINE__ );					\
	}																\
	catch ( ... )													\
	{																\
		const Lox::Exception ex(LOX_WHERE, "unknown exception" );	\
		log_exception( &ex, __FILE__, __LINE__ );					\
	}
