#ifndef __KVS_RW_TOOLS_H__
#define __KVS_RW_TOOLS_H__

#include <stdint.h>
#include <stdio.h>
// 
int kvs_need(const uint8_t *p, const uint8_t *end, size_t n);
int kvs_read_u8(const uint8_t **pp, const uint8_t *end, uint8_t *out);
int kvs_read_u16(const uint8_t **pp, const uint8_t *end, uint16_t *out);
int kvs_read_u32(const uint8_t **pp, const uint8_t *end, uint32_t *out);

int kvs_write_u8(uint8_t **pp, const uint8_t *end, uint8_t v);
int kvs_write_u16(uint8_t **pp, const uint8_t *end, uint16_t v);
int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v);

int kvs_write_file(FILE *fp, const void *buf, size_t n);
int kvs_read_file(FILE *fp, void *buf, size_t n);

int write_full(int fd, const void *buf, size_t len);
int read_full(int fd, void *buf, size_t n);

 /**
 * Request
 * Cmd: 	| OP(1) | argc(1) | repeat { arglen(4) | arg } |
 * 
 * Response
 * Rsp:		| OP(1) | status(1) | datalen(4) | data | 
 */

// 1MB
#define KVS_MAX_RESPONSE 		(65536)
#define KVS_MAX_ARGLEN			(507)
#define KVS_MAX_CMD_BYTES 		(1024)
#define KVS_MAX_ARGC 			3

enum {
	KVS_STATUS_OK = 0,
	KVS_STATUS_ERROR = 1,
	KVS_STATUS_NO_EXIST = 2,
	KVS_STATUS_EXIST = 3,
	KVS_STATUS_BADREQ = 4
};

typedef enum {
	KVS_CMD_START = 0,
	// array
	KVS_CMD_SET = KVS_CMD_START,
	KVS_CMD_GET,
	KVS_CMD_DEL,
	KVS_CMD_MOD,
	KVS_CMD_EXIST,
	// rbtree
	KVS_CMD_RSET,
	KVS_CMD_RGET,
	KVS_CMD_RDEL,
	KVS_CMD_RMOD,
	KVS_CMD_REXIST,
	// hash
	KVS_CMD_HSET,
	KVS_CMD_HGET,
	KVS_CMD_HDEL,
	KVS_CMD_HMOD,
	KVS_CMD_HEXIST,
	
	KVS_CMD_PSYNC,
	KVS_CMD_SAVE,
	KVS_CMD_COUNT,
}kvs_cmd_t;

typedef struct kvs_arg_s{
	uint32_t len;
	const uint8_t *data;     
} kvs_arg_t;

typedef struct kvs_req_s{
	kvs_cmd_t op;
	uint8_t argc;
	kvs_arg_t *args;
}kvs_req_t;

typedef struct kvs_rsp_s{
	kvs_cmd_t op;
	uint8_t status;
	uint32_t dlen;
	const uint8_t *data;
} kvs_rsp_t;

int kvs_parse_one_cmd(const uint8_t *request, int request_length, kvs_req_t *req_out);
void kvs_free_request(kvs_req_t *req);
int kvs_execute_one_cmd(const kvs_req_t *req, kvs_rsp_t *rsp_out);
int kvs_build_one_rsp(const kvs_rsp_t *results, uint8_t *response, size_t response_cap);
int kvs_save_to_file();

int kvs_save_cmd_to_logfile(const uint8_t *cmd, size_t len, int logfd);
int	kvs_replay_log(const char *logfile, int logfd);
int ksv_clear_log(int logfd);

#endif
