#pragma once

extern "C"
{
#include <sys/queue.h>
}

#include <tfe_http.h>
#include <http_half.h>
#include <http_parser.h>

TAILQ_HEAD(hs_private_list, http_session_private);

struct http_plugin
{
	/* Garbage List for HTTP-SESSION object.
	 * these objects can not be destroyed when TCP connection terminated. */
	struct hs_private_list gc_list_hs_private[TFE_THREAD_MAX];
	/* Lock for garbage list */
	pthread_mutex_t lock_list_hs_private[TFE_THREAD_MAX];
	/* GC events */
	struct event * gc_event_hs_private[TFE_THREAD_MAX];
	/* ACCESS LOGGER */
	void * logger;
};

extern struct http_plugin * g_http_plugin;

struct http_session_private
{
	/* PUBLIC */
	struct tfe_http_session hs_public;
	/* TAILQ POINTER */
	TAILQ_ENTRY(http_session_private) next;
	/* HTTP CONNECTION ADDR */
	char * str_stream_info;
	/* REF, HTTP CONNECTION */
	struct http_connection_private * hc_private;
	/* HTTP FRAME CTX */
	struct http_frame_session_ctx * ht_frame;
	/* USER SETUP REQUEST HALF */
	struct http_half_private * hf_private_req_user;
	/* USER SETUP RESPONSE HALF */
	struct http_half_private * hf_private_resp_user;
	/* SUSPEND EVENT */
	tfe_http_event suspend_event;
	/* SUSPEND TAG EFFECTIVE */
	bool suspend_tag_effective;
	/* SUSPEND TAG STREAM */
	bool suspend_tag_signal;
	/* RESUME SIGNAL */
	bool resume_tag_singal;
	/* RELEASE LOCK, when the tag is zero, the session can be destroyed */
	int release_lock;
	/* thread id */
	unsigned int thread_id;
	/* SUSPEND COUNTER, only for debug and log */
	int suspend_counter;
	/* IN GC QUEUE, means the connection of session has destroyed */
	bool in_gc_queue;
	/* KILL */
	bool kill_signal;
};

struct http_connection_private
{
	/* STREAM */
	const struct tfe_stream * stream;
	/* SESSION LIST, REQUEST-RESPONSE PAIRS */
	struct hs_private_list hs_private_list;
	/* ORPHAN SESSION LIST */
	struct hs_private_list hs_private_orphan_list;
	/* IS PREEMPTED */
	unsigned int is_preempted;
	/* SESSION ID COUNTER */
	unsigned int session_id_counter;
};

static inline struct http_half_private * to_hf_request_private(struct http_session_private * hs_private)
{
	if(hs_private == NULL) return NULL;
	struct tfe_http_half * hf_public = hs_private->hs_public.req;
	return container_of(hf_public, struct http_half_private, hf_public);
}

static inline struct http_half_private * to_hf_response_private(struct http_session_private * hs_private)
{
	if(hs_private == NULL) return NULL;
	struct tfe_http_half * hf_public = hs_private->hs_public.resp;
	return container_of(hf_public, struct http_half_private, hf_public);
}

static inline struct tfe_http_half * to_hf_public(struct http_half_private * hf_private)
{
	if(hf_private == NULL) return NULL;
	return &hf_private->hf_public;
}

static inline struct http_half_private * to_hf_private(struct tfe_http_half * hf_public)
{
	if(hf_public == NULL) return NULL;
	return container_of(hf_public, struct http_half_private, hf_public);
}

static inline const struct http_half_private * to_hf_private(const struct tfe_http_half * hf_public)
{
	if(hf_public == NULL) return NULL;
	return container_of(hf_public, struct http_half_private, hf_public);
}

static inline const struct tfe_http_session * to_hs_public(const struct http_session_private * hs_private)
{
	if (hs_private == NULL) return NULL;
	return &hs_private->hs_public;
}

static inline struct tfe_http_session * to_hs_public(struct http_session_private * hs_private)
{
	if (hs_private == NULL) return NULL;
	return &hs_private->hs_public;
}

static inline struct http_session_private * to_hs_private(struct tfe_http_session * hs_public)
{
	if (hs_public == NULL) return NULL;
	return container_of(hs_public, struct http_session_private, hs_public);
}
