/*
 * Copyright (C) 2022 EXOLIGENT (www.exoligent.com)
 * Author: Maxime Coroyer <maxime.coroyer@exoligent.com>
 */

#ifndef __OPC_H__
#define __OPC_H__

#include <open62541/server.h>
#include "opc-fip-types.h"

#define OPC_TRANSPORT_PROFILE "http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"
#define OPC_PUB_NAME "Publisher Connection [UADP]"
#define OPC_SUB_NAME "Subscriber Connection [UADP]"
#define OPC_READER_GROUP_NAME "RG - ReaderGroup 1"
#define OPC_WRITER_GROUP_NAME "WG - WriterGroup 1"
#define OPC_DATASET_READER_NAME "DSR - DataSetReader 1"
#define OPC_DATASET_WRITER_NAME "DSW - DataSetWriter 1"

#define OPC_STR_BSZ_MAX 255
struct gw_opc_publisher {
    char net_str[OPC_STR_BSZ_MAX]; /* network interface */
    char url_str[OPC_STR_BSZ_MAX]; /* url */
    int publisher_id;
    int dataset_writer_id;
    int writer_group_id;
    int publish_period_us;
    /* objects */
    UA_NetworkAddressUrlDataType url;
    UA_NodeId co_ident;
    UA_NodeId w_group_id;
};

struct gw_opc_subscriber {
    char net_str[OPC_STR_BSZ_MAX]; /* network interface */
    char url_str[OPC_STR_BSZ_MAX]; /* url */
    int publisher_id;
    int dataset_writer_id;
    int writer_group_id;
    /* objects */
    UA_NetworkAddressUrlDataType url;
    UA_NodeId co_ident;
    UA_NodeId r_group_id;
};

struct gw_opc_rt_thread_args {
    void *pub_data;
    void *sub_data;
    UA_ServerCallback pub_callback;
    UA_ServerCallback sub_callback;
    UA_Duration interval_ms;
    UA_UInt64 *callback_id;
};

#define OPC_VAR_COUNT_MAX 500
struct gw_opc {
    UA_Server *srv;
    UA_ServerConfig *cfg;
    UA_Boolean running;
    UA_StatusCode status;
    UA_DataType *dt_types;
    UA_DataTypeMember *dt_members;
    UA_Lock mu;
    volatile int task_in_progress;
    /**
     * OPC UA Pub/Sub
     */
    /* publisher */
    struct gw_opc_publisher pub;
    /* subscriber */
    struct gw_opc_subscriber sub;
    pthread_t pubsub_thr_task;
    struct gw_opc_rt_thread_args pubsub_thr_args;
    /**
     * Thread
     */
    pthread_t thr_task;
};

UA_StatusCode opc_value_trywrite(UA_Server *srv,
    UA_QualifiedName target_name, const UA_Variant value,
    const UA_NodeId *node_id_start, UA_NodeId *node_id_found);

#endif
