#pragma GCC diagnostic ignored "-Wunused-parameter"

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>

#include "app_l7_protocol.h"

#include "stellar/stellar.h"
#include "stellar/session.h"
#include "stellar/stellar_exdata.h"
#include "stellar/stellar_mq.h"

#include "cjson/cJSON.h"


#define MAX_APP_ID_VALUE 10000
struct glimpse_detector_test_plugin_env
{
    int test_exdata_idx;
    int l7_exdata_idx;
    int test_app_plugin_id;
	int expect_json_topic_id;
    struct stellar *st;
	char *g_proto_id2name[MAX_APP_ID_VALUE];
};

static int load_l7_protocol_mapper(const char *filename, struct glimpse_detector_test_plugin_env *env)
{
	memset(env->g_proto_id2name, 0, sizeof(env->g_proto_id2name));
	int ret=0, proto_id=0;;
	FILE *fp=NULL;
	char line[1024]={0};
	char type_name[32]={0};
	char proto_name[32]={0};

	fp=fopen(filename, "r");
	if(fp==NULL)
	{
		printf("Open %s failed ...", filename);
		return -1;
	}

	memset(line, 0, sizeof(line));

	while((fgets(line, sizeof(line), fp))!=NULL)
	{
		if(line[0]=='#' || line[0]=='\n' || line[0]=='\r' ||line[0]=='\0')
		{
			continue;
		}
		
		ret=sscanf(line, "%31s %31s %d", type_name, proto_name, &proto_id);
		env->g_proto_id2name[proto_id] = (char*)calloc(strlen(proto_name)+1, 1);
		strcpy(env->g_proto_id2name[proto_id], proto_name);
		memset(line, 0, sizeof(line));
	}

	fclose(fp);
	fp=NULL;
	return ret;
}

static void publish_session_test_result(struct glimpse_detector_test_plugin_env *env,  cJSON *ctx, struct session *sess)
{
        assert(env->l7_exdata_idx >= 0  && ctx != NULL);
        struct l7_protocol_label *label = (struct l7_protocol_label *)session_exdata_get(sess, env->l7_exdata_idx);;
        if(label != NULL)
        {
            int proto_ids[8];
            const char* proto_names[8];
            for(int i = 0; i < label->protocol_id_num; i++)
            {
                proto_ids[i] = (int)(label->protocol_id[i]);
                proto_names[i] = env->g_proto_id2name[proto_ids[i]];

            }
            cJSON *label_ids = cJSON_CreateIntArray(proto_ids, label->protocol_id_num);
            cJSON_AddItemToObject(ctx, "l7_label_id", label_ids);
            cJSON *label_names = cJSON_CreateStringArray(proto_names, label->protocol_id_num);
            cJSON_AddItemToObject(ctx, "l7_label_name", label_names);
        }
        else
        {
                cJSON_AddStringToObject(ctx, "l7_label_id", "UNKNOWN");
        }
        unsigned char dir_flag;
        int is_symmetric=session_is_symmetric(sess, &dir_flag);
        if(is_symmetric)
        {
           cJSON_AddStringToObject(ctx, "STREAM_DIR", "DOUBLE"); 
        }
        else if(dir_flag == SESSION_SEEN_C2S_FLOW)
        {
            cJSON_AddStringToObject(ctx, "STREAM_DIR", "C2S");
        }
        else if(dir_flag == SESSION_SEEN_S2C_FLOW)
        {
             cJSON_AddStringToObject(ctx, "STREAM_DIR", "S2C");
        }
        else
        {
            assert(0);
        }
		session_mq_publish_message(sess, env->expect_json_topic_id, cJSON_Print(ctx));
        cJSON_Delete(ctx);
        return;
}


 void *glimpse_detector_test_ctx_new(struct session *sess, void *plugin_env)
{
    cJSON *ctx =cJSON_CreateObject();
    cJSON_AddStringToObject(ctx, "Tuple4", session_get0_readable_addr(sess));
    enum session_type type= session_get_type(sess);
    if (type == SESSION_TYPE_TCP)
    {
        cJSON_AddStringToObject(ctx, "STREAM_TYPE", "TCP");
    }
    if (type == SESSION_TYPE_UDP)
    {
        cJSON_AddStringToObject(ctx, "STREAM_TYPE", "UDP");
    }
    return ctx;
}

static void APP_TEST_ON_SESSION_MSG(struct session *sess, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env)
{
	if(session_get_current_state(sess)==SESSION_STATE_CLOSED)
	{
		publish_session_test_result((struct glimpse_detector_test_plugin_env*)plugin_env, (cJSON *)per_session_ctx, sess); 
	}
	return;
}

extern "C" void *GLIMPSE_DETECTOR_TEST_PLUG_LOAD(struct stellar *st)
{
    struct glimpse_detector_test_plugin_env *env = (struct glimpse_detector_test_plugin_env *)calloc(1, sizeof(struct glimpse_detector_test_plugin_env));
    env->st=st;
    const char *l7_proto_name=(const char*)"./tsgconf/tsg_l7_protocol.conf";

#if 0
	const char *l7_label_name=(const char*)"L7_PROTOCOL_LABEL";
    const char *l7_bridge_name=(const char*)"APP_BRIDGE";
    MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "L7_LABEL_NAME", l7_label_name, sizeof(l7_label_name), "L7_PROTOCOL_LABEL");
	MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "APP_BRIDGE_NAME", l7_bridge_name, sizeof(l7_bridge_name), "APP_BRIDGE");
	MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "L7_PROTOCOL_FILE", l7_proto_name, sizeof(l7_proto_name), "./tsgconf/tsg_l7_protocol.conf");
#endif 

    env->l7_exdata_idx= stellar_exdata_new_index(st, "L7_PROTOCOL", stellar_exdata_free_default, NULL);	
    env->test_exdata_idx= stellar_exdata_new_index(st, "APP_PROTO_TEST", stellar_exdata_free_default, NULL);	
	if(env->l7_exdata_idx<0 || env->test_exdata_idx<0)
	{
		perror("GLIMPSE_DETECTOR_TEST_PLUG_INIT:stellar_session_get_ex_new_index faild!!!\n");
		exit(-1);
	}
	if(load_l7_protocol_mapper(l7_proto_name, env)<0)
	{
		perror("GLIMPSE_DETECTOR_TEST_PLUG_INIT:l7_protocol_mapper failed !!!\n");	
		exit(-1);
	}
    env->test_app_plugin_id=stellar_session_plugin_register(st, glimpse_detector_test_ctx_new, NULL, env);
    if(env->test_app_plugin_id < 0)
    {
        perror("GLIMPSE_DETECTOR_TEST_PLUG_INIT:stellar_plugin_register failed !!!\n");	
		exit(-1);
    }

	int tcp_topic_id=stellar_mq_get_topic_id(st, TOPIC_TCP);
	int udp_topic_id=stellar_mq_get_topic_id(st, TOPIC_UDP);
	if(tcp_topic_id < 0 || udp_topic_id < 0)
	{
		perror("GLIMPSE_DETECTOR_TEST get tcp or udp topic id failed\n");
		exit(-1);
	}

	stellar_session_mq_subscribe(st, tcp_topic_id, APP_TEST_ON_SESSION_MSG, env->test_app_plugin_id);
	stellar_session_mq_subscribe(st, udp_topic_id, APP_TEST_ON_SESSION_MSG, env->test_app_plugin_id);    
	env->expect_json_topic_id = stellar_mq_create_topic(st, "EXPECT_JSON", stellar_msg_free_default, NULL);
    printf("GLIMPSE_DETECTOR_TEST_PLUG_LOAD OK!\n");	

    return env;
}

extern "C" void GLIMPSE_DETECTOR_TEST_PLUG_UNLOAD(void *plugin_env)
{
    struct glimpse_detector_test_plugin_env *env = (struct glimpse_detector_test_plugin_env *)plugin_env;
    for(int i = 0; i < MAX_APP_ID_VALUE; i++)
    {
        if(env->g_proto_id2name[i])free(env->g_proto_id2name[i]);
    }
	free(env);
    printf("GLIMPSE_DETECTOR_TEST_PLUG_UNLOAD OK!\n");	
    return ;
}
