/*
**********************************************************************************************
*	File: maat_rule.h
*   Description: maat rule entry
*	Authors: Liu WenTan <liuwentan@geedgenetworks.com>
*	Date:    2022-10-31
*   Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
***********************************************************************************************
*/

#ifndef _MAAT_RULE_H_
#define _MAAT_RULE_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>
#include <stddef.h>
#include <linux/limits.h>
#include <sys/time.h>
#include <pthread.h>
#include <dirent.h>
#include <openssl/md5.h>

#include "log/log.h"
#include "fieldstat.h"
#include "maat_command.h"
#include "maat_limits.h"
#include "maat.h"
#include "maat_kv.h"
#include "maat_table.h"
#include "maat_virtual.h"
#include "maat_stat.h"
#include "hiredis/hiredis.h"

#define MAX_TABLE_NUM	1024
#define MAX_COMPILE_TABLE_NUM 16

#define	DISTRICT_ANY	   -1
#define	DISTRICT_UNKNOWN   -2

#define MAX_DISTRICT_STR   128
#define INVALID_VERSION    -1

#define mr_region_id_var "SEQUENCE_REGION"
#define mr_group_id_var	 "SEQUENCE_GROUP"

enum tag_match {
    TAG_MATCH_ERR = -1,
    TAG_MATCH_UNMATCHED,
    TAG_MATCH_MATCHED
};

struct maat_item_inner {
	long long magic_num;
	long long item_id;
	long long group_id;
	long long district_id;
};

struct maat_item {
	long long item_id;
	long long group_id;
};

struct maat_runtime {
    /* maat_runtime can be created and destroy dynamic, so need version info */
    long long version;

    time_t last_update_time;

    long long *ref_cnt;
    struct table_manager *ref_tbl_mgr; //share with maat instance
    size_t max_table_num;
    
    long long rule_num;
    struct maat_kv_store *sequence_map;

    struct maat_garbage_bin *ref_garbage_bin;
    struct log_handle *logger;
};

struct rule_tag {
	char *tag_name;
	char *tag_val;
};

enum data_source {
    DATA_SOURCE_NONE = 0,
    DATA_SOURCE_REDIS,
    DATA_SOURCE_IRIS_FILE,
    DATA_SOURCE_JSON_FILE
};

struct source_iris_ctx {
    char inc_idx_dir[NAME_MAX];
    char full_idx_dir[NAME_MAX];
};

struct source_json_ctx {
	char json_file[NAME_MAX];
	char iris_file[NAME_MAX];
	char effective_json_md5[MD5_DIGEST_LENGTH*2+1];
	struct timespec last_md5_time;
};

struct source_redis_ctx {
	redisContext *read_ctx;
	redisContext *write_ctx;
	char redis_ip[64];
	uint16_t redis_port;
	int redis_db;
	time_t last_reconnect_time;
};

struct maat_options {
    char instance_name[NAME_MAX];
    char foreign_cont_dir[NAME_MAX];
    char decrypt_algo[MAX_KEYWORDS_STR];
    char decrypt_key[MAX_KEYWORDS_STR];
    char log_path[PATH_MAX];
    int log_level;
    char stat_file[PATH_MAX];
    size_t nr_worker_thread;
    char *accept_tags;

    int stat_on;
    int perf_on;
    int deferred_load_on;

    int maat_json_is_gzipped;
    int cumulative_update_off; //Default: cumulative update on

    int gc_timeout_ms;
    int rule_effect_interval_ms;
    int rule_update_checking_interval_ms;

    enum data_source input_mode;
    union {
        struct source_iris_ctx iris_ctx;
        struct source_json_ctx json_ctx;
        struct source_redis_ctx redis_ctx;
    };
};

struct maat_stat {
    char stat_file[PATH_MAX];
    struct fieldstat_instance *fs_handle;
    int total_stat_id[MAX_MAAT_STAT_NUM];
    int fs_status_id[MAX_MAAT_STAT_NUM];
	int fs_column_id[MAX_TABLE_NUM][MAX_MAAT_STAT_NUM];
    struct log_handle *logger;
    struct table_manager *ref_tbl_mgr;
    struct maat_garbage_bin *ref_garbage_bin;
    size_t nr_worker_thread;
    int cmd_q_cnt;
    

    long long *thread_call_cnt;
    long long *hit_cnt;
    long long *not_grp_hit_cnt;

    long long scan_bytes;
	long long scan_cnt;
    long long update_err_cnt;
    long long scan_err_cnt;
    long long zombie_rs_stream;
    long long line_cmd_acc_num;
};

struct maat {
    struct maat_runtime *maat_rt;
    struct maat_runtime *creating_maat_rt;
    struct table_manager *tbl_mgr;
    struct maat_options opts;

    long long maat_version;
    long long last_full_version;
    long long load_specific_version;  //Default: Load the Latest. Only valid in redis mode, and maybe failed for too old
    /* internal state */
    long long new_version;

    int is_running;
    pthread_t cfg_mon_thread;
    pthread_mutex_t background_update_mutex;

    struct log_handle *logger;
    struct maat_garbage_bin *garbage_bin;

    int default_compile_table_id;
    int g2g_table_id; //group2group table id

    /* statistics */
    struct maat_stat *stat;
};

enum district_flag {
    DISTRICT_FLAG_UNSET,
    DISTRICT_FLAG_SET
};

enum last_scan_flag {
    LAST_SCAN_UNSET,
    LAST_SCAN_SET,
    LAST_SCAN_FINISHED
};

struct maat_state {
	struct maat *maat_instance;
	int thread_id;
    int compile_table_id;
	enum district_flag is_set_district;
    enum last_scan_flag is_last_scan;
	long long district_id; //-1: Any District; -2: Unkonwn District;
	int scan_cnt;
	struct maat_compile_state *compile_state;
};

int my_scandir(const char *dir, struct dirent ***namelist,
              int(*filter)(const struct dirent *),
              int(*compar)(const void *, const void *));

struct maat_item_inner *maat_item_inner_new(long long item_id, long long group_id,
                                            long long district_id);

void maat_item_inner_free(void *item_inner);

void *rule_monitor_loop(void *arg);

long long maat_runtime_get_sequence(struct maat_runtime *maat_rt, const char *key);

void maat_read_full_config(struct maat *maat_instance);

void garbage_ip_matcher_free(void *ip_matcher, void *arg);

void garbage_interval_matcher_free(void *ip_matcher, void *arg);

void garbage_bool_matcher_free(void *bool_matcher, void *arg);

void garbage_maat_kv_store_free(void *kv_store, void *arg);

#ifdef __cplusplus
}
#endif

#endif
