/*!
 * \file msg_impl.h
 *
 * Contain all the implementation specific types
 *
 * \author: Christos Choutouridis 8997 <cchoutou@ece.auth.gr>
 */

#ifndef __msg_impl__
#define __msg_impl__

#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <sys/time.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>

/*!
 * Hard-coded AEM list
 */
#define AEMLIST_0 { 7700, 8261, 8765, 8844, 8880, 8861, 8877, 8941, 8934, 8997 }
#define AEMLIST_1 { 8918, 8929, 8997, 8880, 8844, 8861 }

#define AEMLIST         AEMLIST_0
#define AEMLIST_SIZE    (10)

/*!
 * General options
 */
//! @{
#define  MSG_TEXT_SIZE        256         //!< Maximum size of each message
#define  MSG_LIST_SIZE        2000        //!< Maximum size of message history buffer
#define  DEVICE_LIST_SIZE     200         //!< Maximum number of the device in listener's queue

#define  MSG_DELIMITER        '_'         //!< Message delimiter
#define  ADHOC_NET_A          10          //!< [A.B.C.D]
#define  ADHOC_NET_B           0
#define  ADHOC_NET_C           0
#define  ADHOC_NET_D           0

#define  MESSAGE_BODY         "The ships hung in the sky in much the same way that bricks don't!"
//! @}

/*!
 * Helper macros
 */

/*!
 * Messenger types
 */

//! @{

/*!
 * Application status type
 */
typedef enum {
   MSG_OK =0,  //!< Indicate success
   MSG_ERROR   //!< Indicate error
} status_t;

typedef  bool        bool_t;        //!< Boolean type
typedef  char        char_t;        //!< Application wide character type
typedef  int32_t     iter_t;        //!< General iterator type
typedef  uint32_t    aem_t;         //!< AEM data type
typedef  int64_t     tstamp_t;      //!< UNIX time in 64 bit wide signed integer
typedef  aem_t       devAEM_t;      //!< device as AEM type
/*!
 * device as IP type
 */
typedef struct {
   uint16_t A, B, C, D;             //!< IP octets
}devIP_t;

typedef  double      fpdata_t;      //!< Select floating point data type for the application

// Syntactic sugar types
typedef struct sockaddr_in    sockaddr_in_t;    //!< internet socket address type definition
typedef struct sockaddr       sockaddr_t;       //!< general socket address type definition
typedef struct timeval        timeval_t;        //!< general timeval type definition

/*!
 * AEM list for our mesh network
 */
typedef struct {
   devAEM_t dev;     //!< The device
   bool_t   onRange; //!< Flag to indicate if the device is on range
   tstamp_t begin;   //!< First time we had answer from the device on ping
   tstamp_t end;     //!< Last time we had answer from the device on ping
} devList_t;

extern devList_t devList[];

/*!
 * \brief
 *    Core message representation as it described in the requirements
 *
 * Object of this type constructed upon creation or when receiving a message.
 * \note
 *    associate functions -- mutable-like interface:
 *    \sa cMsg_parse() used for parsing and creation
 *    \sa cMsg_getFromAEM() used as fromAEM getter
 *    \sa cMsg_getToAEM() used as toAEM getter
 *    \sa cMsg_getTs() used as timestamp getter
 *    \sa cMsg_getText() used as text getter
 */
typedef struct {
   devAEM_t    from;       //!< sender's AEM
   devAEM_t    to;         //!< destination AEM
   tstamp_t    ts;         //!< UNIX timestamp compatible
   char_t      text[MSG_TEXT_SIZE];    //!< The actual message stream
} cMsg_t;


/*!
 * \brief
 *    Mid and application layer message representation
 *
 * This type
 */
typedef struct {
   devAEM_t    sender;                    //!< The sender's device
   bool_t      recipients[AEMLIST_SIZE];  //!< List of all devices the message has reached.
                                          //! Used as pair mapped in devList array, so each slot here corresponds in
                                          //! the same AEM in devList.
   cMsg_t      cMsg;                      //!< actual message payload
} msg_t;

typedef iter_t mIter_t;       //!< message list iterator type
typedef iter_t dIter_t;       //!< device list iterator type

/*!
 * \brief Message list
 *
 * This holds the last \a MSG_LIST_SIZE messages exchanged from this
 * device(including the ones we have create).
 *
 * With this we create a 2 dimensional map of msg/dev where each item
 * of the list is linked with all the devices reached by us as a fwd-list.
 * The items on the msgList are:
 *  - Messages we create
 *  - Messages received by the listener
 *
 * Here we define 2 directions for iteration. The message direction and the device
 * direction.
 *
 * Every node on the msgList.m array represents a message. Every node in the device
 * list inside msgList[m].recipients represent devices we don't anymore need to send
 * the current message to them.
 *
 * Layout example:
 *
 *           msgList.m
 *                    dev1 dev2 dev3 ...
 *             [ 0 ]  [ ]  [x]  [ ]       <-- x marks "message has been send"
 *         |   [ 1 ]  [x]  [x]  [ ]       <-- x marks "message has been send"
 *   time  |   [ 2 ]
 *   [*1]  |   [ 3 ]       ...
 *        \|/
 *              ...
 *
 *             [MAX]
 *
 * [*1]: msgList is actually implemented as a ring buffer so in that
 *       content, "time is a loop".
 */
typedef struct {
   msg_t    m[MSG_LIST_SIZE];    //!< The actual data representation
   mIter_t  first;               //!< A ring buffer iterator for begin()
   mIter_t  last;                //!< A ring buffer iterator marking the last item on .m
   size_t   size;
} msgList_t;

//! @}




/*!
 * Application settings
 */
//! @{

/*!
 * Statistical data type
 */
typedef struct {
   uint32_t    totalMsg;         //!< Total messages processed (both incoming and created)
   uint32_t    duplicateMsg;     //!< Incoming duplicate messages
   uint32_t    forMeMsg;         //!< Incoming messages for me
   uint32_t    myMsg;            //!< Messages created by me
   uint32_t    inDirectMsg;      //!< Incoming messages created by the sender for me
   uint32_t    outDirectMsg;     //!< Outgoing messages from me for the recipient

   fpdata_t    avMsgSize;        //!< average message payload size
   fpdata_t    avTimeToMe;       //!< average time to me
} stats_t;

extern stats_t stats;

/*!
 * Verbose level enumerator for settings
 */
typedef enum {
   OUTLEVEL_0,    //!< Output only results [default]
   OUTLEVEL_1,    //!< Output results and every message also
   OUTLEVEL_2     //!< Debug level, use with care!
}outLevel_en;


/*!
 * Application settings
 */
typedef struct {
   devAEM_t          me;               //!< Who Am I
   uint16_t          port;             //!< Application port
   time_t            seekerInterval;   //!< sleep time for seeker
   time_t            msgIntervalMin;   //!< minimum sleep time for client
   time_t            msgIntervalMax;   //!< maximum sleep time for client
   outLevel_en       outLevel;         //!< Verbose level
   time_t            pingTimeout;      //!< Ping timeout
   timeval_t         sendTimeout;      //!< Send and select timeout
   bool_t            trackTime;        //!< Track message timing flag
}settings_t;

extern settings_t settings;

/*!
 * Helper macro to setup default settings to application
 */
#define settings_init(s) s = {         \
   .me = 8997,                         \
   .port = 2288,                       \
   .seekerInterval = 30,               \
   .msgIntervalMin = 60,               \
   .msgIntervalMax = 300,              \
   .outLevel = OUTLEVEL_1,             \
   .pingTimeout = 1,                   \
   .sendTimeout = {4, 0},              \
   .trackTime = false                  \
}

//! @}

#endif /* __msg_impl__ */
