#ifndef G_SYSCALLS_H
#define G_SYSCALLS_H

#include "recovered_game.h"

typedef intptr_t (*game_syscall_t)(intptr_t command, ...);

extern game_syscall_t g_syscall;

struct coduo_sound_alias_s;
struct vmCvar_s;

typedef enum game_syscall_id_e {
    SYSCALL_PRINTF = 0,
    SYSCALL_ERROR = 1,
    SYSCALL_ERROR_LOCALIZED = 2,
    SYSCALL_MILLISECONDS = 3,
    SYSCALL_CVAR_REGISTER = 4,
    SYSCALL_CVAR_UPDATE = 5,
    SYSCALL_CVAR_SET = 6,
    SYSCALL_CVAR_VARIABLE_INTEGER_VALUE = 7,
    SYSCALL_CVAR_VARIABLE_VALUE = 8,
    SYSCALL_CVAR_VARIABLE_STRING_BUFFER = 9,
    SYSCALL_ARGC = 10,
    SYSCALL_ARGV = 11,
    SYSCALL_HUNK_ALLOC = 12,
    SYSCALL_HUNK_ALLOC_LOW = 13,
    SYSCALL_HUNK_ALLOC_ALIGN = 14,
    SYSCALL_HUNK_ALLOC_LOW_ALIGN = 15,
    SYSCALL_HUNK_ALLOC_TEMP = 16,
    SYSCALL_HUNK_FREE_TEMP = 17,
    SYSCALL_FS_FOPEN_FILE = 18,
    SYSCALL_FS_READ = 19,
    SYSCALL_FS_WRITE = 20,
    SYSCALL_FS_RENAME = 21,
    SYSCALL_FS_FCLOSE_FILE = 22,
    SYSCALL_SEND_CONSOLE_COMMAND = 23,
    SYSCALL_LOCATE_GAME_DATA = 24,
    SYSCALL_GET_GUID = 25,
    SYSCALL_DROP_CLIENT = 26,
    SYSCALL_SEND_SERVER_COMMAND = 27,
    SYSCALL_SET_CONFIGSTRING = 28,
    SYSCALL_GET_CONFIGSTRING = 29,
    SYSCALL_GET_CONFIGSTRING_CONST = 30,
    SYSCALL_IS_LOCAL_CLIENT = 31,
    SYSCALL_GET_CLIENT_PING = 32,
    SYSCALL_GET_USERINFO = 33,
    SYSCALL_SET_USERINFO = 34,
    SYSCALL_GET_SERVERINFO = 35,
    SYSCALL_SET_BRUSH_MODEL = 36,
    SYSCALL_TRACE = 37,
    SYSCALL_TRACE_CAPSULE = 38,
    SYSCALL_SIGHT_TRACE = 39,
    SYSCALL_SIGHT_TRACE_CAPSULE = 40,
    SYSCALL_SIGHT_TRACE_TO_ENTITY = 41,
    SYSCALL_CM_BOX_TRACE = 42,
    SYSCALL_CM_CAPSULE_TRACE = 43,
    SYSCALL_CM_BOX_SIGHT_TRACE = 44,
    SYSCALL_CM_CAPSULE_SIGHT_TRACE = 45,
    SYSCALL_LOCATIONAL_TRACE = 46,
    SYSCALL_POINT_CONTENTS = 47,
    SYSCALL_IN_PVS = 48,
    SYSCALL_IN_PVS_IGNORE_PORTALS = 49,
    SYSCALL_IN_SNAPSHOT = 50,
    SYSCALL_ADJUST_AREA_PORTAL_STATE = 51,
    SYSCALL_AREAS_CONNECTED = 52,
    SYSCALL_LINK_ENTITY = 53,
    SYSCALL_UNLINK_ENTITY = 54,
    SYSCALL_ENTITIES_IN_BOX = 55,
    SYSCALL_ENTITY_CONTACT = 56,
    SYSCALL_GET_USERCMD = 57,
    SYSCALL_GET_ENTITY_TOKEN = 58,
    SYSCALL_FS_GET_FILE_LIST = 59,
    SYSCALL_MAP_EXISTS = 60,
    SYSCALL_REAL_TIME = 61,
    SYSCALL_SNAP_VECTOR = 62,
    SYSCALL_ENTITY_CONTACT_CAPSULE = 63,
    SYSCALL_COM_SOUND_ALIAS_STRING = 64,
    SYSCALL_COM_PICK_SOUND_ALIAS = 65,
    SYSCALL_COM_SOUND_ALIAS_INDEX = 66,
    SYSCALL_SURFACE_TYPE_FROM_NAME = 67,
    SYSCALL_SURFACE_TYPE_TO_NAME = 68,
    SYSCALL_ADD_TEST_CLIENT = 69,
    SYSCALL_GET_ARCHIVED_CLIENT_INFO = 70,
    SYSCALL_ADD_DEBUG_STRING = 71,
    SYSCALL_ADD_DEBUG_LINE = 72,
    SYSCALL_SET_ARCHIVE = 73,
    SYSCALL_Z_MALLOC = 74,
    SYSCALL_Z_FREE = 75,
    SYSCALL_XANIM_CREATE_TREE = 76,
    SYSCALL_XANIM_CREATE_SMALL_TREE = 77,
    SYSCALL_XANIM_FREE_SMALL_TREE = 78,
    SYSCALL_XMODEL_EXISTS = 79,
    SYSCALL_XMODEL_GET = 80,
    SYSCALL_DOBJ_CREATE = 81,
    SYSCALL_DOBJ_EXISTS = 82,
    SYSCALL_SAFE_DOBJ_FREE = 83,
    SYSCALL_XANIM_GET_ANIMS = 84,
    SYSCALL_XANIM_CLEAR_TREE_GOAL_WEIGHTS = 86,
    SYSCALL_XANIM_CLEAR_GOAL_WEIGHT = 87,
    SYSCALL_XANIM_CLEAR_TREE_GOAL_WEIGHTS_STRICT = 88,
    SYSCALL_XANIM_SET_COMPLETE_GOAL_WEIGHT_KNOB = 89,
    SYSCALL_XANIM_SET_COMPLETE_GOAL_WEIGHT_KNOB_ALL = 90,
    SYSCALL_XANIM_SET_ANIM_RATE = 91,
    SYSCALL_XANIM_SET_TIME = 92,
    SYSCALL_XANIM_SET_GOAL_WEIGHT_KNOB = 93,
    SYSCALL_XANIM_CLEAR_TREE = 94,
    SYSCALL_XANIM_HAS_TIME = 95,
    SYSCALL_XANIM_IS_PRIMITIVE = 96,
    SYSCALL_XANIM_GET_LENGTH = 97,
    SYSCALL_XANIM_GET_LENGTH_SECONDS = 98,
    SYSCALL_XANIM_SET_COMPLETE_GOAL_WEIGHT = 99,
    SYSCALL_XANIM_SET_GOAL_WEIGHT = 100,
    SYSCALL_XANIM_CALC_ABS_DELTA = 101,
    SYSCALL_XANIM_CALC_DELTA = 102,
    SYSCALL_XANIM_GET_REL_DELTA = 103,
    SYSCALL_XANIM_GET_ABS_DELTA = 104,
    SYSCALL_XANIM_IS_LOOPED = 105,
    SYSCALL_XANIM_NOTETRACK_EXISTS = 106,
    SYSCALL_XANIM_GET_TIME = 107,
    SYSCALL_XANIM_GET_WEIGHT = 108,
    SYSCALL_DOBJ_DUMP_INFO = 109,
    SYSCALL_DOBJ_CREATE_SKEL_FOR_BONE = 110,
    SYSCALL_DOBJ_CREATE_SKEL_FOR_BONES = 111,
    SYSCALL_DOBJ_UPDATE_SERVER_TIME = 112,
    SYSCALL_DOBJ_INIT_SERVER_TIME = 113,
    SYSCALL_DOBJ_GET_HIERARCHY_BITS = 114,
    SYSCALL_DOBJ_CALC_ANIM = 115,
    SYSCALL_DOBJ_CALC_SKEL = 116,
    SYSCALL_XANIM_LOAD_ANIM_TREE = 117,
    SYSCALL_XANIM_SAVE_ANIM_TREE = 118,
    SYSCALL_XANIM_CLONE_ANIM_TREE = 119,
    SYSCALL_DOBJ_NUM_BONES = 120,
    SYSCALL_DOBJ_GET_BONE_INDEX = 121,
    SYSCALL_DOBJ_GET_MATRIX_ARRAY = 122,
    SYSCALL_DOBJ_DISPLAY_ANIM = 123,
    SYSCALL_XANIM_HAS_FINISHED = 124,
    SYSCALL_XANIM_GET_NUM_CHILDREN = 125,
    SYSCALL_XANIM_GET_CHILD_AT = 126,
    SYSCALL_XMODEL_NUM_BONES = 127,
    SYSCALL_XMODEL_GET_BONE_NAMES = 128,
    SYSCALL_DOBJ_GET_ROT_TRANS_ARRAY = 129,
    SYSCALL_DOBJ_SET_ROT_TRANS_INDEX = 130,
    SYSCALL_DOBJ_SET_CONTROL_ROT_TRANS_INDEX = 131,
    SYSCALL_DOBJ_GET_BOUNDS = 132,
    SYSCALL_XANIM_GET_ANIM_NAME = 133,
    SYSCALL_DOBJ_GET_TREE = 134,
    SYSCALL_XANIM_GET_ANIM_TREE_SIZE = 135,
    SYSCALL_XMODEL_DEBUG_BOXES = 136,
    SYSCALL_GET_WEAPON_INFO_MEMORY = 137,
    SYSCALL_FREE_WEAPON_INFO_MEMORY = 138,
    SYSCALL_FREE_CLIENT_SCRIPT_PERS = 139,
    SYSCALL_RESET_ENTITY_PARSE_POINT = 140
} game_syscall_id_t;

typedef struct qtime_s {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
} qtime_t;

/*
 * System call prototypes for engine interface.
 * These functions are provided by the engine via syscall table.
 */

/* Error handling */
extern void trap_Printf(const char *message);
extern void trap_Error(const char *message);
extern void trap_Error_Localized(const char *message);

/* Trace/Physics */
extern void trap_Trace(struct trace_s *trace, const float *start, const float *mins,
                       const float *maxs, const float *end, int passEntityNum,
                       int contentMask);
extern void trap_TraceCapsule(struct trace_s *trace, const float *start, const float *mins,
                              const float *maxs, const float *end, int passEntityNum,
                              int contentMask);
extern void trap_SightTrace(int32_t *traceResult, const float *start, const float *mins,
                            const float *maxs, const float *end, int passEntityNum,
                            int passOwnerNum, int contentMask);
extern void trap_SightTraceCapsule(int32_t *traceResult, const float *start, const float *mins,
                                   const float *maxs, const float *end,
                                   int passEntityNum, int passOwnerNum,
                                   int contentMask);
extern void trap_CM_BoxTrace(struct trace_s *trace, const float *start, const float *end,
                             const float *mins, const float *maxs, int model,
                             int brushMask);
extern void trap_CM_CapsuleTrace(struct trace_s *trace, const float *start, const float *end,
                                 const float *mins, const float *maxs, int model,
                                 int brushMask);
extern int trap_CM_BoxSightTrace(const float *start, const float *end,
                                 const float *mins, const float *maxs,
                                 int model, int brushMask);
extern int trap_CM_CapsuleSightTrace(const float *start, const float *end,
                                     const float *mins, const float *maxs,
                                     int model, int brushMask);
extern void trap_LocationalTrace(struct trace_s *trace, const float *start, const float *end,
                                 int passEntityNum, int contentMask,
                                 const void *priorityMap);
extern int trap_PointContents(const float *point, int passEntityNum, int contentMask);
extern qboolean trap_InPVS(const float *p1, const float *p2);
extern qboolean trap_InPVSIgnorePortals(const float *p1, const float *p2);
extern int trap_InSnapshot(const float *origin, int entityNum);
extern void trap_AdjustAreaPortalState(gentity_t *ent, qboolean open);
extern qboolean trap_AreasConnected(int area1, int area2);
extern int trap_EntitiesInBox(const float *mins, const float *maxs,
                              int *entityList, int maxcount, int contentMask);
extern int trap_SightTraceToEntity(const float *start, const float *mins,
                                   const float *maxs, const float *end,
                                   int entityNum, int contentMask);
extern qboolean trap_EntityContact(const float *mins, const float *maxs, gentity_t *ent);
extern qboolean trap_EntityContactCapsule(const float *mins, const float *maxs, gentity_t *ent);

/* Entity Management */
extern void trap_LinkEntity(gentity_t *ent);
extern void trap_UnlinkEntity(gentity_t *ent);
extern void trap_DObjCreate(DObjModel *models, uint16_t modelCount,
                            XAnimTree *tree, int entityNum, uint16_t gameId);
extern qboolean trap_DObjExists(gentity_t *ent);
extern void trap_SafeDObjFree(int entityNum, qboolean freeAll);
extern int trap_DObjNumBones(gentity_t *ent);
extern int trap_DObjGetBoneIndex(gentity_t *ent, const char *tagName);
extern float *trap_DObjGetMatrixArray(gentity_t *ent);
extern void trap_DObjDumpInfo(gentity_t *ent);
extern qboolean trap_DObjCreateSkelForBone(gentity_t *ent, int boneIndex);
extern qboolean trap_DObjCreateSkelForBones(gentity_t *ent, uint32_t *partBits);
extern int trap_DObjUpdateServerTime(gentity_t *ent, float serverTime,
                                     qboolean notify);
extern void trap_DObjDisplayAnim(gentity_t *ent);
extern void trap_DObjInitServerTime(gentity_t *ent, float serverTime);
extern void trap_DObjGetHierarchyBits(gentity_t *ent, int boneIndex,
                                      uint32_t *partBits);
extern void trap_DObjCalcAnim(gentity_t *ent, uint32_t *partBits);
extern void trap_DObjCalcSkel(gentity_t *ent, uint32_t *partBits);
extern DObjAnimMat *trap_DObjGetRotTransArray(gentity_t *ent);
extern qboolean trap_DObjSetRotTransIndex(gentity_t *ent, uint32_t *partBits,
                                          int boneIndex);
extern qboolean trap_DObjSetControlRotTransIndex(gentity_t *ent,
                                                 uint32_t *partBits,
                                                 int boneIndex);
extern void trap_DObjGetBounds(gentity_t *ent, vec3_t mins, vec3_t maxs);
extern XAnimTree *trap_DObjGetTree(gentity_t *ent);
extern qboolean trap_XModelExists(const char *modelName);
extern XModel *trap_XModelGet(const char *modelName);
extern int trap_XModelNumBones(XModel *model);
extern const uint16_t *trap_XModelGetBoneNames(XModel *model);
extern void trap_XModelDebugBoxes(gentity_t *ent);

/*
 * XAnim trap ABI notes:
 * packed animation refs remain uint32_t high/low tree-index+anim-index
 * values, while runtime tree handles use XAnimTree * so native64 does not
 * truncate engine-owned pointers that i386 carried in a single word.
 */
extern int trap_XAnimGetAnimTreeSize(XAnim *anims);
extern qboolean trap_XAnimHasTime(uint32_t anim);
extern qboolean trap_XAnimIsPrimitive(uint32_t anim);
extern const char *trap_XAnimGetAnimName(uint32_t anim);
extern int trap_XAnimGetLength(XAnim *anims, uint16_t animIndex);
extern float trap_XAnimGetLengthSeconds(uint32_t anim);
extern void trap_XAnimGetRelDelta(uint32_t anim, float *rotationDelta,
                                  float *moveDelta, float startTime, float endTime);
extern void trap_XAnimGetAbsDelta(uint32_t anim, float *rotationDelta,
                                  float *moveDelta, float time);
extern qboolean trap_XAnimIsLooped(uint32_t anim);
extern float trap_XAnimGetWeight(XAnimTree *tree, uint32_t anim);
extern float trap_XAnimGetTime(XAnimTree *tree, uint32_t anim);
extern qboolean trap_XAnimNotetrackExists(uint32_t anim, uint16_t notetrack);
extern qboolean trap_XAnimHasFinished(XAnimTree *tree, uint32_t anim);
extern int trap_XAnimGetNumChildren(uint32_t anim);
extern uint32_t *trap_XAnimGetChildAt(uint32_t *out, uint32_t anim,
                                      int childIndex);
extern XAnimTree *trap_XAnimCreateTree(XAnim *anims);
extern XAnimTree *trap_XAnimCreateSmallTree(XAnim *anims);
extern void trap_XAnimFreeSmallTree(XAnimTree *tree);
extern void trap_XAnimCloneAnimTree(XAnimTree *fromTree, XAnimTree *toTree);
extern XAnim *trap_XAnimGetAnims(XAnimTree *tree);
extern uint32_t *trap_XAnimGetRoot(uint32_t *out, XAnimTree *tree);
extern void trap_XAnimClearTreeGoalWeights(XAnimTree *tree, uint32_t anim,
                                           float blendTime);
extern void trap_XAnimClearGoalWeight(XAnimTree *tree, uint32_t anim,
                                      float blendTime);
extern void trap_XAnimClearTreeGoalWeightsStrict(XAnimTree *tree, uint32_t anim,
                                                 float blendTime);
extern void trap_XAnimSetCompleteGoalWeightKnob(XAnimTree *tree, uint32_t anim,
                                                float weight, float blendTime,
                                                float rate, uint16_t notifyName,
                                                qboolean restart);
extern void trap_XAnimSetCompleteGoalWeightKnobAll(XAnimTree *tree, uint32_t anim,
                                                   uint32_t knob, float weight,
                                                   float blendTime, float rate,
                                                   uint16_t notifyName,
                                                   qboolean restart);
extern void trap_XAnimSetAnimRate(XAnimTree *tree, uint32_t anim, float rate);
extern void trap_XAnimSetTime(XAnimTree *tree, uint32_t anim, float time);
extern void trap_XAnimSetGoalWeightKnob(XAnimTree *tree, uint32_t anim,
                                        float weight,
                                        float blendTime, float rate,
                                        uint16_t notifyName, qboolean restart);
extern void trap_XAnimClearTree(XAnimTree *tree);
extern void trap_XAnimSetCompleteGoalWeight(XAnimTree *tree, uint32_t anim,
                                            float weight, float blendTime,
                                            float rate, uint16_t notifyName,
                                            qboolean restart);
extern void trap_XAnimSetGoalWeight(XAnimTree *tree, uint32_t anim, float weight,
                                    float blendTime, float rate,
                                    uint16_t notifyName, qboolean restart);
extern void trap_XAnimCalcAbsDelta(XAnimTree *tree, uint32_t anim,
                                   float *rotationDelta, float *moveDelta);
extern void trap_XAnimCalcDelta(XAnimTree *tree, uint32_t anim,
                                float *rotationDelta, float *moveDelta,
                                int weightSelector);
extern void trap_XAnimLoadAnimTree(XAnimTree *tree);
extern void trap_XAnimSaveAnimTree(XAnimTree *tree);

/* Cvar */
extern void trap_Cvar_Register(struct vmCvar_s *cvar, const char *name,
                               const char *value, int flags);
extern void trap_Cvar_Set(const char *name, const char *value);
extern void trap_Cvar_Update(struct vmCvar_s *cvar);
extern void trap_Cvar_VariableStringBuffer(const char *name, char *buffer, int size);
extern int trap_Cvar_VariableIntegerValue(const char *name);
extern float trap_Cvar_VariableValue(const char *name);

/* Configstring */
extern void trap_GetConfigstring(int index, char *buffer, int bufferLength);
extern const char *trap_GetConfigstringConst(int index);
extern void trap_SetConfigstring(int index, const char *value);

/* Client Info */
extern void trap_GetUserinfo(int clientNum, char *buffer, int bufferSize);
extern void trap_SetUserinfo(int clientNum, const char *info);
extern void trap_GetUsercmd(int clientNum, usercmd_t *command);
extern int trap_GetArchivedClientInfo(int clientNum, int32_t *archiveTime,
                                      playerState_t *playerState,
                                      clientState_t *meta);
extern int trap_IsLocalClient(int clientNum);
extern int trap_GetGuid(int clientNum);
extern int trap_GetClientPing(int clientNum);

/* Server Commands */
extern void trap_SendServerCommand(int clientNum, int reliable, const char *command);
extern void trap_SendConsoleCommand(int executionTime, const char *text);
extern void trap_DropClient(int clientNum, const char *reason);
extern gentity_t *trap_AddTestClient(void);
extern void trap_SetArchive(qboolean enabled);

/* Filesystem */
extern int trap_FS_FOpenFile(const char *path, int *handle, int mode);
extern void trap_FS_FCloseFile(int handle);
extern void trap_FS_Read(void *buffer, int length, int handle);
extern void trap_FS_Write(const void *buffer, int length, int handle);
extern void trap_FS_Rename(const char *from, const char *to);
extern int trap_FS_GetFileList(const char *path, const char *extension,
                               char *listBuffer, int bufferSize);
extern int trap_MapExists(const char *mapName);

/* Debug */
extern void trap_AddDebugString(const float *origin, const float *color, float scale,
                                const char *text);
extern void trap_AddDebugLine(const float *start, const float *end, const float *color,
                              int depthTest, int duration);
extern int trap_SurfaceTypeFromName(const char *name);
extern const char *trap_SurfaceTypeToName(int surfaceType);

/* Sound aliases */
extern const char *trap_Com_SoundAliasString(const char *name);
extern void trap_Com_PickSoundAlias(const char *name, void *alias);
extern int trap_Com_SoundAliasIndex(
    const struct coduo_sound_alias_s *alias);

/* Command Args */
extern int trap_Argc(void);
extern void trap_Argv(int arg, char *buffer, int bufferLength);
extern qboolean trap_GetEntityToken(char *buffer, int bufferSize);

/* Misc */
extern int trap_Milliseconds(void);
extern void trap_RealTime(qtime_t *qtime);
extern void trap_SnapVector(float *vec);
extern void trap_GetServerinfo(char *buffer, int bufferSize);
extern void trap_LocateGameData(gentity_t *gEnts, int numGEntities,
                                int sizeofGEntity, playerState_t *clients,
                                int sizeofClient);
extern void trap_SetBrushModel(gentity_t *ent);
extern void trap_FreeClientScriptPers(void);
extern weaponInfo_t **trap_GetWeaponInfoMemory(int bytes, int *alreadyLoaded);
extern void trap_FreeWeaponInfoMemory(int mode);
extern void trap_ResetEntityParsePoint(void);

/* Hunk memory */
extern void *trap_Hunk_AllocInternal(size_t size);
extern void *trap_Hunk_AllocLowInternal(size_t size);
extern void *trap_Hunk_AllocAlignInternal(size_t size, int alignment);
extern void *trap_Hunk_AllocLowAlignInternal(size_t size, int alignment);
extern void *trap_Hunk_AllocateTempMemoryInternal(size_t size);
extern void trap_Hunk_FreeTempMemoryInternal(void *ptr);
extern void *trap_Z_MallocInternal(size_t size);
extern void trap_Z_FreeInternal(void *ptr);

#endif /* G_SYSCALLS_H */
