#ifndef LIP_OPCUA_TREE_ITEM_H
#define LIP_OPCUA_TREE_ITEM_H


#include "lip_opcua_tree_item_acc.h"
#include "lip/app/opcua/types/lip_opcua_nodeid.h"
#include "lip/app/opcua/types/lip_opcua_datatype_descr.h"
#include "lip/app/opcua/lip_opcua_svc_proto_defs.h"
#include "lip/app/opcua/server/monitems/lip_opcua_server_monitem_cbs.h"

struct st_lip_opcua_tree_item;
struct st_lip_opcua_tree_item_ref_descr;

typedef struct {
    uint8_t  node_class;
    const struct st_lip_opcua_tree_item_ref_descr *refs;
} t_lip_opcua_tree_item_class_descr_hdr;

typedef struct st_lip_opcua_tree_item {
    t_lip_opcua_nodeid nodeid;
    t_lip_opcua_qualified_name browse_name;
    const t_lip_opcua_loc_string_ptr_list *display_name;
    const struct st_lip_opcua_tree_item_ref_descr *refs;
    const t_lip_opcua_tree_item_class_descr_hdr *class_descr_hdr;
    union {
        void *ptr;        
        uint32_t uint;
        int32_t sint;
        uint64_t uint64;
        t_lip_opcua_string_ptr str;
        const t_lip_opcua_loc_string_ptr_list *loctext;
        double vdouble;
        struct {
            const void *data;
            int32_t size;
        } carr;
    } user;
} t_lip_opcua_tree_item;





typedef struct st_lip_opcua_tree_item_descr_variable {
    t_lip_opcua_tree_item_class_descr_hdr hdr;
    const t_lip_opcua_datatype_descr *data_descr;
    struct {
        const t_lip_opcua_acc_cbs acc;
        const t_lip_opcua_tree_item_mon_cbs *mon;
    } cbs;
} t_lip_opcua_tree_item_descr_variable;


typedef struct st_lip_opcua_tree_item_descr_vartype {
    t_lip_opcua_tree_item_class_descr_hdr hdr;
    const t_lip_opcua_datatype_descr *data_descr;
    uint8_t is_abstract;
} t_lip_opcua_tree_item_descr_vartype;


typedef enum {
    LIP_OPCUA_TREE_ITEM_DATATYPE_TYPEDEF_VARIANT_NONE   = 0,
    LIP_OPCUA_TREE_ITEM_DATATYPE_TYPEDEF_VARIANT_STRUCT = 1,
} t_lip_opcua_tree_item_datatype_typedef_variant;

typedef struct st_lip_opcua_tree_item_descr_datatype {
    t_lip_opcua_tree_item_class_descr_hdr hdr;
    uint8_t is_abstract;
    uint8_t typedef_variant;
    union {
        const struct st_lip_opcua_struct_def *typedef_struct;
    };;
    //DataTypeDefinition for struct/union
} t_lip_opcua_tree_item_descr_datatype;


typedef struct st_lip_opcua_tree_item_descr_object {
    t_lip_opcua_tree_item_class_descr_hdr hdr;
    uint8_t evt_notifier_flags;
} t_lip_opcua_tree_item_descr_object;

typedef enum {
    LIP_OPCUA_TREE_ITEM_REFTYPE_FLAG_ABSTRACT = 1 << 0,
    LIP_OPCUA_TREE_ITEM_REFTYPE_FLAG_SYMMETRIC = 1 << 1,
} t_lip_opcua_tree_item_ref_descrtype_flags;

typedef struct {
    t_lip_opcua_tree_item_class_descr_hdr hdr;
    const t_lip_opcua_tree_item *base_ref;
    uint8_t flags; /* флаги из t_lip_opcua_tree_item_ref_descrtype_flags */
    const t_lip_opcua_loc_string_ptr_list inverse_name;
} t_lip_opcua_tree_item_descr_reftype;



typedef struct st_lip_opcua_tree_item_descr_objtype {
    t_lip_opcua_tree_item_class_descr_hdr hdr;
    uint8_t is_abstract;
} t_lip_opcua_tree_item_descr_objtype;



#define LIP_OPCUA_TREE_ITEM_VAR_INIT    .hdr.node_class = LIP_OPCUA_NODECLASS_VARIABLE,
#define LIP_OPCUA_TREE_ITEM_OBJECT_INIT .hdr.node_class = LIP_OPCUA_NODECLASS_OBJECT,


static inline const t_lip_opcua_tree_item_descr_variable *lip_opcua_tree_item_variable_descr(const t_lip_opcua_tree_item *item) {
    return item->class_descr_hdr->node_class == LIP_OPCUA_NODECLASS_VARIABLE ? (const t_lip_opcua_tree_item_descr_variable *)item->class_descr_hdr : NULL;
}
static inline const t_lip_opcua_tree_item_descr_object *lip_opcua_tree_item_object_descr(const t_lip_opcua_tree_item *item) {
    return item->class_descr_hdr->node_class == LIP_OPCUA_NODECLASS_OBJECT ? (const t_lip_opcua_tree_item_descr_object *)item->class_descr_hdr : NULL;
}
static inline const t_lip_opcua_tree_item_descr_reftype *lip_opcua_tree_item_reftype_descr(const t_lip_opcua_tree_item *item) {
    return item->class_descr_hdr->node_class == LIP_OPCUA_NODECLASS_REFERENCE_TYPE ? (const t_lip_opcua_tree_item_descr_reftype *)item->class_descr_hdr : NULL;
}
static inline const t_lip_opcua_tree_item_descr_vartype *lip_opcua_tree_item_vartype_descr(const t_lip_opcua_tree_item *item) {
    return item->class_descr_hdr->node_class == LIP_OPCUA_NODECLASS_VARIABLE_TYPE ? (const t_lip_opcua_tree_item_descr_vartype *)item->class_descr_hdr : NULL;
}
static inline const t_lip_opcua_tree_item_descr_datatype *lip_opcua_tree_item_datatype_descr(const t_lip_opcua_tree_item *item) {
    return item->class_descr_hdr->node_class == LIP_OPCUA_NODECLASS_DATA_TYPE ? (const t_lip_opcua_tree_item_descr_datatype *)item->class_descr_hdr : NULL;
}
static inline const t_lip_opcua_tree_item_descr_objtype *lip_opcua_tree_item_objtype_descr(const t_lip_opcua_tree_item *item) {
    return item->class_descr_hdr->node_class == LIP_OPCUA_NODECLASS_OBJECT_TYPE ? (const t_lip_opcua_tree_item_descr_objtype *)item->class_descr_hdr : NULL;
}



#endif // LIP_OPCUA_TREE_ITEM_H
