#ifndef CODUO_MSG_PRIVATE_H
#define CODUO_MSG_PRIVATE_H

#include "coduo_engine_structs.h"

typedef struct netField_s {
    const char *name;
    int32_t offset;
    int32_t bits;
} netField_t;

enum {
    MSG_BITMASK_TABLE_COUNT = 33,
    MSG_DELTA_ENTITY_FIELD_COUNT = 60,
    MSG_DELTA_ENTITY_BASE_FIELD_COUNT = 68,
    MSG_DELTA_CLIENT_FIELD_COUNT = 22,
    MSG_DELTA_PLAYERSTATE_FIELD_COUNT = 114
};

extern uint32_t msg_bitmaskTable[MSG_BITMASK_TABLE_COUNT];
extern netField_t msg_entityDefaultNetFields[MSG_DELTA_ENTITY_FIELD_COUNT];
extern netField_t
    msg_entityAltTrajectoryNetFields[MSG_DELTA_ENTITY_FIELD_COUNT];
extern netField_t
    msg_entityBaselineNetFields[MSG_DELTA_ENTITY_BASE_FIELD_COUNT];
extern netField_t msg_clientNetFields[MSG_DELTA_CLIENT_FIELD_COUNT];
extern netField_t msg_playerStateNetFields[MSG_DELTA_PLAYERSTATE_FIELD_COUNT];
extern netField_t msg_hudElemNetFields[CODUO_HUD_ELEM_NET_FIELD_COUNT];
extern netField_t msg_objectiveNetFields[CODUO_OBJECTIVE_NET_FIELD_COUNT];

void MSG_Init(msg_t *msg, uint8_t *data,
              int32_t length);
void MSG_BeginReading(msg_t *msg);
void MSG_WriteBits(msg_t *msg, int32_t value,
                   int32_t bits);
void MSG_WriteBit0(msg_t *msg);
void MSG_WriteBit1(msg_t *msg);
int32_t MSG_ReadBits(msg_t *msg,
                                    int32_t bits);
int32_t MSG_ReadBit(msg_t *msg);
void MSG_WriteByte(msg_t *msg, int32_t value);
void MSG_WriteData(msg_t *msg, const void *data,
                   int32_t length);
void MSG_WriteShort(msg_t *msg, int32_t value);
void MSG_WriteLong(msg_t *msg, int32_t value);
void MSG_WriteString(msg_t *msg, const char *text);
void MSG_WriteBigString(msg_t *msg, const char *text);
void MSG_WriteAngle(msg_t *msg, float angle);
void MSG_WriteAngle16(msg_t *msg, float angle);
int32_t MSG_ReadByte(msg_t *msg);
int32_t MSG_ReadShort(msg_t *msg);
int32_t MSG_ReadLong(msg_t *msg);
float MSG_ReadAngle16(msg_t *msg);
char *MSG_ReadString(msg_t *msg);
char *MSG_ReadBigString(msg_t *msg);
char *MSG_ReadStringLine(msg_t *msg);
void MSG_ReadData(msg_t *msg, void *data,
                  int32_t length);

void MSG_SetDefaultUserCmd(const playerState_t *playerState, usercmd_t *cmd);
void MSG_ReadDeltaUsercmdKey(msg_t *msg, uint32_t key,
                             const usercmd_t *from,
                             usercmd_t *to);
void MSG_WriteDeltaEntity(msg_t *msg,
                          const coduo_host_entity_state_snapshot_t *from,
                          const coduo_host_entity_state_snapshot_t *to,
                          qboolean force);
void MSG_WriteDeltaClient(msg_t *msg,
                          const coduo_host_client_snapshot_t *from,
                          const coduo_host_client_snapshot_t *to,
                          qboolean force);
void MSG_WriteDeltaPlayerstate(msg_t *msg,
                               const playerState_t *from,
                               const playerState_t *to);
void MSG_ReadDeltaPlayerstate(msg_t *msg,
                              const playerState_t *from,
                              playerState_t *to);
void MSG_WriteReliableCommandToBuffer(const char *in, char *out,
                                      int32_t outSize);
int16_t LittleShort(int16_t value);
int32_t LittleLong(int32_t value);

#endif
