#ifndef LIBTTN_NET_TTN_H
#define LIBTTN_NET_TTN_H
/****************************************************************************************************************/

#include "ttn/lnk/struct.h"

#include "ttn/ttn.h"

#if defined(__cplusplus)
extern "C" {
#endif

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

#define TTN_PACKET_OVERHEAD     4  // Number of bytes used for encapsulation of a data packet
#define TTN_MAX_PACKET_SIZE     (TTN_CONFIG_MAX_PAYLOAD_SIZE + TTN_PACKET_OVERHEAD)

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

#include "ttn/lnk/pkb.h"

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

// Create destroy an instance
struct ttn_lnk_handle_t *ttn_lnk_create(ttn_timerqueue_t *tmq);
void ttn_lnk_close(struct ttn_lnk_handle_t *ttn);

// Set driver for transmit/receive of raw byte data
struct ttn_lnk_device_t;
void ttn_lnk_set_device(struct ttn_lnk_handle_t *ttn, struct ttn_lnk_device_t *dev);

// Set device bitrate (Passed along to the driver, but also used to calculate timeout values.)
void ttn_lnk_set_speed(struct ttn_lnk_handle_t *ttn, unsigned int bitspersecond);

// Set local station MAC
void ttn_lnk_set_mac(struct ttn_lnk_handle_t *ttn, const uint8_t *mac);
static inline const uint8_t *ttn_lnk_mac(struct ttn_lnk_handle_t *ttn);

// Set a user defined data pointer
static inline void ttn_lnk_set_data(struct ttn_lnk_handle_t *ttn, void *data);
static inline void *ttn_lnk_data(struct ttn_lnk_handle_t *ttn);

// Set a user defined data pointer
static inline void ttn_lnk_set_allocator_data(struct ttn_lnk_handle_t *ttn, void *data);
static inline void *ttn_lnk_allocator_data(struct ttn_lnk_handle_t *ttn);

// A newly created instance always starts in stopped state
void ttn_lnk_start(struct ttn_lnk_handle_t *ttn);
void ttn_lnk_stop(struct ttn_lnk_handle_t *ttn);

// true if so
static inline int ttn_lnk_is_online(struct ttn_lnk_handle_t *ttn);

// Call this when OS indicates that device has data for reading.
void ttn_lnk_receive_device(struct ttn_lnk_handle_t *ttn);

// This call causes a bus reconfiguration.
void ttn_lnk_bus_reset(struct ttn_lnk_handle_t *ttn);

// Tracing of packet contents
static inline void ttn_lnk_set_tracelevel(struct ttn_lnk_handle_t *ttn, unsigned int level);

// A bitmap of known peers
static inline ttn_bitmap_t ttn_lnk_population(struct ttn_lnk_handle_t *ttn);

// Get state
static inline int ttn_lnk_station_id(struct ttn_lnk_handle_t *ttn);
static inline int ttn_lnk_next_station_id(struct ttn_lnk_handle_t *ttn);
static inline int ttn_lnk_probing_station_id(struct ttn_lnk_handle_t *ttn);

// Attempt to become the current probing host
void ttn_lnk_become_probing_host(struct ttn_lnk_handle_t *ttn);

// Ask a station to make some noise, flash LEDs, whatever, get attention.
void ttn_lnk_buzz(struct ttn_lnk_handle_t *ttn, unsigned int tid);

// Make some noise, flash LEDs, whatever, get attention.
void ttn_glue_buzz(struct ttn_lnk_handle_t *ttn, unsigned int sid);

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

// Send the pkb structured data.
int ttn_pkb_send(struct ttn_lnk_handle_t *ttn, ttn_pkb_t *pkb) __attribute__ ((warn_unused_result));

// Get receive data.
// Returned pkb must be free'd by the caller.
// Returns 0 if there is none.
ttn_pkb_t *ttn_lnk_receive(struct ttn_lnk_handle_t *ttn);

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

// Diagnostics events go here
typedef void ttn_diag_event_cb_t(void *data, const struct ttn_diag_event_t *diag);
static inline void ttn_set_diag_event_handler(struct ttn_lnk_handle_t *ttn, ttn_diag_event_cb_t *cb, void *data);

// Just log to debug log
void ttn_log_diag_event(struct ttn_lnk_handle_t *ttn, const struct ttn_diag_event_t *data);

// Current link state
static inline enum ttn_lnk_state_t ttn_lnk_state(struct ttn_lnk_handle_t *ttn);

// For debugging purposes
const char *ttn_lnk_state_name(enum ttn_lnk_state_t state);

// Ditto, with ANSI color codes
const char *ttn_lnk_colored_state_name(enum ttn_lnk_state_t state);

// For debugging purposes
const char *ttn_format_probe_state(const uint8_t *mac, unsigned int bits, char *buf, size_t bufsize);
const char *ttn_format_bitfield(ttn_bitmap_t bitfield, char *buf, size_t bufsize);

// For debugging purposes
void ttn_trace_packet(int level, const struct ttn_lnk_handle_t *ttn, const struct ttn_packet_t *pkt, size_t len, const char *tag);

// Returns an (possibly incompletely filled) array with TTN_MAX_ID items.
// BEWARE OF OFF-BY-ONE: First array item at index 0 represents TID 1.
static inline const struct ttn_peer_properties_t *ttn_lnk_peer_properties(struct ttn_lnk_handle_t *ttn);

// Returns stats counter structure.
// The pointer stays valid for as long as the ttn handle exists.
static const struct ttn_stats_t *ttn_lnk_stats(struct ttn_lnk_handle_t *ttn);

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

ttn_pkb_t *ttn_glue_pkb_alloc(void *allocator_data, size_t lsize);
ttn_pkb_t *ttn_glue_pkb_dup(void *allocator_data, ttn_pkb_t *pkb);
void ttn_glue_pkb_free(void *allocator_data, ttn_pkb_t *pkb);

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

#include "ttn/lnk/device.h"
#include "ttn/lnk/handle.h"

static inline void ttn_lnk_set_data(struct ttn_lnk_handle_t *ttn, void *data) {
  ttn->ttn_data = data;
}

static inline void *ttn_lnk_data(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_data;
}

static inline void ttn_lnk_set_allocator_data(struct ttn_lnk_handle_t *ttn, void *data) {
  ttn->ttn_allocator_data = data;
}

static inline void *ttn_lnk_allocator_data(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_allocator_data;
}

static inline void ttn_lnk_set_tracelevel(struct ttn_lnk_handle_t *ttn, unsigned int level) {
  ttn->ttn_tracelevel = level;
}

static inline unsigned int ttn_lnk_tracelevel(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_tracelevel;
}

static inline int ttn_lnk_station_id(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_myid;
}

static inline int ttn_lnk_next_station_id(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_to_id;
}

static inline int ttn_lnk_probing_station_id(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_probing_host;
}

static inline int ttn_lnk_is_online(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_lnk_state >= TTN_STATE_ONLINE;
}

static inline const uint8_t *ttn_lnk_mac(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_mymac;
}

static inline enum ttn_lnk_state_t ttn_lnk_state(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_lnk_state;
}

static inline const struct ttn_stats_t *ttn_lnk_stats(struct ttn_lnk_handle_t *ttn) {
  return &ttn->ttn_stats;
}

static inline ttn_bitmap_t ttn_lnk_population(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_up;
}

static inline void ttn_set_diag_event_handler(struct ttn_lnk_handle_t *ttn, ttn_diag_event_cb_t *cb, void *data) {
  ttn->ttn_diag_cb = cb;
  ttn->ttn_diag_data = data;
}

static inline const struct ttn_peer_properties_t *ttn_lnk_peer_properties(struct ttn_lnk_handle_t *ttn) {
  return ttn->ttn_peers;
}

#if defined(__cplusplus)
}
#endif

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