#pragma once

#include <tfe_http.h>
#include <http_parser.h>
#include <sys/queue.h>

typedef int (hf_private_cb)(struct http_half_private * hf_private,
	tfe_http_event ev, const unsigned char * data, size_t len, void * user);

enum hf_private_status
{
	STATUS_INIT,
	STATUS_READING,
	STATUS_COMPLETE,
};

struct http_header_private
{
	TAILQ_ENTRY(http_header_private) next;
	struct http_field_name * field;
	char * value;
};

#define BV(x) (1 << x)
#define HTTP_ACCEPT_ENCODING_NONE					0
#define HTTP_ACCEPT_ENCODING_IDENTITY 				BV(0)
#define HTTP_ACCEPT_ENCODING_GZIP     				BV(1)
#define HTTP_ACCEPT_ENCODING_DEFLATE  				BV(2)
#define HTTP_ACCEPT_ENCODING_COMPRESS 				BV(3)
#define HTTP_ACCEPT_ENCODING_BZIP2    				BV(4)
#define HTTP_ACCEPT_ENCODING_X_GZIP   				BV(5)
#define HTTP_ACCEPT_ENCODING_X_BZIP2  				BV(6)
#define HTTP_ACCEPT_ENCODING_BR						BV(7)

TAILQ_HEAD(http_header_private_list, http_header_private);
struct http_half_private
{
	/* PUBLIC STRUCTURE */
	struct tfe_http_half hf_public;
	/* SESSION OF THIS REQUEST/RESPONSE */
	struct http_session_private * session;
	/* Callback Function */
	hf_private_cb * event_cb;
	/* Callback Function User Pointer */
	void * event_cb_user;
	/* Callback Function User Pointer Deleter */
	void (* event_cb_user_deleter)(void *);
	/* HTTP PARSER */
	struct http_parser * parse_object;
	/* HTTP PARSER SETTING */
	struct http_parser_settings * parse_settings;
	/* CURSOR RELATED TO DELAYED DATA */
	size_t parse_cursor;
	/* HTTP PARSER'S ERRNO */
	enum http_errno parse_errno;
	/* HEADER K-V */
	struct http_header_private_list header_list;

	/* UNDERLAY BUFFER */
	int method_or_status;
	short major;
	short minor;

	/* URI */
	struct evbuffer * evbuf_uri;
	char * url_storage;

	/* Content-Encoding */
	uint16_t accept_content_encoding;
	uint16_t content_encoding;
	struct hf_content_uncompress * cv_uncompress_object;
	struct hf_content_compress * cv_compress_object;

	/* Header Parser */
	struct evbuffer * evbuf_header_field;
	struct evbuffer * evbuf_header_value;
	bool is_evbuf_header_field_set;
	bool is_evbuf_header_value_set;

	/* Status */
	enum hf_private_status body_status;
	enum hf_private_status message_status;

	/* default stream action */
	enum tfe_stream_action stream_action;
	enum tfe_stream_action user_stream_action;
	bool is_user_stream_action_set;

	/* Setup by User */
	bool is_setup_by_user;
	bool is_setup_by_stream;

	struct evbuffer * evbuf_body;
	struct evbuffer * evbuf_raw;
	struct tfe_stream_write_ctx * write_ctx;

	/* UPGRADE */
	bool is_upgrade;
	/* PASSTHROUGH */
	bool is_passthrough;
};

struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor);

void hf_private_destory(struct http_half_private * hf_private);

/** Parse the raw tcp input for HTTP half structure
 * @param hf_private
 * 		hf_private handler.
 * @param data
 * 		raw tcp data, used in the stream's callback.
 * @param len
 * 		raw tcp data length.
 * @return
 * 		0 for need more data,
 * 		1 for reach the boundary, need to call http business callbacks,
 * 		-1 for error.
 */
int hf_private_parse(struct http_half_private * hf_private, const unsigned char * data, size_t len);
void hf_private_construct(struct http_half_private * hf_private);

void hf_private_set_callback(struct http_half_private * hf_private, hf_private_cb * cb,
	void * user, void (* fn_user_deleter)(void *));

void hf_private_set_session(struct http_half_private * hf_private, struct http_session_private * hs_private);

struct http_session_private * hs_private_create(struct http_connection_private * hc_private, unsigned int thread_id,
    struct http_half_private * hf_private_req, struct http_half_private * hf_private_resp);

void hs_private_destroy(struct http_session_private * hs_private);
void hs_private_gc_destroy(struct http_session_private * hs_private, struct hs_private_list * gc_list);
bool hs_private_can_destroy(struct http_session_private * hs_private);

void hs_private_hf_private_set(struct http_session_private * hs_private,
	struct http_half_private * hf, enum tfe_http_direction);

struct http_half_private * hs_private_hf_private_release(struct http_session_private * hs_private, enum tfe_http_direction);
