#include <stdlib.h>

#include "core_runtime_private.h"

#define COM_ERROR_FATAL 0
#define COM_ERROR_DROP 1
#define COM_FREEZE_EXPECTED_ARGC 2
#define COM_FREEZE_SECONDS_ARG 1
#define COM_MILLISECONDS_TO_SECONDS 0.001
#define COM_CRASH_TEST_PATTERN 0x12345678
#define COM_FS_RESTART_CLEAR_LOOKUPS 1

int32_t Cmd_Argc(void);
const char *Cmd_Argv(uint32_t arg);
void SV_Shutdown(const char *finalmsg);
void Hunk_Clear(void);
void Com_Close(void);
void FS_Shutdown(qboolean clearLookupLists);
void FS_ShutdownServerReferencedPaks(void);
void FS_ShutdownServerPakNames(void);
void Sys_Quit(void);

void Com_Quit_f(void)
{
    if (com_errorEntered == 0) {
        Com_ClearTempMemory();
        Com_ClearServerFrameRunningFlag();
        SV_Shutdown("EXE_SERVERQUIT");
        Hunk_Clear();
        Com_Close();
        FS_Shutdown(COM_FS_RESTART_CLEAR_LOOKUPS);
        FS_ShutdownServerReferencedPaks();
        FS_ShutdownServerPakNames();
    }

    Sys_Quit();
}

void Com_Error_f(void)
{
    if (Cmd_Argc() <= 1) {
        Com_Error(COM_ERROR_FATAL, "\x15" "Testing fatal error");
    } else {
        Com_Error(COM_ERROR_DROP, "\x15" "Testing drop error");
    }
}

void Com_Freeze_f(void)
{
    float seconds;
    int start;
    int now;

    if (Cmd_Argc() != COM_FREEZE_EXPECTED_ARGC) {
        Com_Printf("freeze <seconds>\n");
        return;
    }

    seconds = (float)atof(Cmd_Argv(COM_FREEZE_SECONDS_ARG));
    start = Com_Milliseconds();
    /* ORIGINAL_BINARY_BUG: the stock ordered-greater exit test loops forever
     * for NaN; preserved per original-bugs/coduomp-freeze-nan-infinite-loop.md. */
    do {
        now = Com_Milliseconds();
    } while (!((double)(now - start) * COM_MILLISECONDS_TO_SECONDS >
               (double)seconds));
}

void Com_Crash_f(void)
{
    volatile uint32_t *nullWord = (volatile uint32_t *)0;

    *nullWord = COM_CRASH_TEST_PATTERN;
}
