
#include "debug.h"

#include <stdio.h>   
#include <stdlib.h>  // for abort()
#include <stdarg.h>  // for variable args

#ifdef WIN32
#include <io.h>
#include <fcntl.h>
#include <Windows.h>
#endif // WIN32

#ifdef PROTO_DEBUG

static unsigned int debug_level = 0;
static FILE* debug_log = stderr;  // log to stderr by default

void SetDebugLevel(unsigned int level)
{
#if defined(WIN32) && !defined(SIMULATE)
    if (level)
    {
        if (!debug_level && ((stderr == debug_log) || (stdout == debug_log))) 
            OpenDebugWindow();
    }
    else
    {
        if (debug_level && ((stderr == debug_log) || (debug_log == stdout))) 
            CloseDebugWindow();
    }
#endif // WIN32&&!SIMULATE
    debug_level = level;
}  // end SetDebugLevel()

unsigned int GetDebugLevel()
{
    return debug_level;
}

bool OpenDebugLog(const char *path)
{
    CloseDebugLog();
    FILE* ptr = fopen(path, "w+");
    if (ptr)
    {
#if defined(WIN32) && !defined(SIMULATE)
        if (debug_level && ((debug_log == stdout) || (debug_log == stderr))) 
            CloseDebugWindow();
#endif // WIN32&&!SIMULATE
        debug_log = ptr;
        return true;
    }
    else
    {
#if defined(WIN32) && !defined(SIMULATE)
        if (debug_level && (debug_log != stdout) && (debug_log != stderr)) 
            OpenDebugWindow();
#endif // WIN32&&!SIMULATE
        debug_log = stderr;
        DMSG(0, "OpenDebugLog: Error opening debug log file: %s\n", path);
        return false;
    }
}  // end OpenDebugLog()

void CloseDebugLog()
{
    if (debug_log && (debug_log != stderr) && (debug_log != stdout))
    {
        fclose(debug_log);
#ifdef WIN32
        if (debug_level) OpenDebugWindow();
#endif // WIN32&&!SIMULATE
    }
    debug_log = stderr;
}  // end CloseDebugLog()

void TRACE(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(debug_log, format, args);
    fflush(debug_log);
    va_end(args);
}  // end TRACE();

// Display string if statement's debug level 
void DMSG(unsigned int level, const char *format, ...)
{
    if (level <= debug_level)
    {
        va_list args;
        va_start(args, format);
        vfprintf(debug_log, format, args);
        fflush(debug_log);
        va_end(args);   
    }
}  // end DMSG();

void ABORT(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(debug_log, format, args);
    fflush(debug_log);
    va_end(args); 
    abort();
}
#endif // PROTO_DEBUG

#ifdef WIN32
// Open console for displaying debug messages
static unsigned int console_reference_count = 0;
void OpenDebugWindow()
{
    // Open a console window and redirect stderr and stdout to it
    if (0 == console_reference_count)
    {
        AllocConsole();
        int hCrt = _open_osfhandle((long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
        FILE* hf = _fdopen(hCrt, "w" );
        *stdout = *hf;
        int i = setvbuf(stdout, NULL, _IONBF, 0 );
        
        hCrt = _open_osfhandle((long) GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
        hf = _fdopen(hCrt, "r" );
        *stdin = *hf;

        hCrt = _open_osfhandle((long) GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
        hf = _fdopen(hCrt, "w" );
        *stderr = *hf;
        i = setvbuf(stderr, NULL, _IONBF, 0);
    }
    console_reference_count++;
}  // end OpenDebugWindow() 

void CloseDebugWindow()
{
    if (console_reference_count > 0)
    {
        console_reference_count--;
        if (0 == console_reference_count) FreeConsole();
    }
}
#endif // WIN32
