

#ifndef __MQTT_CLIENT_C_
#define __MQTT_CLIENT_C_

/* Library Header files */
#include "stdio.h"
#include "stdint.h"
#include "stddef.h"

/* MQTT Specific header files */
#include "MQTTReturnCodes.h"
#include "MQTTMessage.h"
#include "MQTTPacket.h"

/* AWS Specific header files */
#include "aws_iot_config.h"

/* Platform specific implementation header files */
#include "network_interface.h"
#include "timer_interface.h"

#define MAX_PACKET_ID 65535
#define MAX_MESSAGE_HANDLERS AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS

#define MIN_RECONNECT_WAIT_INTERVAL AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
#define MAX_RECONNECT_WAIT_INTERVAL AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL

void NewTimer(Timer *);

typedef struct Client Client;

typedef struct MessageData MessageData;

typedef void (*messageHandler)(MessageData *);
typedef void (*pApplicationHandler_t)(void);
typedef void (*disconnectHandler_t)(void);
typedef int (*networkInitHandler_t)(Network *);

struct MessageData {
    MQTTMessage *message;
    MQTTString *topicName;
    pApplicationHandler_t applicationHandler;
};

typedef struct
{
    unsigned char  Version;
    unsigned char  MsgId;
    unsigned char  MsgCode;
    unsigned char  OptNum;
    unsigned short Payloadlen;     //msg payload len + opt len + opt head len
    unsigned char  TotalMsgCrc[2];
}AC_MessageHead;

unsigned int  ACEventBuildMsg(unsigned char u8MsgCode,
                                   unsigned char u8MsgId,
                                   unsigned char *pu8Msg,
                                   unsigned short *pu16Len,
                                   unsigned char *pu8Payload,
                                   unsigned short u16PayloadLen);

MQTTReturnCode MQTTConnect(Client *c, MQTTPacket_connectData *options);
MQTTReturnCode MQTTPublish (Client *, const char *, MQTTMessage *);
MQTTReturnCode MQTTSubscribe(Client *c, const char *topicFilter, QoS qos,
                             messageHandler messageHandler, pApplicationHandler_t applicationHandler);
MQTTReturnCode MQTTResubscribe(Client *c);
MQTTReturnCode MQTTUnsubscribe(Client *c, const char *topicFilter);
MQTTReturnCode MQTTDisconnect (Client *);
MQTTReturnCode MQTTYield (Client *, uint32_t);
MQTTReturnCode MQTTAttemptReconnect(Client *c);

uint8_t MQTTIsConnected(Client *);
uint8_t MQTTIsAutoReconnectEnabled(Client *c);

void setDefaultMessageHandler(Client *, messageHandler);
MQTTReturnCode setDisconnectHandler(Client *c, disconnectHandler_t disconnectHandler);
MQTTReturnCode setAutoReconnectEnabled(Client *c, uint8_t value);

MQTTReturnCode MQTTClient(Client *, uint32_t, unsigned char *, size_t, unsigned char *,
                          size_t, uint8_t, networkInitHandler_t, TLSConnectParams *);

uint32_t MQTTGetNetworkDisconnectedCount(Client *c);
void MQTTResetNetworkDisconnectedCount(Client *c);

struct Client {
    uint8_t isConnected;
    uint8_t wasManuallyDisconnected;
    uint8_t isPingOutstanding;
    uint8_t isAutoReconnectEnabled;

    uint16_t nextPacketId;

    uint32_t commandTimeoutMs;
    uint32_t keepAliveInterval;
    uint32_t currentReconnectWaitInterval;
    uint32_t counterNetworkDisconnected;

    size_t bufSize;
    size_t readBufSize;

    unsigned char *buf;  
    unsigned char *readbuf;

    TLSConnectParams tlsConnectParams;
    MQTTPacket_connectData options;

    Network networkStack;
    Timer pingTimer;
    Timer reconnectDelayTimer;

    struct MessageHandlers {
        const char *topicFilter;
        void (*fp) (MessageData *);
        pApplicationHandler_t applicationHandler;
        QoS qos;
    } messageHandlers[MAX_MESSAGE_HANDLERS];      /* Message handlers are indexed by subscription topic */
    
    void (* defaultMessageHandler) (MessageData *);
    disconnectHandler_t disconnectHandler;
    networkInitHandler_t networkInitHandler;
};

#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}

#endif
