#pragma once

#include <tfe_stream.h>
#include <tfe_http.h>

struct tfe_proxy;
struct tfe_thread_ctx;

typedef int plugin_init_cb_t(struct tfe_proxy * proxy);
typedef void plugin_deinit_cb_t(struct tfe_proxy * proxy);

//Return 1 for identify as its traffic;
//Return 0 for unknown traffic;
typedef int stream_open_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
	enum tfe_conn_dir dir, void ** pme);

typedef tfe_stream_action stream_data_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
	enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme);

typedef void stream_close_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
	enum tfe_stream_close_reason reason, void ** pme);

enum tfe_plugin_type
{
	TFE_PLUGIN_TYPE_PLATFORM,
	TFE_PLUGIN_TYPE_PROTOCOL,
	TFE_PLUGIN_TYPE_BUSINESS
};

struct tfe_plugin
{
	/* SYMBOL & PROTOCOL */
	const char * symbol;
	enum tfe_plugin_type type;

	/* PLUGIN INIT & DEINIT */
	plugin_init_cb_t * on_init;
	plugin_deinit_cb_t * on_deinit;

	/* STREAM */
	stream_open_cb_t * on_open;
	stream_data_cb_t * on_data;
	stream_close_cb_t * on_close;

	/* HTTP */
	http_session_begin_cb * on_session_begin;
	http_session_data_cb * on_session_data;
	http_session_end_cb * on_session_end;
};

/* Register plugin */
void tfe_plugin_register(struct tfe_plugin * plugin);
/* Unregister plugin */
void tfe_plugin_unregister(struct tfe_plugin * plugin);

/* Interate */
struct tfe_plugin * tfe_plugin_iterate(unsigned int * iterate);
unsigned int tfe_plugin_total_counts();

#define TFE_PLUGIN_REGISTER(_symbol, _plugin)											\
static void __attribute__((constructor, used)) __plugin_loader_##_symbol();				\
static void __plugin_loader_##_symbol()													\
{																						\
	_plugin.symbol = #_symbol;															\
	tfe_plugin_register(&_plugin);														\
}

#define TFE_PLUGIN_FOREACH(_p_info, _iterator)											\
for((_p_info) = tfe_plugin_iterate((_iterator)); (_p_info) != NULL;						\
	(_p_info) = tfe_plugin_iterate((_iterator)))
