#include <syslog.h>
#include <stdio.h>
#include <string.h>

#include "dy_common.h"
#include "kv_array.h"

/**
*******************************************************************************
*
* @brief 将key value插入到kv数组中，该函数中将分配长度为len的空间，并将data到data+len的内容拷贝进去
* @param this 指向自己这个key-value array
* @param key  key
* @param data  数据内容
* @param len  数据长度
* @return 若存在key则返回数据，若不存在key则返回NULL
*
*******************************************************************************
*/
static int kv_array_insert(void *this, char *key, void *data, int len)
{
    kv_array_t *obj = this;
    int i;
    data_info_t *info = NULL;

    if (key == NULL)
    {
        dy_syslog(LOG_WARNING, "Device key is invalid");
        return -1;
    }

    pthread_rwlock_wrlock(&obj->table.rw_lock);
    for (i = 0; i < obj->table.size; i++)
    {
        info = &obj->table.data_info[i];
        if (info && info->key && (strcmp(info->key, key) == 0))
        {
            if (info->data != data) // 如果指针等于原来指针直接跳过
            {
                if (info->data)
                {
                    // 回收旧数据
                    free(info->data);
                }
                info->data = malloc(len);
                info->len = len;
                memcpy(info->data, data, len);
            }
            goto out;
        }
    }
    // 没有匹配的key,则存入index指定位置
    if (obj->table.index >= obj->table.size)
    {
        obj->table.index = 0;
    }

    info = &obj->table.data_info[obj->table.index];
    if (info->key)
    {
        free(info->key);
    }
    info->key = strdup(key);

    if (info->data)
    {
        free(info->data);
    }
    info->data = malloc(len);
    info->len = len;
    memcpy(info->data, data, len);
    obj->table.index++;

out:
    info->compared = false;
    info->timestamp = time(NULL);
    pthread_rwlock_unlock(&obj->table.rw_lock);
    return 0;
}

/**
*******************************************************************************
*
* @brief 根据key查找数据(key和value 的结构都返回)
* @param this 指向自己这个key-value array
* @param key  key
* @return 若存在key则返回数据，若不存在key则返回NULL
*
*******************************************************************************
*/
static data_info_t *kv_array_get(void *this, char *key)
{
    kv_array_t *obj = this;
    int i;
    data_info_t *info = NULL;

    if (obj == NULL || key == NULL)
    {
        dy_syslog(LOG_ERR, "wrong paramters");
        return NULL;
    }

    pthread_rwlock_rdlock(&obj->table.rw_lock);
    for (i = 0; i < obj->table.size; i++)
    {
        info = &obj->table.data_info[i];
        if (info && info->key && (strcmp(info->key, key) == 0))
        {
            pthread_rwlock_unlock(&obj->table.rw_lock);
            return info;
        }
    }
    pthread_rwlock_unlock(&obj->table.rw_lock);
    return NULL;
}

/**
*******************************************************************************
*
* @brief 根据key查找数据
* @param this 指向自己这个key-value array
* @param key  key
* @return 若存在key则返回数据，若不存在key则返回NULL
*
*******************************************************************************
*/
static void *kv_array_getdata(void *this, char *key)
{
    data_info_t *info = kv_array_get(this, key);
    if (info)return info->data;
    return NULL;
}

/**
*******************************************************************************
*
* @brief 根据key清除key和value的结构体内容
* @param this 指向自己这个key-value array
* @param key  key
* @return 成功返回0; 失败返回-1
*
*******************************************************************************
*/
static int kv_array_delete(void *this, char *key)
{
    kv_array_t *obj = this;
    int i;
    data_info_t *info = NULL;

    if (obj == NULL || key == NULL)
    {
        dy_syslog(LOG_ERR, "wrong paramters");
        return -1;
    }

    pthread_rwlock_wrlock(&obj->table.rw_lock);
    for (i = 0; i < obj->table.size; i++)
    {
        info = &obj->table.data_info[i];
        if (info && info->key && (strcmp(info->key, key) == 0))
        {
            
            free(info->key);
            free(info->data);
            memset(info, 0, sizeof(data_info_t));
            break;
        }
    }
    pthread_rwlock_unlock(&obj->table.rw_lock);

    return 0;
}

/**
*******************************************************************************
*
* @brief 初始化key-value 数组结构
* @param obj[out] 用于存储key-value array
* @param size  数组的大小
*
*******************************************************************************
*/
void kv_array_init(kv_array_t *obj, int size)
{
    obj->table.data_info = calloc(size, sizeof(data_info_t));
    obj->table.size = size;
    obj->table.index = 0;
    pthread_rwlock_init(&obj->table.rw_lock, NULL);

    obj->insert = kv_array_insert;
    obj->get = kv_array_get;
    obj->getdata = kv_array_getdata;
    obj->delete = kv_array_delete;
}
