#include "StackTrace.h"
#include <stdio.h>
#include <stdlib.h>


#ifdef _WIN32

#include "DbgHelp.h"
#include <WinBase.h>
#pragma comment(lib, "Dbghelp.lib")

void PrintStackTrace()
{
  HANDLE process = GetCurrentProcess();
  SymInitialize(process, NULL, TRUE);
  void* stack[60];
  unsigned short frames = CaptureStackBackTrace(0, 60, stack, NULL);
  SYMBOL_INFO *symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
  symbol->MaxNameLen = 255;
  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
  for(int i = 0; i < frames; i++)
  {
    SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
    printf("%i: %016I64LX %s - 0x%0X\n", frames - i - 1, stack[i], symbol->Name, symbol->Address);
  }
  free(symbol);
}

#else

#include <unistd.h>
#include <execinfo.h>
#include <cxxabi.h>

char* SplitStringNext(char* str, char ch)
{
  if (!str)
    return 0;
  int i = 0;
  while (str[i] && str[i] != ch)
    i++;
  if (!str[i])
    return 0;
  str[i] = 0;
  return &str[i + 1];
}

void PrintStackTrace()
{
#ifdef USE_PSTACK
  if (FILE* f = popen(std::string("pstack " + std::to_string(getpid()) + " | c++filt").c_str(), "r"))
  {
    char ch;
    while (fread(&ch, 1, 1, f) > 0)
      std::cout << ch;
    pclose(f);
  }
#else
  void *array[128];
  int size = backtrace(array, 128);
  char** messages = backtrace_symbols(array, size);
  for (int i = 0; i < size && messages != NULL; ++i)
  {
    // messages[i] looks something like this:  "./test(_ZN1DC1Ev+0x18) [0x415974]"
    char *progName  = messages[i];
    char *funcName  = SplitStringNext(progName,'(');
    char *offsetStr = SplitStringNext(funcName,'+');
    char *addrStr   = SplitStringNext(SplitStringNext(offsetStr, ')'), '[');
    char *endStr    = SplitStringNext(addrStr,']');
    fprintf(stderr, "[bt]: (%d) %s [%s] %s offset: %s \n", i, progName, addrStr, abi::__cxa_demangle(funcName, 0, 0, 0), offsetStr );
  }
  free(messages);
#endif
}


#endif


