#ifdef _WIN32
#  include <windows.h> // for OutputDebugStringA
#endif
#include "Utilities.h"
#include <stdarg.h>


static ErrorHandler s_defaultErrorHandler;
static Logger s_defaultMessageLogger;
static HeapManager s_defaultHeapManager;
static ResourceDeviceFactory s_defaultDeviceFactory;


Module g_currentModule{ false, "Main Module", &s_defaultErrorHandler, &s_defaultMessageLogger, &s_defaultHeapManager, &s_defaultDeviceFactory };


void yqDebugBreak()
{
#ifdef _WIN32
  DebugBreak();
#endif
}


void yqConsolePrintString(const char* a_string)
{
#ifdef _WIN32
  // Windows code
  OutputDebugStringA(a_string);
#else
  // ANSI C / POSIX porting code
  fputs(a_string, stderr);
  //fputs("\n", stderr);
#endif
}


void ErrorHandler::handleError(yqResult /*a_result*/, const char *a_location, const char *a_message)
{
  yqConsolePrintString(a_location);
  yqConsolePrintString("Caught an error! ");
  yqConsolePrintString(a_message);
  yqConsolePrintString("\n");
  //yqDebugBreak();
}


void Logger::logMessage(yqLogLevel /*a_logLevel*/, const char *a_location, const char *a_message)
{
  if (BT_IsDebug)
  {
    yqConsolePrintString(a_location);
    yqConsolePrintString(a_message);
    yqConsolePrintString("\n");
  }
}


void *HeapManager::malloc(size_t a_size)
{
  return ::malloc(a_size);
}


void *HeapManager::realloc(void *ptr, size_t newSize)
{
  return ::realloc(ptr, newSize);
}


void HeapManager::free(void *ptr)
{
  ::free(ptr);
}


yqResult ResourceDeviceFactory::CreateResourceDevice(const char * /*resourceID*/, uint32_t /*writerFlags*/, ResourceDevice ** /*newDevice*/)
{
  // TODO:
  yqDebugBreak();
  YQ_API_LEAVE(R_Failure, "Unimplemented");
}


void yqLogMessage(yqLogLevel a_logLevel, const char *a_location, const char* a_func, const char *a_format, ...)
{
  va_list args;
  va_start(args, a_format);
  std::string loc = a_location;
  loc += a_func;
#ifdef _WIN32
  size_t sizeRequired = size_t(_vscprintf(a_format, args) + 1);
  char* message = (char*)_alloca(sizeRequired);
  _vsnprintf(message, sizeRequired, a_format, args);
  if (g_currentModule.m_messageLogger)
    g_currentModule.m_messageLogger->logMessage(a_logLevel, loc.c_str(), message);
  _freea(message);
#else
  char* message = 0;
  if (vasprintf(&message, a_format, args) != -1)
  {
    if (g_currentModule.m_messageLogger)
      g_currentModule.m_messageLogger->logMessage(a_logLevel, loc.c_str(), message);
    free(message);
  }
#endif
  va_end(args);
}


void yqHandleError(yqResult a_result, const char *a_location, const char* a_func, const char *a_format, ...)
{
  va_list args;
  va_start(args, a_format);
  std::string loc = a_location;
  loc += a_func;
#ifdef _WIN32
  size_t sizeRequired = size_t(_vscprintf(a_format, args) + 1);
  char* message = (char*)_alloca(sizeRequired);
  _vsnprintf(message, sizeRequired, a_format, args);
  if (g_currentModule.m_errorHandler)
    g_currentModule.m_errorHandler->handleError(a_result, loc.c_str(), message);
  _freea(message);
#else
  char* message = 0;
  if (vasprintf(&message, a_format, args) != -1)
  {
    if (g_currentModule.m_errorHandler)
      g_currentModule.m_errorHandler->handleError(a_result, loc.c_str(), message);
    free(message);
  }
#endif
  va_end(args);
}


void* yqAllocateMemory(size_t a_newSize)
{
  return g_currentModule.m_heapManager->malloc(a_newSize);
}


void* yqReallocateMemory(void* a_ptr, size_t a_newSize)
{
  return g_currentModule.m_heapManager->realloc(a_ptr, a_newSize);
}


void yqFreeMemory(void* a_ptr)
{
  return g_currentModule.m_heapManager->free(a_ptr);
}



/*

extern char *StringDeepCopy(const char *string);
extern void StringFree(const char *string);
extern char* CreateFilenameHelper(const char* a_filename, const char* a_parent);

// Make a deep copy of the passed in string parameter, or return NULL if a_srcString is NULL
char *StringDeepCopy(const char *a_srcString)
{
	if (!a_srcString)
		return NULL;
	size_t strLength = strlen(a_srcString) + 1; // Add 1 to hold the nul terminator
	char* newStr = YQ_ALLOC_ARRAY(char, strLength);
	return (newStr == NULL) ? NULL : (char*)memcpy(newStr, a_srcString, strLength);
}
void StringFree(const char *a_string)
{
	if (a_string)
		YQ_FREE(a_string);
}
char* CreateFilenameHelper(const char* a_filename, const char* a_parent)
{
	if (!a_filename)
		return NULL;
	size_t neededLen = strlen(a_filename) + 1;
	if (a_parent)
		neededLen += strlen(a_parent) + 1;
	char* filename = YQ_ALLOC_ARRAY(char, neededLen);
	if (!filename)
		return NULL;
	if (a_parent)
	{
		strncpy(filename, a_parent, neededLen);
		char* file = strrchr(filename, '\\');
		if (file == NULL)
			file = filename;
		char* ext = strrchr(file, '.');
		if (ext == NULL)
			strncat(filename, "/", neededLen);
		else
			strncpy(ext, "/", neededLen - (ext - filename));
		strncat(filename, a_filename, neededLen);
	}
	else
	{
		strncpy(filename, a_filename, neededLen);
	}
	return filename;
}


*/

