#ifndef BACKHAUL_TOPOLOGY_H
#define BACKHAUL_TOPOLOGY_H

#include <libubox/list.h>
#include <stdint.h>
#include <time.h>

struct tlv_device_info;
struct tlv_1905neighbor;
struct bh_topology_dev;

#define IFACE_MAX_NUM 16
#define NEIGHBORS_MAX_NUM 16

struct local_iface {
	uint8_t macaddr[6];
	uint16_t media_type;
	uint8_t number_of_neighbors;
	uint8_t neighbors_al_macs[NEIGHBORS_MAX_NUM][6];
	uint8_t neighbors_link_macs[NEIGHBORS_MAX_NUM][6];
};

 /* When populated BH link defined as in TR-181:
  * BHDevALMac/BHLocalMac() <-LinkType -< LocalMac
  * can be read. Above corresponds to:
  * parent_in_tree/parent_iface <--own_iface->media_type-< own_iface
  */
#define UNKNOWN_TREE_LEVEL -1
struct backhaul_info {
	int8_t level_in_tree;		/** total number of BH links from root node */
	uint8_t wifi_hops_from_root;	/** number of Wi-Fi BH links from root node */
	const struct bh_topology_dev *parent_in_tree;
	const struct local_iface *parent_iface;
	const struct local_iface *own_iface;
};

/** Represents single device and its relation to neighbors in BH tree. */
struct bh_topology_dev {
	struct list_head list_element;
	struct timespec last_topo_response;

	uint8_t al_macaddr[6];
	uint8_t number_of_interfaces;
	uint8_t num_of_ifaces_with_neighbors;
	struct local_iface ifaces[IFACE_MAX_NUM];
	struct backhaul_info bh_info;
};

/** Initializes internal structures.
 *  Has to be called once before any other functions are called.
 */
void init_bh_topology(void);

/** Releases all data and internal structures. */
void free_bh_topology(void);

/** Returns tree if backhaul topology tree was already build and is still valid.
 *
 *  It's undefined behaviour to read interface, neighbor and backhaul info
 *  of any bh_topology_dev when this function returns false.
 */
bool is_bh_topology_valid(void);

/** Number of devices in backhaul topology tree. */
uint32_t bh_topology_devs_number(void);

/** Returns backhaul topology device if exists in the model, NULL otherwise. */
struct bh_topology_dev *find_bh_topology_device(const uint8_t *al_macaddr);

/** Adds backhaul topology device to the model, invalidates backhaul tree. */
struct bh_topology_dev *add_bh_topology_device(const uint8_t *al_macaddr);

/** Removes backhaul topology device from the model, invalidates backhaul tree. */
void remove_bh_topology_device(const uint8_t *al_macaddr);

/** Removes all backhaul topology devices from the model, invalidates backhaul tree. */
void remove_all_bh_topology_devices(void);

/**
 * Returns true if interface information provided with tlv_device_info differs
 * from data already stored in bh_topology_dev (model).
 * To reduce time complexity, it's assumed interfaces received in TLV are always ordered
 * the same way. Also only number of interfaces and their MAC addresses are compared.
 */
bool has_interface_info_changed(const struct tlv_device_info *tlv_dev_info,
				const struct bh_topology_dev *bh_topo_dev);
/**
 * Copies interface details from tlv_device_info into bh_topology_dev.
 * Invalidates backhaul tree.
 */
void copy_interface_info_from_tlv(const struct tlv_device_info *tlv_dev_info,
				  struct bh_topology_dev *bh_topo_dev);

/**
 * Returns true if neighbor information provided with 1905 neighbor TLVs differs
 * from data already stored in bh_topology_dev (model).
 */
bool has_neighbor_info_changed(const struct tlv_1905neighbor **neighbor_tlvs,
			       const uint16_t *tlv_lengths,
			       uint8_t tlv_number,
			       const struct bh_topology_dev *bh_topo_dev);

/**
 * Copies neighbors details from 1905 neighbor TLVs into bh_topology_dev.
 * Invalidates backhaul tree.
 */
void copy_neighbor_info_from_tlvs(const struct tlv_1905neighbor **neighbor_tlvs,
				  const uint16_t *tlv_lengths,
				  uint8_t tlv_number,
				  struct bh_topology_dev *bh_topo_dev);

/**
 * Shall be called each time device provides topology response.
 */
void set_bh_toplogy_response_timestamp(struct bh_topology_dev *bh_topo_dev);

/**
 * Builds backhaul topology tree from unordered list of bh_topology_dev structs
 * by setting backhaul_info fields.
 *
 * Controller is always root node in tree. Edges between tree nodes represent
 * BH links, parent nodes provides BH links to child node - each child node
 * can have only one parent (be connected over one BH link).
 *
 * After calling it, is_bh_topology_valid() will return true, until next
 * input data change (device add/remove, interface or neighbor info change.)
 */
void build_bh_topology_tree(const uint8_t *ctrl_al_macaddr);

#endif /* BACKHAUL_TOPOLOGY_H */
