#include <Windows.h>
#include <DbgHelp.h>

#include "dump.h"

int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers) {
  typedef BOOL(WINAPI * MiniDumpWriteDumpT)(
    HANDLE,
    DWORD,
    HANDLE,
    MINIDUMP_TYPE,
    PMINIDUMP_EXCEPTION_INFORMATION,
    PMINIDUMP_USER_STREAM_INFORMATION,
    PMINIDUMP_CALLBACK_INFORMATION
    );
 
  MiniDumpWriteDumpT pfnMiniDumpWriteDump = NULL;
  HMODULE hDbgHelp = LoadLibrary(L"dbghelp.dll");
  if (NULL == hDbgHelp) {
    return EXCEPTION_CONTINUE_EXECUTION;
  }
 
  pfnMiniDumpWriteDump = (MiniDumpWriteDumpT)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
  if (NULL == pfnMiniDumpWriteDump) {
    FreeLibrary(hDbgHelp);
    return EXCEPTION_CONTINUE_EXECUTION;
  }

  TCHAR szFileName[MAX_PATH] = { 0 };
  //TCHAR* szVersion = SOFTWARE_VERSION;

  // convert flutter version chat to tchar
  TCHAR szVersion[MAX_PATH] = { 0 };
  const char* pszMultiByteVersion = FLUTTER_VERSION;
  int iSize = MultiByteToWideChar(CP_ACP, 0, pszMultiByteVersion , -1, NULL, 0);
  MultiByteToWideChar(CP_ACP, 0, pszMultiByteVersion, -1, szVersion, iSize);

  SYSTEMTIME stLocalTime;
  GetLocalTime(&stLocalTime);
  wsprintf(szFileName, L"%04d%02d%02d_%02d%02d%02d_%s.dmp",
    stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
    stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, szVersion);
 
  HANDLE hDumpFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
  if (INVALID_HANDLE_VALUE == hDumpFile) {
    FreeLibrary(hDbgHelp);
    return EXCEPTION_CONTINUE_EXECUTION;
  }

  MINIDUMP_EXCEPTION_INFORMATION expParam;
  expParam.ThreadId = GetCurrentThreadId();
  expParam.ExceptionPointers = pExceptionPointers;
  expParam.ClientPointers = FALSE;
  pfnMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
    hDumpFile, MiniDumpWithDataSegs, (pExceptionPointers ? &expParam : NULL), NULL, NULL);
 
  CloseHandle(hDumpFile);
  FreeLibrary(hDbgHelp);
  return EXCEPTION_EXECUTE_HANDLER;
}

LONG ApplicationCrashHandler(LPEXCEPTION_POINTERS lpExceptionInfo){
  if (IsDebuggerPresent()) {
    return EXCEPTION_CONTINUE_SEARCH;
  }  
  return GenerateMiniDump(lpExceptionInfo);
}