#ifndef __UA_SERVER_H
#define __UA_SERVER_H
#include "sqlite3.h"
/***************HEADER FILES****************/


#include "../prot_transf.h"
#include "open62541.h"
#include "../tag.h"

#if defined(__arm__)
#define ENCODE_TIME_UA(timestamp) ((timestamp+11644473600LL)*1000LL*1000LL*10LL)
#define DECODE_TIME_UA(timestamp) (timestamp/1000LL/1000LL/10LL-11644473600LL)
#else
#define ENCODE_TIME_UA(timestamp) ((timestamp+11644473600L)*1000L*1000L*10L)
#define DECODE_TIME_UA(timestamp) (timestamp/1000L/1000L/10L-11644473600L)
#endif

// #ifndef EN_OPCUA
// #define EN_OPCUA
// #endif

#ifdef EN_OPCUA

typedef struct 
{
    char *data;
    int data_len;
}function_data;

typedef int (*ua_cb)(function_data *input,int input_num,function_data *output,int *output_num); //output的data在用完会被自动释放,在处理函数中需要申请内存

#define TDENGINEFILE "/mnt/ssd/taos"

#ifdef EN_EMS
#define DBFILE "/app/database/opc-history.db"
#define PERSISTENCE_DB_NAME "data_persistence"
#endif

#ifdef EN_LC
#define DBFILE "/app/database/lc_opc-history.db"
#define PERSISTENCE_DB_NAME "lc_data_persistence"
#endif

#define MAX_EX_NUM 5

typedef int (*totalOnWrite)(char *name,void *value);
typedef int (*totalOnRead)(char *name,void *value);
typedef struct total_cb
{
    totalOnWrite onWrite;
    totalOnRead onRead;
    int data_type; //0int 1float 2string
}total_cb_t;


#define NAME_INDEX 0
#define TYPE_INDEX 1
#define NUM_INDEX  2

#define MASTER_NAME "主柜"
#define SLAVE_NAME  "从柜"

typedef struct
{
    unsigned short port;//port已被弃用 自动分配端口
    bool open_history;
    int point_num;
    int history_num;
    char *history_db_pwd;
    long long history_database_size; //数据库大小 默认1g 单位kb
    bool en_encryption;
    bool data_persistence; //数据持久化 0不启用1启用 

    char *someExInfo[MAX_EX_NUM]; //扩展信息  0 名字 1主从 2编号 3网口名 4密码 
    // int ExInfoNum;            //扩展数量
}UA_BASE_DATA;


typedef struct
{
    UA_Server *ua_server; /* OPC UA server pointer */    
    hash_intptr_t *discover_hash; //用来插入发现的服务器
    // pthread_mutex_t mutex;
    
    int gathering_num;
    //历史数据
	UA_HistoryDataGathering gathering;
	UA_HistorizingNodeIdSettings setting;
	bool isUAHasHistoryData;

    int alarm_info_num;
    UA_NodeId outId; //事件节点  如果需要多的 可以用数组
    UA_NodeId eventType; //事件类型节点 如果需要多的 可以用数组 
   // UA_UInt64 callbackId; //定时任务id
    UA_BASE_DATA *user_data; //用户配置参数之类的
    int ems_heartbeat;
    int ems_online;
    int disable;
}UA_SERVER_PARAM;

typedef struct ua_clinet_info_t
{
    UA_Client *clientRegister;
    uint64_t cb_id;
    int valid;
}ua_clinet_info;

typedef struct ua_custom_enum_map
{
    int value;
    char name[48];
}ua_custom_enum_map;

typedef struct ua_custom_enum
{
    char *name;
    UA_NodeId typeId;
    ua_custom_enum_map *enum_arr;
}ua_custom_enum_type;


int ua_server_add_dev_node(void *_var,channel_t *channel, device_t *dev);
void set_double_to_node(UA_SERVER_PARAM *ua_ser_para,UA_NodeId nodeId,double value_f,int tag_state_code);
void set_int_to_node(UA_Server *server,UA_NodeId nodeId,int value_i,int tag_state_code);
int get_a_value_float(UA_Server *server,UA_NodeId nodeId,float *data_f);
int get_a_value_int(UA_Server *server,UA_NodeId nodeId,int *data_i);
ua_custom_enum_type *ua_creat_custom_enum(UA_Server *server, char *name, char *enum_discribe);
char *get_enum_value_string(void *enum_type, int value);
int ua_add_custom_enum(UA_Server *server, const UA_NodeId typeId, const char *name, UA_Int32 val);
void historyCycleCallback(UA_Server *server, void *data) ;
int sqlite3_get_table_list_and_del_by_time(sqlite3 *db, time_t end_time);

int UA_Server_addRepeatedCallback1(UA_SERVER_PARAM *ua_param, UA_ServerCallback callback,
                              void *data, UA_Double interval_ms,
                              UA_UInt64 *callbackId);

int add_alarm_num_to_node(proto_forward_t *var, device_t *dev, char *node_name, char *node_disp_name,
               total_cb_t *total_cb);
               
void stopua();
/**
 * 启动ua执行线程
 * 
*/
void ua_server_thread_start(UA_SERVER_PARAM *ua_param);

/**
 * 停止ua执行线程
 * 
*/
void ua_server_thread_stop(UA_SERVER_PARAM *ua_param);
/**
 * 初始化uaserver 
 * port 端口号
 * open_history 是否开启历史数据 1开启
 * point_num 历史数据点位数
 * history_num 历史数据存储条数
 * history_db_pwd历史数据数据库路径和名称
 * 
*/
UA_SERVER_PARAM *ua_server_init(UA_BASE_DATA *data_ua);


/**
 * 根据name在节点下 注册方法
 * 注意 ua_cb回调函数的输出指针需要在回调函数内申请内存 之后会被自动释放
 * 
*/


int creat_a_base_file(UA_SERVER_PARAM *ua_param,char *nodeId,char *name,UA_NodeId *node_id);

int creat_a_base_string(UA_SERVER_PARAM *ua_param,char *nodeId,char *name,UA_NodeId *node_id,UA_NodeId parent_id,char *defaultString);

int creat_a_base_double(UA_SERVER_PARAM *ua_param,char *nodeId,char *name,UA_NodeId *node_id,UA_NodeId parent_id,char *defaultString);

int ua_server_add_string_node(proto_forward_t *var, device_t *dev, char *node_name, char *node_disp_name, char *v_string);

int addDownloadMethod(UA_SERVER_PARAM *_var,UA_NodeId parent_noteid) ;

int addUploadMethod(UA_SERVER_PARAM *_var,UA_NodeId parent_noteid) ;
int ua_server_add_data_item(proto_forward_t *var, device_t *dev, tag_t *tag,int tag_type,int readonly, sqlite3 *db);
void add_float_to_node(UA_Server *server,UA_NodeId parentNodeId,UA_NodeId *NodeId,char *name,char*displayName);
int add_int_to_node(UA_Server *server,UA_NodeId parentNodeId,int readonly,UA_NodeId *NodeId,char *name,char*displayName,total_cb_t *total_cb);
int ua_add_file(UA_Server *server,UA_NodeId parentNodeId,UA_NodeId *NodeId,char *name,char*displayName);
int creat_a_rw_string(UA_SERVER_PARAM *ua_param,char *displayname,char *name,UA_NodeId *node_id,UA_NodeId parent_id,char *defaultString,total_cb_t *total_cb);
void set_char_to_node(UA_Server *server,UA_NodeId nodeId,char *valuec) ;
void add_time_to_node(UA_Server *server,UA_NodeId parentNodeId,int readonly,UA_NodeId *NodeId,char *name,char*displayName);
UA_NodeId *ua_server_add_dir_for_dev(void *par, char *dev_no, const char *node, char *description, char *displayName);
UA_NodeId ua_server_add_single_dev_node(void *_var, device_t *dev, const char *dev_no, const char *description, const char *displayName);
void addValueCallbackToVariable(UA_Server *server,UA_NodeId currentNodeId);
// int addMethodToNodeNoInput(UA_SERVER_PARAM *_var,UA_NodeId parent_noteid,char *functionName,ua_cb method);
#endif
#endif /* __UA_SERVER_H */

