#ifndef CENOS_EXCEPTION_H
#define CENOS_EXCEPTION_H
#include <stdexcept>
#include <codecvt>
#include <string>
#include <thread>
#include "misc/crashReport.h"
#include <easylogging++/easylogging++.h>

class cenos_exception : public std::domain_error
{
private:
	static void write_dump()
	{
		// It is possible to pass NULL as MINIDUMP_EXCEPTION_INFORMATION* to MiniDumpWriteDump,
		// means there is no exception, just want a dump.
		std::wstring wfilename = write_dump_file(nullptr);

		// Easylogging++ accepts only UTF-8 string, not 16-bit encoded wstring.
		std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
		std::string filename = myconv.to_bytes(wfilename);
		LOG(ERROR) << (wfilename.empty() ? "Cannot write exception dump" : "Exception dump written to " + filename);
	}
public:
	cenos_exception(const std::string &message) : domain_error(message)
	{
		LOG(ERROR) << message;

		// "MiniDumpWriteDump may not produce a valid stack trace for the calling thread.
		// To work around this problem, you must capture the state of the calling thread before
		// calling MiniDumpWriteDump and use it as the ExceptionParam parameter.
		// One way to do this is to force an exception inside a __try/__except block and use
		// the EXCEPTION_POINTERS information provided by GetExceptionInformation.
		// Alternatively, you can call the function from a new worker thread and filter
		// this worker thread from the dump." -- https://docs.microsoft.com/ru-ru/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump
		// As it is not possible to use __try inside throw construction, the only solution is worker thread.
		std::thread worker(&cenos_exception::write_dump);
		worker.join();
	}
};
#endif