#ifndef LIBTTN_ETH_BRIDGE_H
#define LIBTTN_ETH_BRIDGE_H
/****************************************************************************************************************/

#include "ttn/ttn.h"
#include "ttn/lnk/pkb.h"
#include "ttn/lnk/ttn.h"

#include "ttn/bridge/mactable.h"

/****************************************************************************************************************/

struct ttn_bridge_stats {
  uint32_t eth_broadcast_to_ttn_broadcast;
  uint32_t eth_broadcast_to_ttn_unicast;
  uint32_t eth_broadcast_to_ttn_dropped;
  uint32_t eth_unicast_to_ttn_unicast;
  uint32_t eth_unicast_to_ttn_broadcast;

  uint32_t lcl_broadcast_to_ttn_broadcast;
  uint32_t lcl_broadcast_to_ttn_unicast;
  uint32_t lcl_broadcast_to_ttn_dropped;
  uint32_t lcl_unicast_to_ttn_unicast;
  uint32_t lcl_unicast_to_ttn_broadcast;

  uint32_t ttn_to_ttn_dropped;
  uint32_t eth_to_eth_dropped;
  uint32_t lcl_to_lcl_dropped;
};

/****************************************************************************************************************/

struct ttn_bridge_handle_t;

struct ttn_bridge_operations_t {
  enum TTNProcessingResult (*packet_to_eth)(struct ttn_bridge_handle_t *ttb, ttn_pkb_t *pkb) __attribute__ ((warn_unused_result));
  enum TTNProcessingResult (*packet_to_local)(struct ttn_bridge_handle_t *ttb, ttn_pkb_t *pkb) __attribute__ ((warn_unused_result));
  enum TTNProcessingResult (*packet_to_ttn)(struct ttn_bridge_handle_t *ttb, ttn_pkb_t *pkb) __attribute__ ((warn_unused_result));
  void (*close)(struct ttn_bridge_handle_t *ttb);
};

/****************************************************************************************************************/

#include "ttn/bridge/handle.h"

/****************************************************************************************************************/

// Create destroy an instance
struct ttn_bridge_handle_t *ttn_bridge_create(ttn_timerqueue_t *tmq, const struct ttn_bridge_operations_t *ops, void *lcldata);
void ttn_bridge_close(struct ttn_bridge_handle_t *ttb);

// Set TTN instance to bridge to
void ttn_bridge_set_ttn(struct ttn_bridge_handle_t *ttb, struct ttn_lnk_handle_t *ttn);
static struct ttn_lnk_handle_t *ttn_bridge_ttn(struct ttn_bridge_handle_t *ttb);

// Call when there was a packet received by TTN
// Caller must free buffer if result indicates it was NOT processed.
enum TTNProcessingResult ttn_bridge_packet_from_ttn(struct ttn_bridge_handle_t *ttb, ttn_pkb_t *pkb)
   __attribute__ ((warn_unused_result));

// Takes packets that where received from ethernet
// Caller must free buffer if result indicates it was NOT processed.
enum TTNProcessingResult ttn_bridge_packet_from_eth(struct ttn_bridge_handle_t *ttb, ttn_pkb_t *pkb)
   __attribute__ ((warn_unused_result));

// This function takes packets that the local TCP/IP stack wants to transmit.
// Caller must free buffer if result indicates it was NOT processed.
enum TTNProcessingResult ttn_bridge_packet_from_local(struct ttn_bridge_handle_t *ttb, ttn_pkb_t *pkb)
   __attribute__ ((warn_unused_result));

// Stub that polls ttn for rx data and calls ttn_bridge_process_ttn(), ensures buffer gets freed.
void ttn_bridge_receive_ttn(struct ttn_bridge_handle_t *ttb);

// Access to address cache
struct ttn_mac_cache_t *ttn_bridge_mactable(struct ttn_bridge_handle_t *ttb);

// Notify bridge about link loss
void ttn_bridge_reset(struct ttn_bridge_handle_t *ttb);

// Local MAC
void ttn_bridge_set_local_mac(struct ttn_bridge_handle_t *ttb, const uint8_t *mac);

// Set up handling packets targeted to this device
static inline void *ttn_bridge_local_data(struct ttn_bridge_handle_t *ttb);

// Tracing of packet contents
static inline void ttn_bridge_set_tracelevel(struct ttn_bridge_handle_t *ttb, int level);
static inline int ttn_bridge_tracelevel(struct ttn_bridge_handle_t *ttb);
static inline void ttn_bridge_set_mactable_tracelevel(struct ttn_bridge_handle_t *ttb, int level);
static inline int ttn_bridge_mactable_tracelevel(struct ttn_bridge_handle_t *ttb);

// Statistics
static inline const struct ttn_bridge_stats *ttn_bridge_stats(struct ttn_bridge_handle_t *ttb);

/****************************************************************************************************************/

static inline struct ttn_lnk_handle_t *ttn_bridge_ttn(struct ttn_bridge_handle_t *ttb) {
  return ttb->ttb_ttn;
}

static inline const struct ttn_bridge_stats *ttn_bridge_stats(struct ttn_bridge_handle_t *ttb) {
  return &ttb->ttb_stats;
}

// Callers expect this to be thread safe
static inline void ttn_bridge_set_tracelevel(struct ttn_bridge_handle_t *ttb, int level) {
  ttb->ttb_tracelevel = level;
}

// Callers expect this to be thread safe
static inline int ttn_bridge_tracelevel(struct ttn_bridge_handle_t *ttb) {
  return ttb->ttb_tracelevel;
}

// Callers expect this to be thread safe
static inline void ttn_bridge_set_mactable_tracelevel(struct ttn_bridge_handle_t *ttb, int level) {
  ttn_mactable_set_tracelevel(&ttb->ttb_mactable, level);
}

// Callers expect this to be thread safe
static inline int ttn_bridge_mactable_tracelevel(struct ttn_bridge_handle_t *ttb) {
  return ttn_mactable_tracelevel(&ttb->ttb_mactable);
}

static inline void *ttn_bridge_local_data(struct ttn_bridge_handle_t *ttb) {
  return ttb->ttb_lcl_data;
}

/****************************************************************************************************************/
#endif
