bool ResourceCompiler::Check_File_Timestamp(std::string path)
{
	Platform* platform = Platform::Get();

	std::string input_directory	= platform->Extract_Directory(path);
	std::string input_filename	= platform->Extract_Filename(path);
	std::string output_directory= Directory_To_Output_Directory(input_directory);
	std::string output_path		= platform->Join_Path(output_directory, input_filename + ".timestamp");

	// If input file dosen't exist, we can't compile.
	if (!platform->Is_File(path.c_str()))
	{
		return false;
	}

	// If output file dosen't exist, we need to compile.
	if (!platform->Is_File(output_path.c_str()))
	{
		return true;
	}

	// Check timestamps.
	u64 input_timestamp  = StreamFactory::Get_Last_Modified(path.c_str());
	u64 output_timestamp = StreamFactory::Get_Last_Modified(output_path.c_str());

	return input_timestamp > output_timestamp;
}
bool AtlasResourceCompiler::Should_Compile()
{
	Platform* platform = Platform::Get();

	// If input dosen't exist, the wtf.
	if (!platform->Is_File(m_input_path.c_str()))
	{
		DBG_ASSERT_STR(false, "Attempt to compile non-existing resource '%s'.", m_input_path.c_str());
		return false;
	}

	// If input has been modified, compile is definitely required.
	if (Check_File_Timestamp(m_input_path))
	{
		return true;
	}

	// Read in the XML, so we can determine if there are any other dependent files.
	if (!Load_Config())
	{
		return false;
	}

	// Check dependent files.
	for (std::vector<std::string>::iterator iter = m_dependent_files.begin(); iter != m_dependent_files.end(); iter++)
	{
		std::string& path = *iter;
		if (Check_File_Timestamp(path.c_str()))
		{
			return true;
		}
	}

	return false;
}
LONG WINAPI ExceptionHandler(struct _EXCEPTION_POINTERS *exceptionInfo)
{
	Platform* platform = Platform::Get();

	std::string dump_dir  = platform->Get_Working_Dir() + "\\.crashes";
    std::string dump_path = dump_dir + "\\00000000.dmp";

    DBG_LOG("~~~~~~~~~~~~ UNHANDLED EXCEPTION OCCURRED ~~~~~~~~~~~");

    // Make sure dump file exists.
	if (!platform->Is_Directory(dump_dir.c_str()))
    {
        DBG_LOG("Attempt to create dump folder ...");
        DBG_LOG("Path: %s", dump_dir.c_str());

		if (!platform->Create_Directory(dump_dir.c_str(), true))
        {
            DBG_LOG("Failed to create dump folder. Aborting.");
            exit(0);
        }
    }

    // Find somewhere to dump the file.
    unsigned int index = 0;
    do
    {
		dump_path = dump_dir + "\\" + StringHelper::To_String(index) + ".dmp";
        index++;

	} while (platform->Is_File(dump_path.c_str()));

    // Dump the file!
    DBG_LOG("Attempt to create dump file ...");
    DBG_LOG("Path: %s", dump_path.c_str());

    HANDLE fileHandle = CreateFileA(dump_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fileHandle == NULL)
    {
        DBG_LOG("Failed to create open dump file. Aborting.");
        exit(0);
    }

    // Duuuuuuuuump.
    HANDLE process = GetCurrentProcess();

    MINIDUMP_EXCEPTION_INFORMATION exceptionParam;
    exceptionParam.ThreadId          = GetCurrentThreadId();
    exceptionParam.ExceptionPointers = exceptionInfo;
    exceptionParam.ClientPointers    = FALSE;
	
	EnterCriticalSection(&g_dbghelp_critical_section);

    BOOL result = MiniDumpWriteDump(process,
                                    GetCurrentProcessId(),
                                    fileHandle,
                                    MiniDumpNormal,
                                    exceptionInfo == NULL ? NULL : &exceptionParam,
                                    NULL,
                                    NULL);
	
	LeaveCriticalSection(&g_dbghelp_critical_section);

    // Close the dump file handle.
    CloseHandle(fileHandle);

    // Check a file was created.
    if (result == FALSE)
    {
        u32 ec = GetLastError();
        DBG_LOG("Failed to create dump file, GetLastError()=%i (%s)", ec, FormatSystemError(ec).c_str());
    }
    else
    {
        DBG_LOG("Success!");
    }

	// Dump stack trace.
	DBG_LOG("");
	DBG_LOG("Call Stack:");

	StackFrame frames[256];
	int frameCount = platform->Get_Stack_Trace(frames, 256, exceptionInfo);
	for (int i = 0; i < frameCount; i++)
	{
		StackFrame& frame = frames[i];		
		platform->Resolve_Stack_Frame_Info(frame);

		DBG_LOG("[%i] %s (%i): %s", i, frame.File, frame.Line, frame.Name); 
	}

	DBG_LOG("");

	// Bail the f**k out.
    // We use this to long jump back to the point after PlatformMain is called
    // so we can deinitialize everything.
	if (GetCurrentThreadId() == g_main_thread_id)
	{
	    DBG_LOG("Attempting recovery through longjmp ...");
		longjmp(g_error_recovery_longjmp, 1);
	}

    return EXCEPTION_EXECUTE_HANDLER;
}