#pragma once

#include <marsio.h>
#include <tfe_stream.h>
#include <netinet/ether.h>
#include <MESA/Maat_rule.h>
#include <pcap/pcap.h>

enum traffic_mirror_ethdev_type
{
    TRAFFIC_MIRROR_ETHDEV_AF_PACKET,
    TRAFFIC_MIRROR_ETHDEV_MARSIO
};

enum traffic_mirror_target_addr_type
{
    TRAFFIC_MIRROR_TARGET_BY_VLAN_ID,
    TRAFFIC_MIRROR_TARGET_BY_ETHER_ADDR,
};

struct traffic_mirror_instance
{
    void * logger;
    unsigned int enable;
    unsigned int nr_threads;
    unsigned int default_vlan_id_for_mac;

    Maat_feather_t maat_feather;
    int policy_table_id;
    int profile_table_id;

    /* DEFAULT MAC ADDRESS, IN VLAN MODE */
    char default_ether_addr_src;
    char default_ether_addr_dst;

    struct traffic_mirror_ethdev * ethdev;
};

struct policy_table_ex_data
{
    unsigned int atomic_refcnt;
    unsigned int enable;
    unsigned int profile_id;
};

struct profile_table_ex_data
{
    unsigned int atomic_refcnt;
    unsigned int nr_targets;

    /* Target VLANS */
    unsigned int * vlans;
    struct ether_addr * ether_addrs;
    int rewrite_mac;
    int rewrite_vlan;
};

struct traffic_mirror_ethdev_pcap
{
    pcap_t * pcap_device_handle;
    char sendbuf[TFE_THREAD_MAX][ETHER_MAX_LEN];
};

struct traffic_mirror_ethdev_mr4
{
    /* DEVICE INSTANCES */
    struct mr_instance * instance;
    struct mr_vdev * device;
    struct mr_sendpath * sendpath;

    /* THREAD SENDBUF */
    unsigned int nr_tx_threads;
    marsio_buff_t * sendbuf[TFE_THREAD_MAX];
};

struct traffic_mirror_ethdev
{
    /* PUBLIC */
    char str_device[TFE_SYMBOL_MAX];

    unsigned int mtu;
    unsigned int en_offload_vlan;
    unsigned int en_offload_ip_cksum;
    unsigned int en_offload_tcp_cksum;
    char local_ether_addr[6];

    enum traffic_mirror_ethdev_type type;
    union
    {
        struct traffic_mirror_ethdev_pcap * detail_pcap;
        struct traffic_mirror_ethdev_mr4 * detail_mr4;
    };

    /* FUNCTIONS */
    char * (*fn_send_prepare)(struct traffic_mirror_ethdev *, unsigned int tid);
    int (*fn_send_finish)(struct traffic_mirror_ethdev * ethdev, unsigned int, unsigned int);
    void (*fn_send_abort)(struct traffic_mirror_ethdev * ethdev, unsigned int tid);
    void (*fn_destroy)(struct traffic_mirror_ethdev * ethdev);
};

struct traffic_mirror_rebuild_target
{
    struct ether_addr ether_addr;
    unsigned int vlan_tci;
    int rewrite_as_target_mac;
    int rewrite_as_target_vlan;
};

struct traffic_mirror_ethdev * traffic_mirror_ethdev_pcap_create(const char * str_ethdev, void * logger);
struct traffic_mirror_ethdev * traffic_mirror_ethdev_mr4_create(const char * str_ethdev,
    unsigned int nr_threads, void * logger);

void traffic_mirror_ethdev_destroy(struct traffic_mirror_ethdev * ethdev);
int traffic_mirror_ethdev_finish(struct traffic_mirror_ethdev * ethdev, unsigned int tid, unsigned int pktlen);

struct traffic_mirror_rebuild * traffic_mirror_rebuild_create(struct tfe_stream_addr * addr,
	struct ether_addr * s_ether_addr, struct ether_addr * d_ether_addr,
	struct traffic_mirror_rebuild_target * target, struct traffic_mirror_ethdev * ethdev);

void traffic_mirror_rebuild_destroy(struct traffic_mirror_rebuild * instance);
void traffic_mirror_rebuild_handshake(struct traffic_mirror_rebuild * instance, unsigned int tid);
void traffic_mirror_rebuild_data(struct traffic_mirror_rebuild * instance, unsigned int tid, const char * data,
    unsigned int datalen, enum tfe_conn_dir dir);
void traffic_mirror_rebuild_farewell(struct traffic_mirror_rebuild * instance, unsigned int tid);

