/*
 * Created by jiaqiang.ye@lnxall.com
 *
 * Common PCS configure interface
 *
 * 2024/09/23
 */

#include "../adapter/pe_adapter.h"
#include "../common.h"
#include "../tag.h"
#include <math.h>
#include <sys/syslog.h>
#include "adapter_define.h"
#include "collector-api.h"

proto_forward_t* get_proto_forward_var(void);


static inline int double_to_int(double value)
{
    return round(value);
}

static int adapter_function_find(const char* dev_no, const char* function, adapter_function_t** maph)
{
    char p[DEV_NAME_LEN + ADAPTER_FUNCTION_NAME_LEN] = {0};
    snprintf(p, DEV_NAME_LEN + ADAPTER_FUNCTION_NAME_LEN, "%s.%s", dev_no, function);
    proto_forward_t* proto = get_proto_forward_var();
    return hash_intptr_findptr(proto->func_map_hash, p, strlen(p), (void**)maph);
}

bool adapter_function_exist(pe_class* this_p, const char* function)
{
    adapter_function_t* maph = NULL;
    return adapter_function_find(this_p->no, function, &maph) == 0 && maph != NULL;
}

int adapter_function_set(pe_class* this_p, const char* function, double value)
{
    if (this_p == NULL || this_p->opt == NULL) return -1;
    adapter_function_t* maph = NULL;

    if (adapter_function_find(this_p->no, function, &maph) < 0 || maph == NULL)
    {
        return -1; // hash can not find key
    }
    int ret = -1;
    for (int j = 0; j < maph->maps_num; j++)
    {
        adapter_var_map_t* map = &maph->maps[j];
        if ((map->map_in != -1 || map->map_out != -1) && (map->map_in != double_to_int(value))) continue;

        if (map->map_in == -1 && map->map_out == -1)
        {
            map->data_type == 0 ? dev_set_dev_tag_int(this_p->no, map->tagname, double_to_int(value)) : dev_set_dev_tag_float(this_p->no, map->tagname, value);
            ret =  0;
        }
        if (map->map_in == double_to_int(value))
        {
            map->data_type == 0 ? dev_set_dev_tag_int(this_p->no, map->tagname, map->map_out) : dev_set_dev_tag_float(this_p->no, map->tagname, (double)(map->map_out));
            ret = 0;
        }
    }

    if(ret == -1) proto_syslog(LOG_ERR, "Error, invalid function name [%s] in [%s]", function, __FUNCTION__);
    return ret;
}


// @return: 0 int,1 double ; -1 failed
int adapter_function_get_double(pe_class* this_p, const char* function, double* value)
{
    if (this_p == NULL || this_p->opt == NULL) return -1;
    adapter_function_t* maph = NULL;
    if (adapter_function_find(this_p->no, function, &maph) < 0 || maph == NULL) return -1; // hash can not find key

    char* tagname = NULL;
    int   ret     = 0;
    for (int j = 0; j < maph->maps_num; j++)
    {
        adapter_var_map_t* map = &maph->maps[j];

        if (tagname == NULL || strcmp(tagname, map->tagname) != 0)
        {
            tagname = map->tagname;
            if (map->data_type == 0)
            {
                int t = 0;
                ret   = dev_get_dev_tag_int_with_result(this_p->no, map->tagname, &t);
                if (ret == 0)
                    *value = (double)t;
            }
            else
            {
                ret = dev_get_dev_tag_float_with_result(this_p->no, map->tagname, value);
            }
        }

        if (map->map_in == -1 && map->map_out == -1 && ret == 0)
        {
            return 0;
        }
        if (ret == 0 && map->map_out == double_to_int(*value))
        {
            *value = (double)map->map_in;
            return 0;
        }
    }
    proto_syslog(LOG_ERR, "Error, invalid function name [%s] in [%s]", function, __FUNCTION__);
    return -1;
}

int adapter_function_get_int(pe_class* this_p, const char* function, int* value)
{
    if (this_p == NULL || this_p->opt == NULL) return -1;
    adapter_function_t* maph = NULL;
    if (adapter_function_find(this_p->no, function, &maph) < 0 || maph == NULL) return -1; // hash can not find key

    char* tagname = NULL;
    int   ret     = 0;
    for (int j = 0; j < maph->maps_num; j++)
    {
        adapter_var_map_t* map = &maph->maps[j];

        if (tagname == NULL || strcmp(tagname, map->tagname) != 0)
        {
            tagname = map->tagname;
            if (map->data_type == 1)
            {
                double t = 0;
                ret   = dev_get_dev_tag_float_with_result(this_p->no, map->tagname, &t);
                if (ret == 0)
                    *value = double_to_int(t);
            }
            else
            {
                ret = dev_get_dev_tag_int_with_result(this_p->no, map->tagname, value);
            }
        }

        if (ret == 0 && map->map_in == -1 && map->map_out == -1)
        {
            return 0;
        }
        if (ret == 0 && map->map_out == *value)
        {
            *value = map->map_in;
            return 0;
        }
    }
    proto_syslog(LOG_ERR, "Error, invalid function name [%s] in [%s]", function, __FUNCTION__);
    return -1;
}


static char* common_compatible_arr[] = {COMMON_ADAPTER, "common_pcs", "common", NULL};

pe_adapter common_adp __at_pe_adp_section = {
    .compatible  = common_compatible_arr,
    .init        = NULL,
    .set_power   = NULL,
    .set_repower = NULL,
    .set_mode    = NULL,
    .set_onoff   = NULL,
    .set_connect = NULL,

    .get_power   = NULL,
    .get_repower = NULL,
    .get_mode    = NULL,
    .get_onoff   = NULL,
    .get_connect = NULL,

    .set_value     = NULL,
    .get_int_value = NULL,
    .get_double_value = NULL,
};
