#ifndef LIP_OPCUA_SERVER_MONITEM_H
#define LIP_OPCUA_SERVER_MONITEM_H

#include "lip/app/opcua/types/lip_opcua_base_types.h"
#include "lip/app/opcua/types/lip_opcua_readvalueid.h"
#include "lip/app/opcua/server/tree/lip_opcua_tree_item.h"
#include "lip_opcua_server_monitem_params.h"
#include "lip_opcua_server_monitem_notification.h"
#include "lip_opcua_server_monitem_queue.h"
#include "ltimer.h"

struct st_lip_opcua_session_ctx;
struct st_lip_opcua_srvsub_ctx;


typedef struct {
    t_lip_opcua_read_value_id rd_value_id;
    t_lip_opcua_monitoring_params mon_params;
    t_lip_opcua_monmode mon_mode;
    t_lip_opcua_ret_tstmp_types tstmps;
    t_lclock_ticks req_time;
} t_lip_opcua_monitem_create_params;


typedef struct st_lip_opcua_monitem_ctx {
    const t_lip_opcua_tree_item *item;
    t_lip_opcua_nodeid node_id; /* node-id требуется для возможности отслеживания пересоздания элемента */
    t_lip_opcua_intid id;
    t_lip_opcua_attr_id attr;
    t_lip_opcua_item_read_params rd_params;
    t_lip_opcua_monmode mon_mode;
    t_lip_opcua_intid   client_handle;
    t_ltimer sampling_tmr;
    //t_lip_opcua_filter filter;
    t_lip_opcua_monitem_notification_ctx notifications;
    const t_lip_opcua_tree_item_mon_cbs *mon_cbs;
    union {
        void *user_ctx;
#if LIP_OPCUA_SERVER_MONITEM_USER_DATA_MAX_SIZE > 0
        /* Вместо указателя на пользовательские данные можно хранить их
         * непосредственно внутри monitem. В этом случае должен быть
         * настроен размер не меньше макисимального хранимого размера */
        uint8_t user_data[LIP_OPCUA_SERVER_MONITEM_USER_DATA_MAX_SIZE];
#endif
    };
} t_lip_opcua_monitem_ctx;


void lip_opcua_server_monitem_init(void);

t_lip_opcua_err lip_opcua_server_monitem_create(struct st_lip_opcua_session_ctx *session,
                                                struct st_lip_opcua_srvsub_ctx *sub,
                                                t_lip_opcua_monitem_create_params *params,
                                                t_lip_opcua_monitem_ctx **pmonitem);
void lip_opcua_server_monitem_delete(t_lip_opcua_monitem_ctx *monitem);
void lip_opcua_server_monitem_pull(t_lip_opcua_monitem_ctx *monitem, struct st_lip_opcua_session_ctx *session, struct st_lip_opcua_srvsub_ctx *sub, t_lclock_ticks time);
t_lip_opcua_err lip_opcua_server_monitem_sample(t_lip_opcua_monitem_ctx *monitem, struct st_lip_opcua_session_ctx *session, t_lclock_ticks time);
t_lip_opcua_err lip_opcua_server_monitem_set_monmode(t_lip_opcua_monitem_ctx *monitem, t_lip_opcua_monmode mode, t_lclock_ticks req_time);
t_lip_opcua_err lip_opcua_server_monitem_set_monitoring_params(struct st_lip_opcua_srvsub_ctx *sub, t_lip_opcua_monitem_ctx *monitem, t_lip_opcua_monitoring_params *params, t_lip_opcua_ret_tstmp_types tstmps, t_lclock_ticks req_time);
void lip_opcua_server_monitem_notification_pubrdy(t_lip_opcua_monitem_ctx *monitem);
t_lip_opcua_notification_info *lip_opcua_server_monitem_next_notification(t_lip_opcua_monitem_ctx *monitem);
void lip_opcua_server_monitem_drop_notification(t_lip_opcua_monitem_ctx *monitem);

static LINLINE uint16_t lip_opcua_server_monitem_pubrdy_items_cnt(t_lip_opcua_monitem_ctx *monitem) {
    return monitem->notifications.pub_rdy;
}
#if LIP_OPCUA_SERVER_MONITEM_USER_DATA_MAX_SIZE > 0
static LINLINE void *lip_opcua_server_monitem_user_data(t_lip_opcua_monitem_ctx *monitem) {
    return &monitem->user_data[0];
}
#endif
static LINLINE uint32_t lip_opcua_server_monitem_sampling_interval(t_lip_opcua_monitem_ctx *monitem) {
    return ltimer_interval_ms(&monitem->sampling_tmr);
}

void lip_opcua_server_monitem_process_item_add(const t_lip_opcua_tree_item *item);
void lip_opcua_server_monitem_process_item_delete(const t_lip_opcua_tree_item *item);



#endif // LIP_OPCUA_SERVER_MONITEM_H
