/*
 * Kangaroo Punch MultiPlayer Game Server Mark II
 * Copyright (C) 2020-2021  Scott Duensing
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */


#ifndef PACKET_H
#define PACKET_H


#include "os.h"
#include "packets.h"


/*
 * Packet format (without framing):
 *
 * Byte 01:  cces ssss  - Two control bits, one encryption bit, five sequence bits.
 * Byte 02:  pppp pppp  - Eight bits, packet type.
 * Byte 03:  cccc cccc  - Eight bits, channel.
 * Byte 04:  dddd dddd  \
 * Byte ..:  dddd dddd   > Packet payload.
 * Byte X0:  dddd dddd  /
 * Byte X1:  cccc cccc  - Checksum
 *
 */


#define PACKET_MAX               1024  // Maximum number of bytes per packet.
#define PACKET_SEQUENCE_MAX        32  // Five bits of data, 32 max.  Represents size of replay history.  Also maximum number of packets on the wire at a time.

#define PACKET_INPUT_QUEUE_SIZE  4096
#define PACKET_BUFFER_SIZE       (PACKET_MAX * 2 + 2 + 8)   // Worst case, every byte is a PACKET_FRAME.  Add two for ending frame.  Add 8 for worst case header and CRC.

#define PACKET_FRAME             0x7e

#define PACKET_ENCRYPT_KEY_SIZE     8  // 16 bits each.  Provides 16 bytes (128 bits) of keydata.


// This enum must be 4 entries or less.
typedef enum PacketControlE {
	PACKET_CONTROL_DAT = 0,  // Regular data packet.
	PACKET_CONTROL_RTX,      // Retransmission packet.
	PACKET_CONTROL_NAK,      // Negative acknowledge.
	PACKET_CONTROL_BAD,
	PACKET_CONTROL_COUNT
} PacketControlT;


typedef struct PacketDecodeDataS {
	// Output
	PacketTypeT  packetType;   // One of PACKET_TYPE_*
	char        *data;         // Buffer received.  MUST FREE.
	uint16_t     length;       // Length of buffer.
	uint8_t      channel;      // Which data channel it arrived on.
} PacketDecodeDataT;

typedef struct PacketEncodeDataS {
	// Input
	PacketControlT  control;      // One of PACKET_CONTROL_*
	PacketTypeT     packetType;   // One of PACKET_TYPE_*
	uint8_t         channel;      // Which data channel to use.
	uint8_t         encrypt;      // Do we want the packet encrypted?
	// Input & Output
	uint8_t         sequence;     // For NAK packets, input the sequence number we missed.  Other packets returns the sequence of this packet.
	// Output
	char           *dataPointer;  // Buffer ready to send.  DO NOT FREE.
	uint16_t        length;       // Length of buffer.
} PacketEncodeDataT;

typedef struct PacketHistoryDataS {
	char     data[PACKET_BUFFER_SIZE];
	uint16_t length;
	uint8_t  sequence;
} PacketHistoryDataT;

typedef struct PacketThreadDataS {
	// Internal state per thread for packet processing.
	/*
	uint8_t             sequence;
	uint8_t             lastRemoteSequence;
	PacketHistoryDataT  history[PACKET_SEQUENCE_MAX];
	uint8_t             historyPosition;
	*/
	char                decodeBuffer[PACKET_MAX];
	char                encodeBuffer[PACKET_BUFFER_SIZE];
	char                decodeQueue[PACKET_INPUT_QUEUE_SIZE];
	uint16_t            decodeQueueHead;
	uint16_t            decodeQueueTail;
	uint8_t             inEscape;
	uint8_t             newPacket;
	uint16_t            length;
	void               *senderData;
	uint16_t            dhModulus[PACKET_ENCRYPT_KEY_SIZE];
	uint16_t            dhBase[PACKET_ENCRYPT_KEY_SIZE];
	uint16_t            dhMySecret[PACKET_ENCRYPT_KEY_SIZE];
	uint16_t            dhMyPublic[PACKET_ENCRYPT_KEY_SIZE];
	uint16_t            dhTheirPublic[PACKET_ENCRYPT_KEY_SIZE];
	uint16_t            dhSharedKey[PACKET_ENCRYPT_KEY_SIZE];
	uint8_t             encryptionBuffer[PACKET_MAX];
	void               *aesContext;
} PacketThreadDataT;


typedef void (*packetSender)(char *data, uint32_t length, void *userData);


char              *packetContentPack(uint16_t *length, char *format, ...);
void               packetContentUnpack(char *buffer, char *format, ...);
void               packetDebugPrint(uint8_t *data, uint16_t length);
uint8_t            packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *decodeData, char *input, uint16_t inputLength);
void               packetDecodeDataDestroy(PacketDecodeDataT **packet);
void               packetDecodeDataStaticDestroy(PacketDecodeDataT *packet);
uint8_t            packetEncode(PacketThreadDataT *threadData, PacketEncodeDataT *data, char *input, uint16_t length);
uint8_t            packetEncryptionReady(void);
void               packetEncryptionSetup(PacketThreadDataT *threadData);
void               packetSend(PacketThreadDataT *threadData, PacketEncodeDataT *data);
void               packetSenderRegister(packetSender sender);
PacketThreadDataT *packetThreadDataCreate(void *senderData);
void               packetThreadDataDestroy(PacketThreadDataT **data);


#endif // PACKET_H
