/********************************************************************************
 * @File name: libcollector-api.c
 * @Author: xpzhao
 * @Version: 0.1
 * @Date: 2023-7-1
 * @Description: Provide the API function for user, give up level
 * a easy method to use
 ********************************************************************************/
#include <string.h>
#include <syslog.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "../adapter/pe_adapter.h"
#include "collector-api.h"
#include "../common.h"
// #include "../opcua/ua-server.h"

void register_callback_ems(void *context, tag_t *tag)
{
    ems_data_cb_t ems_data_cb = context;
    tag_value data_value;
    data_value.type = tag->data_type;
    if (data_value.type == TYPE_TAG_INT)
    {
        data_value.value.to_int = tag->read_cache.to_int;
        data_value.value_last.to_int = tag->last_read_cache.to_int;
    }
    else
    {
        data_value.value.to_float = tag->read_cache.to_float;
        data_value.value_last.to_float = tag->last_read_cache.to_float;
    }
    ems_data_cb(tag->dev_tag_name, &data_value);
}

void register_callback_ems_with_par(void *context, tag_t *tag)
{
    ems_with_par_cb_s *p = (ems_with_par_cb_s*)context;
    tag_value data_value;
    data_value.type = tag->data_type;
    if (data_value.type == TYPE_TAG_INT)
    {
        data_value.value.to_int = tag->read_cache.to_int;
        data_value.value_last.to_int = tag->last_read_cache.to_int;
    }
    else
    {
        data_value.value.to_float = tag->read_cache.to_float;
        data_value.value_last.to_float = tag->last_read_cache.to_float;
    }
    p->cb(tag->dev_tag_name, &data_value, p->par);
}

int collector_variant_monitor_add_one_with_par(pcs_ctrl_var_t *var, char *node, ems_data_par_cb cb, void *par, int type)// type:0->变化回调 1->刷新回调
{
    int ret = 0;
    ems_with_par_cb_s *p_cm_s = NULL;
    p_cm_s = calloc(1, sizeof(ems_with_par_cb_s));
    if (p_cm_s == NULL)
    {
        return -1;
    }
    p_cm_s->cb = cb;
    p_cm_s->par = par;
    if (type == 0)
    {
        ret = register_data_collect_cb_by_name(var->device_layer_ptr, node, register_callback_ems_with_par, p_cm_s);
    }
    else
    {
        ret = register_data_flush_cb_by_name(var->device_layer_ptr, node, register_callback_ems_with_par, p_cm_s);
    }
    if (ret != 0)
    {
        free(p_cm_s);
        return -1;
    }

    return ret;
}

bool check_nod_exist(const char *nod) // 检查点位是否存在
{
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    return check_tag_by_name(var->device_layer_ptr, (char *)nod);
}

int collector_variant_monitor_add(pcs_ctrl_var_t *var, const char **node, size_t size,
                                  ems_data_cb_t tag_get_data_cb_t)
{
    int ret = -1;
    for (size_t i = 0; i < size; i++)
    {
        ret = register_data_collect_cb_by_name(var->device_layer_ptr, (char *)node[i], register_callback_ems, tag_get_data_cb_t);
        if (ret == -1)
            break;
    }
    return ret;
}

int collector_flush_variant_monitor_add(pcs_ctrl_var_t *var, const char **node, size_t size,
                                        ems_data_cb_t tag_get_data_cb_t)
{
    int ret = -1;
    for (size_t i = 0; i < size; i++)
    {
        ret = register_data_flush_cb_by_name(var->device_layer_ptr, (char *)node[i], register_callback_ems, tag_get_data_cb_t);
        if (ret == -1)
            break;
    }
    return ret;
}

int collector_var_monitor_add_mul(pcs_ctrl_var_t *var, const char **node_temp, size_t size,
                                      ems_data_cb_t tag_get_data_cb_t, int cabinet_cnt, int type)
{
    int (*register_cb_p[2])(proto_forward_t *var,char *name,tag_get_data_cb tag_get_data_cb,void *context) = 
    {
        register_data_collect_cb_by_name, // 变化回调
        register_data_flush_cb_by_name // 刷新回调
    };

    char nod_name[TAG_NAME_LEN + DEV_NAME_LEN] = {0};
    char *p_tmp = NULL;
    if (cabinet_cnt < 0)
    {
        cabinet_cnt = 0 - cabinet_cnt;
        for (int j = 1; j <= cabinet_cnt; j++)
        {
            for (size_t i = 0; i < size; i++)
            {
                snprintf(nod_name, sizeof(nod_name), node_temp[i], j);
                if (0 != register_cb_p[type](var->device_layer_ptr, nod_name, register_callback_ems, tag_get_data_cb_t))
                {
                    proto_syslog(LOG_ERR, "%s register callback error", nod_name);
                }
                else
                {
                    proto_syslog(LOG_NOTICE, "%s register callback ok", nod_name);
                }
            }
        }
        return 0;
    }
    // 第一个特殊处理
    for (size_t i = 0; i < size; i++)
    {
        memset(nod_name, 0, sizeof(nod_name));
        p_tmp = strstr(node_temp[i], "%d.");
        if (p_tmp != NULL)
        {
            memcpy(nod_name, node_temp[i], p_tmp - node_temp[i]);
            strcat(nod_name, p_tmp + 2);
        }
        if (0 != register_cb_p[type](var->device_layer_ptr, nod_name, register_callback_ems, tag_get_data_cb_t))
        {
            proto_syslog(LOG_ERR, "%s register callback error", nod_name);
        }
        else
        {
            proto_syslog(LOG_NOTICE, "%s register callback ok", nod_name);
        }
    }

    for (int j = 2; j <= cabinet_cnt; j++)
    {
        for (size_t i = 0; i < size; i++)
        {
            snprintf(nod_name, sizeof(nod_name), node_temp[i], j);
            if (0 != register_cb_p[type](var->device_layer_ptr, nod_name, register_callback_ems, tag_get_data_cb_t))
            {
                proto_syslog(LOG_ERR, "%s register callback error", nod_name);
            }
            else
            {
                proto_syslog(LOG_NOTICE, "%s register callback ok", nod_name);
            }
        }
    }
    return 0;
}

int collector_variant_monitor_add_mul(pcs_ctrl_var_t *var, const char **node_temp, size_t size,
                                      ems_data_cb_t tag_get_data_cb_t, int cabinet_cnt)
{
    return collector_var_monitor_add_mul(var, node_temp, size, tag_get_data_cb_t, cabinet_cnt, 0);
}

int collector_ems_variant_monitor_add_mul(pcs_ctrl_var_t *var, const char **node_temp, size_t size,
                                          ems_data_cb_t tag_get_data_cb_t, int cabinet_cnt)
{
    char nod_name[TAG_NAME_LEN + DEV_NAME_LEN] = {0};
    for (int j = 1; j <= cabinet_cnt; j++)
    {
        for (size_t i = 0; i < size; i++)
        {
            snprintf(nod_name, sizeof(nod_name), node_temp[i], j);
            if (0 != register_data_collect_cb_by_name(var->device_layer_ptr, nod_name, register_callback_ems, tag_get_data_cb_t))
            {
                proto_syslog(LOG_ERR, "%s register callback error", nod_name);
            }
            else
            {
                proto_syslog(LOG_NOTICE, "%s register callback ok", nod_name);
            }
        }
    }
    return 0;
}

int collector_variant_monitor_add_one(pcs_ctrl_var_t *var, char *node,
                                      ems_data_cb_t tag_get_data_cb_t)
{
    int ret = -1;
    ret = register_data_collect_cb_by_name(var->device_layer_ptr, node, register_callback_ems, tag_get_data_cb_t);
    return ret;
}
// syntactic sugar
int collector_write_one_int_data(const char *nod, int write_val) // 下行写数据 可以给自己写  可以当作刷新自己数据的方式 会触发相应回调
{
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    tag_value tag_val = {0};
    memset(&tag_val, 0, sizeof(tag_value));
    tag_val.type = TYPE_TAG_INT;
    tag_val.value.to_int = write_val;
    return write_data_to_tag_by_name(var->device_layer_ptr, (char *)nod, &tag_val);
}

int collector_write_one_float_data(const char *nod, double write_val) // 下行写数据 可以给自己写
{
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    tag_value tag_val;
    memset(&tag_val, 0, sizeof(tag_value));
    tag_val.type = TYPE_TAG_FLOAT;
    tag_val.value.to_float = write_val;
    return write_data_to_tag_by_name(var->device_layer_ptr, (char *)nod, &tag_val);
}

int collector_read_one_int_data(const char *nod, int *resp_val) // 从cache读数据
{
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    tag_value tag_val = {0};
    memset(&tag_val, 0, sizeof(tag_value));
    int ret = read_data_form_tag_by_name(var->device_layer_ptr, (char *)nod, TYPE_TAG_INT, &tag_val);
    if (ret == 0)
    {
        *resp_val = tag_val.value.to_int;
    }
    else
    {
        ems_syslog(LOG_INFO, " read_nod:%s error", nod);
    }
    return ret;
}

int collector_read_one_float_data(const char *nod, double *resp_val) // 从cache读数据
{
    pcs_ctrl_var_t *var = get_pcs_ctrl_var();
    tag_value tag_val = {0};
    memset(&tag_val, 0, sizeof(tag_value));
    int ret = read_data_form_tag_by_name(var->device_layer_ptr, (char *)nod, TYPE_TAG_FLOAT, &tag_val);
    *resp_val = tag_val.value.to_float;
    return ret;
}

int set_sample_period(char *name, int sample_period)
{
    set_sample_period_by_dev_no(get_proto_forward_var(), name, sample_period);
    return 0;
}
/*********************************通用点位读写方法********************************************/
#define NODE_SIZE TAG_NAME_LEN + DEV_NAME_LEN
void dev_set_dev_tag_int(const char* dev_id, const char* var_id, int val)
{
    //char *nod = alloc_node_tag(dev_id,var_id);
    char nod[NODE_SIZE] = {0};
    //memset(nod,0,NODE_SIZE);
    snprintf(nod,NODE_SIZE,"%s.%s",dev_id,var_id);
    collector_write_one_int_data(nod,val);
    //free(nod);
}

void dev_set_dev_tag_float(const char* dev_id, const char* var_id, double val)
{
    //char *nod = alloc_node_tag(dev_id,var_id);
    char nod[NODE_SIZE] = {0};
    //memset(nod,0,NODE_SIZE);
    snprintf(nod,NODE_SIZE,"%s.%s",dev_id,var_id);
    collector_write_one_float_data(nod, val);
    //free(nod);
}

int dev_get_nodeid_int(const char* nod_id)
{
    int write_val=0;
    collector_read_one_int_data(nod_id, &write_val);
    return write_val;
}

int dev_get_dev_tag_int(const char* dev_id, const char* var_id)
{
    char nod[NODE_SIZE] = {0};
    //memset(nod,0,NODE_SIZE);
    snprintf(nod,NODE_SIZE,"%s.%s",dev_id,var_id);
    return dev_get_nodeid_int(nod);
}

double dev_get_nodeid_float(const char* nod_id)
{
    double write_val=0.0f;
    collector_read_one_float_data(nod_id, &write_val);
    return write_val;
}

double dev_get_dev_tag_float(const char* dev_id, const char* var_id)
{
    char nod[NODE_SIZE] = {0};
    //memset(nod,0,NODE_SIZE);
    snprintf(nod,NODE_SIZE,"%s.%s",dev_id,var_id);
    return dev_get_nodeid_float(nod);
}


int dev_get_dev_tag_float_with_result(const char* dev_id, const char* var_id,double *value)
{
    char nod[NODE_SIZE] = {0};
    //memset(nod,0,NODE_SIZE);
    snprintf(nod,NODE_SIZE,"%s.%s",dev_id,var_id);
    return collector_read_one_float_data(nod, value);
}

int dev_get_dev_tag_int_with_result(const char* dev_id, const char* var_id,int *value)
{
    char nod[NODE_SIZE] = {0};
    //memset(nod,0,NODE_SIZE);
    snprintf(nod,NODE_SIZE,"%s.%s",dev_id,var_id);
    return collector_read_one_int_data(nod, value);
}



/*********************************PCS操作方法,不同PCS操作方法不一样********************************************/
void def_set_pcs_power(const char* dev_id, float val)
{
    pe_set_power(dev_id, val);
}
void def_set_pcs_repower(const char* dev_id, float val)
{
    pe_set_repower(dev_id, val);
}

void def_set_pcs_onoff(const char* dev_id, int val)
{
    if (val == 0)
    {
        pe_set_onoff(dev_id, PE_ADP_OFF);
    }
    else
    {
        pe_set_onoff(dev_id, PE_ADP_ON);
    }
    
}

void def_set_pcs_mode(const char* dev_id, int val)
{
    pe_set_mode(dev_id, val);
}

void dev_set_pcs_connect(const char* dev_id, PCS_CONNSTA_E val)
{
    pe_set_connect(dev_id, val);
}

double def_get_pcs_power(const char* dev_id)
{
    double p = 0;
    pe_get_power(dev_id, &p);
    return p;
}

double def_get_pcs_repower(const char* dev_id)
{
    double p = 0;
    pe_get_repower(dev_id, &p);
    return p;
}

int def_get_pcs_onoff(const char* dev_id)
{
    return pe_get_onoff(dev_id);
}

int dev_get_pcs_connect(const char* dev_id)
{
    return pe_get_connect(dev_id);
}

int dev_get_pcs_mode(const char* dev_id)
{
    return pe_get_mode(dev_id);
}

int dev_get_function_int(const char* dev_id, const char* function,int* value)
{
    return pe_get_int_value(dev_id, function, value);
}

int dev_get_function_double(const char* dev_id, const char* function,double* value)
{
    return pe_get_double_value(dev_id, function, value);
}

int dev_set_function(const char* dev_id, const char* function, double value)
{
    return pe_set_value(dev_id, function, value);
}
