// spdloglb.cpp : Definiert die exportierten Funktionen für die DLL-Anwendung.
//



#include "stdafx.h"
#include "spdlog/spdloglb_VarArg.h"
#include "spdlog/spdloglb_ostream.h"
#include "spdlog/cstyle/sink_handle.h"
#include "spdlog/cstyle/logger_handle.h"
#include "spdloglb_helpers.h"

//#include "Sink_mgr.h"
//#include "BaumEventLog_ResourceList.h"

namespace spdlog
{


	DWORD								g_InstanceCount = 0;


	void logger_error_handler(const std::string &err_msg);

	class spdloglib_error_manager
	{
	private:
		error_callback*		_callback;

	public:
		spdloglib_error_manager()
		{
			_callback = NULL;
		}

		void init(error_callback* lp_err_clb)
		{
			if (lp_err_clb)
				free();
			_callback = lp_err_clb;
			if (_callback)
			{
				spdlog::set_error_handler(logger_error_handler);
			}
		}
		void free(void)
		{
			spdlog::set_error_handler(NULL);
		}

		void on_error(const char* lpMsg)
		{
			if (_callback)
				_callback->on_error(lpMsg);
		}

	}g_spdloglib_error_manager;

	
	void logger_error_handler(const std::string &err_msg)
	{
		g_spdloglib_error_manager.on_error(err_msg.c_str());
	}


	// Initialize the library and define some per instance modes
	// The library may get loaded and initialized by more than one modules of the current process. But the "per instance" values
	// has to be unique for one instance (one running exe). So this values are stored at the first call, the next call returns
	// BevlInitReturn_WasInitialized to indicate that this settings was not incorperated at all. So there are the following rules:
	//
	// * AsyncMode with all its settings (QueueSize ...) has to be defined unique to one application
	// * If any of the logs are accessed by more than one thread, it is required to set "MultiThreaded" to true.
	//   Missing this may cause really bad side effects (missing synchronisation)
	// * Never use the same logfile from two different applications (EXE-Files)
	// * Not really sure about the impact, but I think it is a good idea to write different logfiles for each instance,
	//	 if the program supports more than one instance.
	//
	// Parameters:
	// AsyncMode:				Speeds up logging by creating a queue for the log messages
	// QueuSize:				Size of the queue that gets created for each logger
	// OverflowPolicy:			Defines what to do if a queue is full.
	//							0 -> hold/sleep the program until the queue has space again
	//							1 -> discard the message
	// FlushIntervalMs:			Defines the interval to perform automatic flush operations on a queue
	SPDLOGLB_API spdlog::InitReturn SpdLog_Init(bool AsyncMode, unsigned long QueueSize, unsigned long OverflowPolicy, unsigned long FlushIntervalMs, error_callback* lp_err_clb)
	{
		if (g_InstanceCount++ == 0)
		{
			g_spdloglib_error_manager.init(lp_err_clb);

			spdlog::async_overflow_policy		opc = spdlog::async_overflow_policy::block_retry;

			switch (OverflowPolicy)
			{
			case unsigned long(spdlog::async_overflow_policy::block_retry) :
				opc = spdlog::async_overflow_policy::block_retry;
				break;

			case unsigned long(spdlog::async_overflow_policy::discard_log_msg) :
				opc = spdlog::async_overflow_policy::discard_log_msg;
				break;
			}

			std::chrono::milliseconds			fims = std::chrono::milliseconds::zero();
			fims += std::chrono::milliseconds(FlushIntervalMs);


			if (AsyncMode)
				spdlog::details::registry::instance().set_async_mode(QueueSize, opc, NULL, fims, NULL);
			else
				spdlog::details::registry::instance().set_sync_mode();

			return InitReturn_Succeed;
		}
		else
			return InitReturn_WasInitialized;
	}


	SPDLOGLB_API bool SpdLog_Free(void)
	{
		if (--g_InstanceCount == 0)
		{

			g_InstanceCount = 0;
			// Free all remaining objects
			sink_handle_factory::drop_all();
			logger_handle_factory::drop_all();
			spdlog::details::registry::instance().drop_all();
			spdlog::details::registry::instance().set_sync_mode();
			g_spdloglib_error_manager.free();
			return true;
		}
		return false;
	}



	// Ther is a rule for all filebased sinks: they should never point to the same file!
	// So all this functions look for a existing sink with the same name before a new one is created.
	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateFileSink(const spdlog::filename_char_t* file_name, bool force_flush, bool MultiThreaded)
	{
		CBevlFnConverter fnc(file_name);
		
		spdlog::log_handle_t ret_val = NULL;
		try
		{
			ret_val = sink_handle_factory::create_simple_file_sink(fnc, force_flush, MultiThreaded);
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}

		return ret_val;

	}


	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateRotatingFileSink(const spdlog::filename_char_t* FileName, const spdlog::filename_char_t* FileExt, size_t max_file_size, size_t max_files,  bool MultiThreaded)
	{
		CBevlFnConverter fnc(FileName);
		CBevlFnConverter fnx(FileExt);

		spdlog::log_handle_t ret_val = NULL;
		try
		{
			ret_val = sink_handle_factory::create_rotating_file_sink(fnc, fnx,  MultiThreaded, max_file_size, max_files);
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}

		return ret_val;
//		return sink_handle_factory::create_rotating_file_sink(fnc, fnx, force_flush, MultiThreaded, max_file_size, max_files);
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateDailyFileSink(const spdlog::filename_char_t* FileName, const spdlog::filename_char_t* FileExt, int rotation_hour, int rotation_minute, bool MultiThreaded)
	{
		CBevlFnConverter fnc(FileName);
		CBevlFnConverter fnx(FileExt);
		try
		{
			return sink_handle_factory::create_daily_file_sink(fnc, fnx, rotation_hour, rotation_minute,  MultiThreaded);
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return NULL;
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateMsvcSink(bool MultiThreaded)
	{
		try
		{
			return sink_handle_factory::create_msvc_sink(MultiThreaded);
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return NULL;
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateStdoutSink(bool MultiThreaded, bool UseColor)
	{
		try
		{
			return sink_handle_factory::create_stdout_sink(MultiThreaded, UseColor);
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return NULL;
//		return sink_handle_factory::create_stdout_sink(MultiThreaded, UseColor);
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateStderrSink(bool MultiThreaded, bool UseColor)
	{
		try
		{
			return sink_handle_factory::create_stderr_sink(MultiThreaded, UseColor);
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return NULL;
//		return sink_handle_factory::create_stderr_sink(MultiThreaded, UseColor);
	}


	// The sink handle is only required to make the calls to "SpdLog_CreateLogger". After you have created
	// your logger, you may call SpdLog_FreeSink to free your reference to the sink. Sinks taken by created loggers
	// get freed at the point when the logger is destroyed itself, completely behind your back. 
	SPDLOGLB_API bool SpdLog_FreeSink(spdlog::log_handle_t hSink)
	{
		return sink_handle_factory::free_sink(hSink);
	}


	// Creates a logger. 
	// Need 1-n output sinks that get created before with the appropriate functions
	// LoggerName has to be a unique name for each logger.
	// FormatString is the base format for each log entry, decorating it with timestamps ...
	// log_level is the current level from BevlLogLevel_trace to BevlLogLevel_off, all messages with lower LogLEvels are thrown away.
	// LogBitMask is the mask to filter out message classes in functions that uses a bit flag to indicate the message class
	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateLogger(spdlog::log_handle_t* lpSinks, const unsigned long nSinks, const char* LoggerName, const spdlog::log_char_t* FormatString, unsigned long log_level, unsigned long LogBitMask)
	{
		try
		{
			logger_handle* lph = logger_handle_factory::create_logger_p(lpSinks, nSinks, LoggerName);
			if (lph)
			{
				lph->set_level(CBevlLogLevelConverter(log_level));
				lph->set_pattern(CBevlFormatstringConverter(FormatString));
#ifdef SPDLOG_BITMASK_LOG_FILTER
				lph->set_enable_bit_mask(LogBitMask);
#endif
				return lph->GetHandle();
			}
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}

		return nullptr;

	}

	// Finds a existing logger. The logger list is valid for the complete process, so a logger may be used by more than one module at a time.
	// In this case it is best to query first for the logger using this function, because it is not possible to create two loggers
	// with the same name.
	SPDLOGLB_API spdlog::log_handle_t SpdLog_GetLogger(const char* LoggerName)
	{
		return logger_handle_factory::get_logger(LoggerName);
	}

	SPDLOGLB_API bool SpdLog_DeleteLogger(spdlog::log_handle_t hLogger)
	{
		return logger_handle_factory::delete_logger(hLogger);
	}

	SPDLOGLB_API bool SpdLog_IsValidLoggerHandle(spdlog::log_handle_t hLogger)
	{
		return logger_handle_factory::validate_logger_handle(hLogger);
	}


	// Sets the basic log output pattern. It is a format string according to https://github.com/gabime/spdlog/wiki/3.-Custom-formatting.
	// Use this format string to do the base setup for the log output lines.
	// Attention: if called with hLogger == NULL, it resets the fomat pattern of all existing Loggers!
	SPDLOGLB_API bool SpdLog_SetLoggerFormatPattern(spdlog::log_handle_t hLogger, spdlog::fmt_formatchar_t* lpPattern)
	{
		return logger_handle_factory::set_logger_format_pattern(hLogger, lpPattern);
	}

	SPDLOGLB_API bool SpdLog_SetLoggerLevel(spdlog::log_handle_t hLogger, unsigned long log_level)
	{
		return logger_handle_factory::set_level(hLogger, CBevlLogLevelConverter(log_level));
	}

	SPDLOGLB_API bool SpdLog_SetLoggerBitMask(spdlog::log_handle_t hLogger, unsigned long BitMask)
	{

#ifdef SPDLOG_BITMASK_LOG_FILTER
		return logger_handle_factory::set_logger_enable_bitmask(hLogger, BitMask);
#else
		return false;
#endif
	}

	// Flushes the log if a message that matches the LogLEvel was loggt. 
	SPDLOGLB_API bool SpdLog_SetLoggerAutomaticFlush(spdlog::log_handle_t hLogger, unsigned long log_level)
	{
		return logger_handle_factory::set_logger_automatic_flush(hLogger, CBevlLogLevelConverter(log_level));
	}

	// Flushes the log file (to disk ...)
	SPDLOGLB_API bool SpdLog_LoggerFlush(spdlog::log_handle_t hLogger)
	{
		return logger_handle_factory::logger_flush(hLogger);
	}

	SPDLOGLB_API unsigned long SpdLog_GetLoggerLevel(spdlog::log_handle_t hLogger)
	{
		return logger_handle_factory::get_level(hLogger);
	}

	SPDLOGLB_API unsigned long SpdLog_GetLoggerBitMask(spdlog::log_handle_t hLogger)
	{
#ifdef SPDLOG_BITMASK_LOG_FILTER
		return logger_handle_factory::get_logger_enable_bitmask(hLogger);
#else
		return 0;
#endif

	}
	SPDLOGLB_API unsigned long SpdLog_GetLoggerAutomaticFlush(spdlog::log_handle_t hLogger)
	{
		return logger_handle_factory::get_logger_automatic_flush(hLogger);
	}


	SPDLOGLB_API bool SpdLog_GetLoggerName(spdlog::log_handle_t hLogger, char* lpBuffer, unsigned long BufSize)
	{
		if (lpBuffer == NULL)
			return false;
		if (BufSize == 0)
			return false;

		std::string s;
		if (logger_handle_factory::get_logger_name(hLogger, s))
		{
			unsigned long cpLen = s.length();
			if (cpLen >= BufSize)
				cpLen = BufSize - 1;
			strncpy_s(lpBuffer,BufSize, s.data(), cpLen);
			lpBuffer[cpLen] = '\0';
			return true;
		}
		return false;
	}



	SPDLOGLB_API bool SpdLog_SetLoggerErrorHandler(spdlog::log_handle_t hLogger, log_err_handler ErrorHandler)
	{
		return logger_handle_factory::set_error_handler(hLogger, ErrorHandler);
	}


	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateSimpleFileLogger(const char* logger_name,
		const spdlog::filename_char_t* file_name,
		bool force_flush,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		try
		{
			logger_handle* lpLh = logger_handle_factory::create_simple_file_logger_p(logger_name, file_name, force_flush, MultiThreaded);
			if (lpLh == nullptr)
				return nullptr;

			if (lp_prop)
			{
				if (lp_prop->FormatString)
					lpLh->set_pattern(lp_prop->FormatString);
				lpLh->set_level(lp_prop->Level);
#ifdef SPDLOG_BITMASK_LOG_FILTER
				lpLh->set_enable_bit_mask(lp_prop->LogBitMask);
#endif
			}
			return lpLh->GetHandle();
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}

		return nullptr;
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_GetOrCreateSimpleFileLogger(const char* logger_name,
		const spdlog::filename_char_t* file_name,
		bool force_flush,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{

		spdlog::log_handle_t hExt = logger_handle_factory::get_logger(logger_name);
		if (hExt != nullptr)
			return hExt;

		return SpdLog_CreateSimpleFileLogger(logger_name, file_name, force_flush, MultiThreaded, lp_prop);

	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateRotatingFileLogger(const char* logger_name,
		const spdlog::filename_char_t* file_name,
		const spdlog::filename_char_t* file_ext,
		size_t max_file_size,
		size_t max_files,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{

		try
		{
			logger_handle* lpLh = logger_handle_factory::create_rotating_file_logger_p(logger_name, file_name, file_ext, max_file_size, max_files, MultiThreaded);
			if (lpLh == nullptr)
				return nullptr;

			if (lp_prop)
			{
				lpLh->set_level(lp_prop->Level);
				if (lp_prop->FormatString)
					lpLh->set_pattern(lp_prop->FormatString);
#ifdef SPDLOG_BITMASK_LOG_FILTER
				lpLh->set_enable_bit_mask(lp_prop->LogBitMask);
#endif
			}
			return lpLh->GetHandle();
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return nullptr;
	}

	// Creates a rotating logfile restricted in file size and number of renamed files
	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateOrGetRotatingFileLogger(const char* logger_name,
		const spdlog::filename_char_t* file_name,
		const spdlog::filename_char_t* file_ext,
		size_t max_file_size,
		size_t max_files,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		spdlog::log_handle_t hExt = logger_handle_factory::get_logger(logger_name);
		if (hExt != nullptr)
			return hExt;

		return SpdLog_CreateRotatingFileLogger(logger_name, file_name, file_ext, max_file_size, max_files, MultiThreaded, lp_prop);

	}

	// Creates a logfile that switch over to another file after a specified time.
	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateDaylyFileLogger(const char* logger_name,
		const spdlog::filename_char_t* file_name,
		const spdlog::filename_char_t* file_ext,
		int rotation_hour,
		int rotation_minute,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		try
		{
			logger_handle* lpLh = logger_handle_factory::create_dayly_file_logger_p(logger_name, file_name, file_ext, rotation_hour, rotation_minute, MultiThreaded);
			if (lpLh == NULL)
				return nullptr;

			if (lp_prop)
			{
				lpLh->set_level(lp_prop->Level);
				if (lp_prop->FormatString)
					lpLh->set_pattern(lp_prop->FormatString);
#ifdef SPDLOG_BITMASK_LOG_FILTER
				lpLh->set_enable_bit_mask(lp_prop->LogBitMask);
#endif
			}
			return lpLh->GetHandle();
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return nullptr;
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_GetOrCreateDaylyFileLogger(const char* logger_name,
		const spdlog::filename_char_t* file_name,
		const spdlog::filename_char_t* file_ext,
		int rotation_hour,
		int rotation_minute,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		spdlog::log_handle_t hExt = logger_handle_factory::get_logger(logger_name);
		if (hExt != nullptr)
			return hExt;

		return SpdLog_CreateDaylyFileLogger(logger_name, file_name, file_ext, rotation_hour, rotation_minute, MultiThreaded, lp_prop);

	}


	// Logger for Microsoft Visual Studio (OutputDebugString)
	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateMsvcLogger(const char* logger_name,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{

		try
		{
			logger_handle* lpLh = logger_handle_factory::create_msvc_logger_p(logger_name, MultiThreaded);

			if (lpLh == NULL)
				return nullptr;

			if (lp_prop)
			{
				lpLh->set_level(lp_prop->Level);
				if (lp_prop->FormatString)
					lpLh->set_pattern(lp_prop->FormatString);
#ifdef SPDLOG_BITMASK_LOG_FILTER
				lpLh->set_enable_bit_mask(lp_prop->LogBitMask);
#endif
			}
			return lpLh->GetHandle();
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return nullptr;
	}


	SPDLOGLB_API spdlog::log_handle_t SpdLog_GetOrCreateMsvcLogger(const char* logger_name,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		spdlog::log_handle_t hExt = logger_handle_factory::get_logger(logger_name);
		if (hExt != nullptr)
			return hExt;

		return SpdLog_CreateMsvcLogger(logger_name, MultiThreaded, lp_prop);

	}


	// Logger mit Ausgabe nach stdout (console)
	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateStdoutLogger(const char* logger_name,
		bool use_color,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{

		try
		{
			logger_handle* lpLh = logger_handle_factory::create_stdout_logger_p(logger_name, use_color, MultiThreaded);

			if (lpLh == NULL)
				return nullptr;

			if (lp_prop)
			{
				lpLh->set_level(lp_prop->Level);
				if (lp_prop->FormatString)
					lpLh->set_pattern(lp_prop->FormatString);
#ifdef SPDLOG_BITMASK_LOG_FILTER
				lpLh->set_enable_bit_mask(lp_prop->LogBitMask);
#endif
			}
			return lpLh->GetHandle();
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return nullptr;
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_GetOrCreateStdoutLogger(const char* logger_name,
		bool use_color,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{

		spdlog::log_handle_t hExt = logger_handle_factory::get_logger(logger_name);
		if (hExt != nullptr)
			return hExt;

		return SpdLog_CreateStdoutLogger(logger_name, use_color, MultiThreaded, lp_prop);

	}


	// Logger mit Ausgabe nach stderr (console)
	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateStderrLogger(const char* logger_name,
		bool use_color,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		try
		{
			logger_handle* lpLh = logger_handle_factory::create_stderr_logger_p(logger_name, use_color, MultiThreaded);

			if (lpLh == NULL)
				return nullptr;

			if (lp_prop)
			{
				lpLh->set_level(lp_prop->Level);
				if (lp_prop->FormatString)
					lpLh->set_pattern(lp_prop->FormatString);
#ifdef SPDLOG_BITMASK_LOG_FILTER
				lpLh->set_enable_bit_mask(lp_prop->LogBitMask);
#endif
			}
			return lpLh->GetHandle();
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return nullptr;
	}

	SPDLOGLB_API spdlog::log_handle_t SpdLog_GetOrCreateStderrLogger(const char* logger_name,
		bool use_color,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{

		spdlog::log_handle_t hExt = logger_handle_factory::get_logger(logger_name);
		if (hExt != nullptr)
			return hExt;

		return SpdLog_CreateStderrLogger(logger_name, use_color, MultiThreaded, lp_prop);

	}



	// The log functions has the following common parameters:
	// log_level: is a value from BevlLogLevelEnum. If this value is lower than the loggers loglevel, the message is filtered out.
	// log_bit_flag: this value is compared to the mask from the logger and filtered out if the bit is not set.

	SPDLOGLB_API bool SpdLog_LogBf(spdlog::log_handle_t hLogger, unsigned long log_level, unsigned long log_bit_flag, const spdlog::log_char_t* log_string)
	{
#ifdef SPDLOG_BITMASK_LOG_FILTER
		// Direct cast to the enum
		return logger_handle_factory::log_bf(hLogger, spdlog::level::level_enum(log_level), log_bit_flag, log_string);

		return false;
#else
		return false;
#endif
	}

	SPDLOGLB_API bool SpdLog_LogBfo(spdlog::log_handle_t hLogger, unsigned long log_bit_flag, const spdlog::log_char_t* log_string)
	{
#ifdef SPDLOG_BITMASK_LOG_FILTER
		return logger_handle_factory::log_bfo(hLogger, log_bit_flag, log_string);

#else
		return false;
#endif
	}

	SPDLOGLB_API bool SpdLog_Log(spdlog::log_handle_t hLogger, unsigned long log_level, const spdlog::log_char_t* log_string)
	{
		return logger_handle_factory::log(hLogger, spdlog::level::level_enum(log_level), log_string);
	}




	// Formats the log output using printf format style. It uses the original printf functions, is not type safe and does
	// not use the format library of Victor Zvervovich, althogh it does supports printf style formating. To use this,
	// there are functions in "SpdLog_VarArg" that provide a way to handle variable parameter list in a typesafe way.
	
	
	SPDLOGLB_API bool SpdLog_LogPrintf(spdlog::log_handle_t hLogger, unsigned long log_level, const spdlog::log_char_t* log_string, ...)
	{
		va_list args;
		va_start(args, log_string);
		return SpdLog_vLogPrintf(hLogger, log_level, log_string, args);
	}

	SPDLOGLB_API bool SpdLog_vLogPrintf(spdlog::log_handle_t hLogger, unsigned long log_level, const spdlog::log_char_t* log_string, va_list args)
	{

		const unsigned long BUF_SIZE = 1024;

		spdlog::log_char_t Buffer[BUF_SIZE];

#ifdef SPDLOG_WCHAR_LOGGING
		_vsnwprintf_s(Buffer, BUF_SIZE, log_string, args);
#else
		_vsnprintf_s(Buffer, BUF_SIZE, log_string, args);
#endif
		return logger_handle_factory::log(hLogger, spdlog::level::level_enum(log_level), Buffer);
	}

	SPDLOGLB_API bool SpdLog_LogPrintfBf(spdlog::log_handle_t hLogger, unsigned long log_level, unsigned long log_bit_flag, const spdlog::log_char_t* log_string, ...)
	{
#ifdef SPDLOG_BITMASK_LOG_FILTER

		va_list args;
		va_start(args, log_string);
		return SpdLog_vLogPrintfBf(hLogger, log_level, log_bit_flag, log_string, args);

#else
		return false;
#endif // SPDLOG_BITMASK_LOG_FILTER

	}

	SPDLOGLB_API bool SpdLog_vLogPrintfBf(spdlog::log_handle_t hLogger, unsigned long log_level, unsigned long log_bit_flag, const spdlog::log_char_t* log_string, va_list args)
	{

#ifdef SPDLOG_BITMASK_LOG_FILTER
		const unsigned long BUF_SIZE = 1024;

		spdlog::log_char_t Buffer[BUF_SIZE+1];

#ifdef SPDLOG_WCHAR_LOGGING
		_vsnwprintf_s(Buffer, BUF_SIZE,_TRUNCATE, log_string, args);
#else
		_vsnprintf_s(Buffer, BUF_SIZE, _TRUNCATE, log_string, args);
#endif
		return logger_handle_factory::log_bf(hLogger, spdlog::level::level_enum(log_level), log_bit_flag, Buffer);
#else   // SPDLOG_BITMASK_LOG_FILTER
		return false;
#endif	// SPDLOG_BITMASK_LOG_FILTER
	}

	
	
	SPDLOGLB_API bool SpdLog_LogPrintfBfo(spdlog::log_handle_t hLogger, unsigned long log_bit_flag, const spdlog::log_char_t* log_string, ...)
	{
#ifdef SPDLOG_BITMASK_LOG_FILTER
		va_list args;
		va_start(args, log_string);
		return SpdLog_vLogPrintfBfo(hLogger, log_bit_flag, log_string, args);
#else
		return false;
#endif
	}

	SPDLOGLB_API bool SpdLog_vLogPrintfBfo(spdlog::log_handle_t hLogger, unsigned long log_bit_flag, const spdlog::log_char_t* log_string, va_list args)
	{

#ifdef SPDLOG_BITMASK_LOG_FILTER

		const unsigned long BUF_SIZE = 1024;
		spdlog::log_char_t Buffer[BUF_SIZE];

#ifdef SPDLOG_WCHAR_LOGGING
		_vsnwprintf_s(Buffer, BUF_SIZE, _TRUNCATE, log_string, args);
#else
		_vsnprintf_s(Buffer, BUF_SIZE, _TRUNCATE, log_string, args);
#endif
		return logger_handle_factory::log_bfo(hLogger, log_bit_flag, Buffer);
#else   // SPDLOG_BITMASK_LOG_FILTER
		return false;
#endif	// SPDLOG_BITMASK_LOG_FILTER

	}

	SPDLOGLB_API bool SpdLog_LogFormat(spdlog::log_handle_t hLogger, unsigned long log_level, const spdlog::log_char_t* log_string, vararg_list& args)
	{
		return logger_handle_factory::log_format(hLogger, spdlog::level::level_enum(log_level), log_string, args);
	}

	SPDLOGLB_API bool SpdLog_LogFormatBf(spdlog::log_handle_t hLogger, unsigned long log_level, unsigned long log_bit_flag, const spdlog::log_char_t*  log_string, vararg_list& args)
	{
#ifdef SPDLOG_BITMASK_LOG_FILTER
		return logger_handle_factory::log_format_bf(hLogger, spdlog::level::level_enum(log_level), log_bit_flag, log_string, args);
#else
		return false;
#endif

	}

	SPDLOGLB_API bool SpdLog_LogFormatBfo(spdlog::log_handle_t hLogger, unsigned long log_bit_flag, const spdlog::log_char_t*  log_string, vararg_list& args)
	{
#ifdef SPDLOG_BITMASK_LOG_FILTER
		return logger_handle_factory::log_format_bfo(hLogger, log_bit_flag, log_string, args);
#else
		return false;
#endif

	}


	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateOstreamSink(spdlog::std_ostream_t& os, bool force_flush, bool MultiThreaded)
	{
		try
		{
			return spdlog::sink_handle_factory::create_ostream_sink(os, MultiThreaded, force_flush);
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return nullptr;
	}


	SPDLOGLB_API spdlog::log_handle_t SpdLog_CreateOstreamLogger(const char* logger_name,
		spdlog::std_ostream_t& os,
		bool force_flush,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		try
		{
			spdlog::logger_handle* lpLh = logger_handle_factory::create_ostream_logger_p(logger_name, os, force_flush, MultiThreaded);
			if (lpLh)
			{
				if (lp_prop)
				{
					lpLh->set_pattern(lp_prop->FormatString);
					lpLh->set_level(lp_prop->Level);
#ifdef SPDLOG_BITMASK_LOG_FILTER
					lpLh->set_enable_bit_mask(lp_prop->LogBitMask);
#endif
				}
				return lpLh->GetHandle();
			}
			return nullptr;
		}
		catch (const std::exception &ex)
		{
			g_spdloglib_error_manager.on_error(ex.what());
		}
		catch (...)
		{
			g_spdloglib_error_manager.on_error("Unknown exception");
		}
		return nullptr;
	}


	SPDLOGLB_API spdlog::log_handle_t SpdLog_GetOrCreateOstreamLogger(const char* logger_name,
		spdlog::std_ostream_t& os,
		bool force_flush,
		bool MultiThreaded,
		SPDLOGLB_CREATELOGGER_PARAM* lp_prop)
	{
		spdlog::log_handle_t hExt = logger_handle_factory::get_logger(logger_name);
		if (hExt != nullptr)
			return hExt;

		return SpdLog_CreateOstreamLogger(logger_name, os, force_flush, MultiThreaded, lp_prop);
	}



	// Have trouble to make it compile using the current buildin format library. Works with tester of the current format
	// library. Cancelled at the moment.
	//// The same way, just with the printf style format syntax of the format library.
	//// Attention: the format specifiers are not neccessarily the same that you know from "printf", look into the doku 
	//// of the format library. For example, "%S" for a string of the opposite character format (char/wchar) is not supported.
	//SPDLOGLB_API bool SpdLog_LogFormatPrintf(spdlog::log_handle_t hLogger, unsigned long log_level, spdlog::log_char_t* log_string, vararg_list& args);
	//SPDLOGLB_API bool SpdLog_LogFormatPrintfBf(spdlog::log_handle_t hLogger, unsigned long log_level, unsigned long log_bit_flag, spdlog::log_char_t* log_string, vararg_list& args);
	//SPDLOGLB_API bool SpdLog_LogFormatPrintfBfo(spdlog::log_handle_t hLogger, unsigned long log_bit_flag, spdlog::log_char_t* log_string, vararg_list& args);


} // namespace spdlog




