#ifndef LIP_OPCUA_UADP_DEFS_H
#define LIP_OPCUA_UADP_DEFS_H

#include "lip/lip_defs.h"
#include "lip/app/opcua/types/lip_opcua_tstmp.h"
#include <string.h>

/** Идентификатор источника публикаций OPC-UA (целое число или строка) */
typedef struct {
    uint8_t is_valid; /**< Признак, действительна ли информация в данной структуре */
    uint8_t is_str;   /**< Признак, задан идентификатор строкой (true) или целым числом */
    int16_t len;      /**< Размер идентификатора в байтах. Если целое число, то может быть 1, 2, 4 или 8.
                           Если строка - длина строки (строка может не содержать завершающий 0) */
    union {
        uint64_t intval;    /**< Если идентификатор задан целым числом, то младшие len байт данного поля содержит значение идентификатора */
        const uint8_t *str; /**< Если идентификатор задан строкой, то указывает на начало строки длиной в len байт, которая содержит идентификатор */
    };
} t_lip_uadp_pubid;

typedef struct {
    uint32_t mj;
    uint32_t mn;
} t_lip_opcua_version;


typedef enum {
    LIP_UADP_DS_FLAG_SEQNUM_VALID           = 1 << 1,
    LIP_UADP_DS_FLAG_TSTMP_VALID            = 1 << 2,
    LIP_UADP_DS_FLAG_STATUS_VALID           = 1 << 3,
    LIP_UADP_DS_FLAG_VERSION_MJ_VALID       = 1 << 4,
    LIP_UADP_DS_FLAG_VERSION_MN_VALID       = 1 << 5,
} t_lip_uadp_ds_flags;


typedef struct {
    uint16_t flags;
    uint16_t writer_id;
#if LIP_OPCUA_UADP_DS_SEQNUM
    uint16_t seqnum;
#endif
#if LIP_OPCUA_UADP_DS_STATUS
    uint16_t status;
#endif
#if LIP_OPCUA_UADP_DS_VERSION
    t_lip_opcua_version version;
#endif
#if LIP_OPCUA_UADP_DS_TSTMP
    t_lip_opcua_tstmp  ts;
#endif
    const uint8_t *data_ptr;
    uint16_t  data_size;
} t_lip_uadp_ds_info;


typedef enum {
    LIP_UADP_GROUP_FLAG_ID_VALID            = 1 << 1,
    LIP_UADP_GROUP_FLAG_SEQNUM_VALID        = 1 << 1,
    LIP_UADP_GROUP_FLAG_TSTMP_VALID         = 1 << 2,
    LIP_UADP_GROUP_FLAG_VERSION_VALID       = 1 << 3,
    LIP_UADP_GROUP_FLAG_NETMSG_NUM_VALID    = 1 << 4,
} t_lip_uadp_group_flags;


typedef struct {
    uint16_t flags;
    uint16_t id;
#if LIP_OPCUA_UADP_GROUP_NETMSGNUM
    uint16_t netmsg_num;
#endif
#if LIP_OPCUA_UADP_GROUP_SEQNUM
    uint16_t seqnum;
#endif
#if LIP_OPCUA_UADP_GROUP_VERSION
    uint32_t version;
#endif
#if LIP_OPCUA_UADP_GROUP_TSTMP
    t_lip_opcua_tstmp  tstmp;
#endif
} t_lip_uadp_group_info;


static inline bool lip_uadp_pubid_is_valid(const t_lip_uadp_pubid *pubid) {
    return pubid->is_valid && (pubid->is_str ? (pubid->len > 0) && (pubid->str != NULL) :
                                   (pubid->len == 1) || (pubid->len == 2) || (pubid->len == 4) || (pubid->len == 8));
}

static inline void lip_uadp_pubid_init_str(t_lip_uadp_pubid *pubid, const char *str, int16_t len) {    
    pubid->is_str = 1;
    pubid->len = len < 0 ? (int16_t)strlen(str) : len;
    pubid->str = (const uint8_t *)str;
    pubid->is_valid = pubid->len > 0;
}

#endif // LIP_OPCUA_UADP_DEFS_H
