#pragma once

#include <openssl/ossl_typ.h>
#include <event2/event.h>

#include <tfe_stream.h>
#include <tfe_future.h>
#include <proxy.h>

struct tfe_thread_ctx
{
	struct tfe_proxy *proxy;
	pthread_t thr;
	int readable_tid;
	unsigned int thread_id;
	unsigned int load;

	struct event_base * evbase;
	struct evdns_base* dnsbase;
	struct evhttp_connection* evhttp;
	time_t lastime;
	
	unsigned int nr_modules;
	const struct tfe_plugin * modules;
};

enum tfe_plugin_state
{
	PLUG_STATE_READONLY,
	PLUG_STATE_PREEPTION,
	PLUG_STATE_DETACHED
};

struct plugin_ctx
{
	enum tfe_plugin_state state;
	unsigned int is_plugin_opened;
	void * pme;
};

struct tfe_stream_write_ctx
{
	struct tfe_stream_private * _stream;
	enum tfe_conn_dir dir;
};

struct tfe_conn_private
{
	struct tfe_stream_private * _stream_ref;
	evutil_socket_t fd;
	struct bufferevent * bev;
	struct ev_token_bucket_cfg * ratelimit_bucket;
	uint8_t on_writing;
};

enum tfe_stream_event_log_type
{
	EVENT_LOG_CLOSE_BY_FD_PEER,
	EVENT_LOG_CLOSE_BY_FD_EOF,
	EVENT_LOG_CLOSE_BY_FD_ERROR,
	EVENT_LOG_CLOSE_BY_SSL_ERROR,
	__EVENT_LOG_CLOSE_MAX
};

struct tfe_stream_event_log
{
	enum tfe_stream_event_log_type type;
	enum tfe_conn_dir dir;
	unsigned int error;
	const char * str_error;
};

struct tfe_stream_private
{
	struct tfe_stream head;
	char * str_stream_addr;
	void * stream_logger;

	struct tfe_proxy * proxy_ref;
	struct tfe_thread_ctx * thread_ref;
	struct tfe_cmsg * cmsg;

	enum tfe_stream_proto session_type;
	struct tfe_stream_write_ctx * w_ctx_upstream;
	struct tfe_stream_write_ctx * w_ctx_downstream;
	struct tfe_conn_private * conn_upstream;
	struct tfe_conn_private * conn_downstream;

	struct
	{
		struct ssl_mgr * ssl_mgr;
		struct ssl_stream * ssl_downstream;
		struct ssl_stream * ssl_upstream;
	};

	uint8_t is_first_call_rxcb;
	uint8_t is_plugin_opened;
	int calling_idx;

	size_t forward_bytes;
	size_t drop_bytes;
	size_t defer_bytes;
	struct timeval defer_timeval;

	enum tfe_app_proto app_proto;

	/* Plugin Ctxs */
	unsigned int nr_plugin_ctxs;
	struct plugin_ctx * plugin_ctxs;

	/* TCP forward without scan or decode when the tcp_passthough is set */
	bool tcp_passthough;

	/* For defer connection setup */
	evutil_socket_t defer_fd_downstream;
	evutil_socket_t defer_fd_upstream;

	/* ASYNC UPSTREAM */
	future * future_upstream_create;
	/* ASYNC DOWNSTREAM */
	future * future_downstream_create;

	/* SUSPEND */
	bool is_suspended;
	enum tfe_conn_dir suspended_by;

	/* KILL */
	bool need_to_be_kill;

	/* KEYRING-ID */
	unsigned keyring_id;

	/* ONLY FOR LOG */
	evutil_socket_t log_fd_downstream;
	evutil_socket_t log_fd_upstream;

	/* EVENT LOG */
#define STREAM_EVENT_LOG_MAX	8
	struct tfe_stream_event_log log_event[STREAM_EVENT_LOG_MAX];
	unsigned int nr_log_event;

	/* CONNECTION LOG */
	char ssl_downstream_info_dump[TFE_STRING_MAX];
	char ssl_upstream_info_dump[TFE_STRING_MAX];

	/* OFFSET FOR LOG */
	size_t downstream_rx_offset;
	size_t upstream_rx_offset;
};

static inline void * __STREAM_LOGGER(struct tfe_stream_private * _stream)
{
	return _stream->proxy_ref->logger;
}
