#ifndef __PUBSUB_H__
#define __PUBSUB_H__

#include <open62541/server.h>
#include <open62541/plugin/log_stdout.h>

#include <quickjs/quickjs.h>

#ifndef DLL_PUBLIC
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#endif

#define countof(x) (sizeof(x) / sizeof((x)[0]))

#define DATA_SET_WRITER_ID 1
#define WRITER_GROUP_ID 1

#define MAX_STR_SIZE 1024

struct strNode {
  char *str;
  struct strNode *next;
};
typedef struct {
  struct strNode *head;
  struct strNode *tail;
} StrQueue;

typedef struct {
    UA_UInt16 id;
    UA_Double latitude;
    UA_Double longitude;
    UA_Double altitudeAbs;
    UA_Double altitudeRel;
    UA_Int64  timestamp;
    UA_Float  yaw;
    UA_Float  speed;
    UA_Float  climbRate;
    StrQueue receiveMessageQueue;
    pthread_mutex_t messageMutex;
    StrQueue receiveLogQueue;
    pthread_mutex_t logMutex;
} JSDroneData;

typedef struct {
    UA_Double latitude;
    UA_Double longitude;
    UA_Double altitude;
    UA_Int64 timestamp;
} JSPositionData;

typedef union {
    struct {
        UA_UInt32 message;
        UA_UInt32 positionArray;
        UA_UInt32 speedArray;
        UA_UInt32 log;
    };
    UA_UInt32 getter[4];
 } PubsubVariableIDs;

typedef struct {
    char*       name;
    char*       typeName;
    UA_NodeId   typeNodeId;
    char*       description;
    void*       value;
    int         type;
    UA_Byte     builtInType;
    UA_Int32    valueRank;
    size_t      arrayDimensionsSize;
    UA_UInt32*  arrayDimensions;
    union {
        void*     (*getArray)(void);
        UA_String (*getString)(void);
    } getter;
} VariableData;

typedef struct {
    size_t nbVariable;
    VariableData *variableArray;
} VariableStruct;

int runPubsub(const UA_Logger *logger, UA_String *transportProfile,
              UA_NetworkAddressUrlDataType *networkAddressUrl,
              VariableStruct variables, UA_UInt32 id,
              VariableStruct *pubsubVariableArray,
              PubsubVariableIDs *pubsubIDArray,
              UA_UInt32 nbReader, UA_Duration interval,
              UA_UInt16 (*get_reader_id)(UA_UInt32 nb),
              VariableData (*get_value)(UA_String identifier),
              void (*update)(UA_UInt32 id, const UA_DataValue*, bool print),
              UA_Boolean *running);

UA_String get_message(void);

UA_String get_log(void);

UA_UInt16 get_drone_id(UA_UInt32 nb);

VariableData pubsub_get_value(UA_String identifier);

DLL_PUBLIC JSModuleDef *js_init_module(JSContext *ctx, const char *module_name);

#endif /* __PUBSUB_H__ */