#ifndef PROTO_FORWARD__H__
#define PROTO_FORWARD__H__
#include "tag.h"
#include "opcua/ua-server.h"
#include "modbus_tcp_ser.h"
#include "lnxall_buffer.h"
#include "business_log.h"
#define DEV_ONLIEN_TAG_INDEX 0 //在线状态的tag存放位置
#define DEV_OFFLINE_COUNT 10

#define MODBUS_MAX_POINT_ADDR 65534
#define MODBUS_MAX_DEV_ADDR 255

#define YDT1363_MIN_DEV_ADDR 0
#define YDT1363_MAX_DEV_ADDR 255

typedef int (*each_tag_cb)(tag_t *tag,void *contex);
typedef enum 
{
    OFFLINE = 0,
    ONLINE
}ONILE_STATE;

/**
 * log_lv 使能数采log等级    
 *     LOG_EMERG      system is unusable
 *     LOG_ALERT      action must be taken immediately
 *     LOG_CRIT       critical conditions
 *     LOG_ERR        error conditions
 *     LOG_WARNING    warning conditions
 *     LOG_NOTICE     normal, but significant, condition
 *     LOG_INFO       informational message
 *     LOG_DEBUG      debug-level message
 * enable_open_ua 是否是能 opc-ua
 * ua_base_data opc-ua参数，内部会copy一份到proto_forward_t->ua_server_param  ***不写使用默认参数
 * enable_modbus_server 是否使能modbusserver 
 * modbus_ser_data modbusserver的map路径等参数 ***此参数必填
 * 
*/
typedef struct
{
    // int log_lv;
#ifdef EN_OPCUA
    bool enable_open_ua; 
    UA_BASE_DATA ua_base_data;
#endif
    int db_update_interval;
    bool enable_modbus_server;
    MODBUS_SERVER_BASE_PARAM modbus_ser_data;
}proto_forward_param_t;

/**
 * 初始化采集信息 成功返回句柄 失败返回NULL
*/
proto_forward_t *proto_forward_creat(proto_forward_param_t *proto_forward_param);


/**
 * 根据配置文件创建设备模板
 * 
*/

int load_device_cfg(proto_forward_t *var,char *device_config_pwd, int is_file);


/**
 * 启动proto_forward
 * 传入 proto_forward_init 返回的指针
 * 
*/
int proto_forward_schedule(proto_forward_t *proto_forward_p);

/**
 * 停止proto_forward
 * 返回0
 * 
*/
int proto_forward_schedule_stop();

/**
 * 调用上行注册的回调函数
 *  数据改变可主动调用此函数 刷新上行modbusserver和opc等注册的回调函数
*/

void reflush_data_up(tag_t* tag); 

/**
 * read_data_form_tag_by_name
 * 根据 name 读取tag值
 * 
 * //返回值 -1 未找到tag
 * data_type TYPE_TAG_INT 和TYPE_TAG_FLOAT 要读的数据的类型 和tag的类型无关 会从tag的数据类型 自动转化需要的类型
 * 
*/
int read_data_form_tag_by_name(proto_forward_t *var,char* name,int data_type,tag_value_t *tag_val);


/**
 * write_data_to_tag_by_name
 * 根据 name 写入tag值
 * 
 * //返回值 -1 未找到tag -2队列数据太多
 * data_type TYPE_TAG_INT 和TYPE_TAG_FLOAT 写入数据的类型 和tag的类型无关 会自动转化为tag的数据类型的数据
 * 
*/
int write_data_to_tag_by_name(proto_forward_t *var,char *name,tag_value_t *tag_val) ;

/**
 * check_tag_by_name
 * 根据 name 判断tag是否存在
 * 
 * //返回值 true 存在 false不存在
 *
 * 
*/
bool check_tag_by_name(proto_forward_t *var,char* name);

/**
 * 根据tag注册变化回调
 * 
*/
int register_data_collect_cb_by_tag(proto_forward_t *var,tag_t *tag,tag_get_data_cb tag_get_data_cb,void *context);


/**
 * 注册一个数据刷新callback
 * 
*/
int register_data_flush_cb_by_tag(proto_forward_t *var,tag_t *tag,tag_get_data_cb tag_get_data_cb,void *context);

/**
 * 根据name注册采集完成进行的回调函数
 * 返回 0成功 -1 回调数量超过上限  -2没找到tag 
 * 
*/

int register_data_collect_cb_by_name(proto_forward_t *var,char *name,tag_get_data_cb tag_get_data_cb,void *context) ;


int register_data_flush_cb_by_name(proto_forward_t *var,char *name,tag_get_data_cb tag_get_data_cb,void *context);
/**
 * 
 * 根据name获取char值从user_def 没获取到返回null  这个指针指向 user_def的原有数据不需要释放
 * 
*/
char* find_char_in_user_def(device_t *dev_ptr, const char *name); 

/**
 * 
 * 根据name获取int值从user_def
 * 字符串中的类型不一致会强制转换成需要的类型 未获取到返回默认值 default_val
 * 
*/
int find_int_in_user_def(device_t *dev_ptr, const char *name, int default_val); 


/**
 * 
 * 根据name获取float值从user_def
 * 字符串中的类型不一致会强制转换成需要的类型 未获取到返回默认值 default_val
 * 
*/
float find_float_in_user_def(device_t *dev_ptr, const char *name, float default_val) ;

/**
 * 根据name找到tag
*/
tag_t *find_tag_by_name(proto_forward_t *var,char *name) ;
/**
 * 根据设备no和内部的节点名找到tag
*/
tag_t *find_tag_by_dev_and_node(proto_forward_t *var, char *dev_no, char *node);
/**
 * 检查设备在线状态
*/
void check_online_state(device_t *dev_ptr);

/**
 * 刷新设备在线时间
*/
void refresh_online_state(device_t *dev_ptr) ;

/**
 * 刷新设备自定义点位状态
*/
void refresh_special_state(device_t *dev_ptr,int now_state,int tag_id);

/**
 * 
 * 读取在线状态 1在线
*/
int check_online(device_t *dev_ptr);
/**
 * 
 * 直接设置设备离线
*/
void set_dev_offline(device_t *dev_ptr) ;


/**
 * 在往tag写入参数后需要执行
 * 直接调用会给采集部分发出信号并执行写操作
 * 
*/
void awake_dev_sync(tag_t *tag);

/**
 * 从写数据列表获取一个write_list_t
 * 返回write_list_t成功 返回NULL列表已经没有项了
 * 
*/
write_list_t* get_data_from_list(channel_t *chan_ptr) ;


/**
 * 查通道列表中要写入数据的数量
 * 
*/
int check_list_num(channel_t *chan_ptr);

/**
 * 等待信号量
 * 在数采部分写数据需要掉此等待 返回0后取查列表进行写操作
 * 
*/
int sem_wait_time(sem_t *sem,int timeout_s,int timeout_ms) ;

/**
 * 设置数采部分采样率
 * 必须在proto_forward_creat之前调用，因为proto_forward_creat内部需要这个默认值
 * 
*/
void set_default_sample_rare(int rate);

/**
 * 获取数采句柄
 * 
*/
proto_forward_t *get_proto_forward_var(void);

/**
 * 获取文件夹下模板信息
 * path文件夹路径
 * out_str输出缓存，使用完成后需要释放
 * -1 获取失败
 * 0 获取成功
*/
/**
 *根据设备名称获取s设备和通道指针
 * 
*/
int find_dev_channel_pr_by_dev_no(proto_forward_t *var,char*name,channel_t **chan_pr,device_t **dev_pr);

/**
 * 从tag读取数据
 * 
*/
int read_data_form_tag_by_p(tag_t *tag_finded,int data_type,tag_value_t *tag_val,float scale);

/**
 * 写一个数据到tag
*/
int write_data_to_tag_by_p(tag_t *tag_finded,tag_value_t *tag_val,float scale) ;

/**
 *数采加载完成后的一些处理,调用的时候一定是所有设备配置加载完成后才调用
 * 
*/
int proto_forward_later_handle(void);
// 临时解决策略丢失问题，其他地方非必要不要调用这个函数
int write_int_to_tag_cache_directly(char *dev_no, char *node, long value);
int get_alarm_cnt();
int get_alarm_history_count();

int set_sample_period_by_dev_no(proto_forward_t *var,char*name,int sample_period);
char *get_node_sort(int *out_len);
cJSON *get_dev_tree_from_file(char *file_path);
int get_same_type_devs_cnt(char *type);

int get_same_child_type_devs_cnt(char *type_main, char *child_type);

int reflush_data_by_name_force(proto_forward_t *var,char *name,tag_value_t *tag_val) ;

int do_some_action_foreach_tag(proto_forward_t *var,each_tag_cb each_tag_action,void *contex);

int clean_force_tag(proto_forward_t *var, char *name);
void *get_tag_value_point_by_name(const char *name, int type);
int dev_is_online(device_t *dev_ptr);
int north_cloud_load_nodemap(char *cfg_file);

int read_ems_connect_cb(char *name, void *value_v);
int read_ems_heartbeat_cb(char *name, void *value_v);
int write_ems_heartbeat_cb(char *name, void *value_v);
int get_ems_online(void);
int get_ems_disable(void);
int set_write_tag_write_type(proto_forward_t *var);
void init_nondisplay_tags();
#define LOCATION_4G_FILEPATH "/etc/location_4g.txt"
#endif
