#include "common.h"
#include "dy_utils/dy_common.h"
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

bool ble_load_cfg(ble_var_t *var, struct adapter *adapter, GDBusProxy *proxy)
{
    int i = 0;
    GList *list;
    ble_scanner_cfg_t *scan_cfg = NULL;
    ble_advertising_cfg_t *adv_cfg = NULL;
    ble_slave_cfg_t *slave_cfg = NULL;
    ble_gatt_server_cfg_t *server_cfg = NULL;
    const char *interface;
    int dev_id;

    if (adapter == NULL)
    {
        dy_syslog(LOG_DEBUG, "no adapter found\n");
        return false;
    }
    adapter->enable = true;
    scan_cfg = &adapter->scan_cfg;
    scan_cfg->adapter = adapter;
    adv_cfg = &adapter->adv_cfg;
    adv_cfg->adapter = adapter;
    slave_cfg = &adapter->slave_cfg;
    slave_cfg->adapter = adapter;
    server_cfg = &adapter->server_cfg;
    server_cfg->adapter = adapter;

    adapter->dev_id = var->dev_id;

#if 1
    scan_cfg->enable = true;
    scan_cfg->scan_type = 0x00; // passive
    scan_cfg->filter_policy = 0x00;
    scan_cfg->interval = 0x0100;
    scan_cfg->window = 0x0010;
    scan_cfg->filter_dup = 0x00; // do not filter duplicates
    scan_cfg->own_type = LE_PUBLIC_ADDRESS;
#endif

    get_board_sn(var->sn_str);
    if (load_nodes_cfg(&var->nodes_cfg_table, NODES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load nodes cfg fail");
    }

    for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
    {
        node_cfg_t *node_cfg = &var->nodes_cfg_table->node[i];
        if (node_cfg->port == BLE)
        {
            cJSON *ext = cJSON_Parse(node_cfg->ext_data);
            char mode[16] = {0};
            int slot = -1;

            GET_JSON_VALUE_STRING(ext, "mode", mode);
            GET_JSON_VALUE_INT(ext, "slot", slot);

            if (slot == var->slot)
            {
                if (strcmp(mode, "slave") == 0)
                {
                    slave_cfg->dev_cnt++;
                }
                else if (strcmp(mode, "master") == 0)
                {
                    server_cfg->enable = true;
                    adv_cfg->enable = true;
                    adv_cfg->type = "peripheral";
                }
                else if (strcmp(mode, "master_slave") == 0)
                {
                    slave_cfg->dev_cnt++;
                    server_cfg->enable = true;
                    adv_cfg->enable = true;
                    adv_cfg->type = "peripheral";
                }
                else if (strcmp(mode, "advertiser") == 0)
                {
                    scan_cfg->dev_cnt++;
                }
                else
                {
                    dy_syslog(LOG_DEBUG, "not supported mode:%s\n", mode);
                }
            }
            cJSON_Delete(ext);
        }
    }

    if ( scan_cfg->dev_cnt > 0)
    {
        scan_cfg->scan_dev = calloc(scan_cfg->dev_cnt, sizeof(ble_scan_dev_t));
        int index = 0;
        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            node_cfg_t *node_cfg = &var->nodes_cfg_table->node[i];
            if (node_cfg->port == BLE)
            {
                cJSON *ext = cJSON_Parse(node_cfg->ext_data);
                char mode[16] = {0};
                char *addr;
                char *type;
                int slot = -1;

                GET_JSON_VALUE_INT(ext, "slot", slot);
                GET_JSON_VALUE_STRING(ext, "mode", mode);

                if (slot == var->slot)
                {
                    if (strcmp(mode, "advertiser") == 0)
                    {
                        ble_scan_dev_t *scan_dev = &scan_cfg->scan_dev[index];
                        index++;
                        GET_JSON_VALUE_DY_STRING(ext, "addr", addr);
                        scan_dev->SN = node_cfg->sn;
                        scan_dev->addr = addr;
                        scan_dev->adapter = var->adapter;
                    }
                }
                cJSON_Delete(ext);
            }
        }
    }

    if (slave_cfg->dev_cnt > 0)
    {
        slave_cfg->slave = calloc(slave_cfg->dev_cnt, sizeof(ble_slave_dev_t));
        int index = 0;
        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            node_cfg_t *node_cfg = &var->nodes_cfg_table->node[i];
            if (node_cfg->port == BLE)
            {
                cJSON *ext = cJSON_Parse(node_cfg->ext_data);
                char mode[16] = {0};
                char *addr;
                char *type;
                int slot = -1;

                GET_JSON_VALUE_INT(ext, "slot", slot);
                GET_JSON_VALUE_STRING(ext, "mode", mode);

                if (slot == var->slot)
                {
                    dy_syslog(LOG_DEBUG, "mode:%s\n", mode);
                    if (strcmp(mode, "slave") == 0 || strcmp(mode, "master_slave") == 0)
                    {
                        struct ble_sess_store * bstore;
                        ble_slave_dev_t *slave = &slave_cfg->slave[index];
                        index++;
                        GET_JSON_VALUE_STRING(ext, "mode", mode);
                        GET_JSON_VALUE_DY_STRING(ext, "addr", addr);
                        GET_JSON_VALUE_DY_STRING(ext, "addr_type", type);
                        slave->addr = addr;
                        slave->AddressType = type;
                        slave->SN = node_cfg->sn;

                        /* initialize BLE data buffer store */
                        bstore = &slave->buf_store;
                        bstore->num_data = 0;
                        bstore->cur_offset = 0;
                        bstore->lsend_tsec = ble_gettime(NULL, &bstore->lsend_tmsec);
                        bstore->ble_buffer = (unsigned char *) calloc(0x1, BLE_SESS_BUFSIZ);
                        if (bstore->ble_buffer == NULL) {
                            dy_syslog(LOG_ERR, "Error, System out of memory!\n");
                        }
                        if (pthread_mutex_init(&bstore->store_lock, NULL) != 0) {
                            dy_syslog(LOG_ERR, "Error, failed to initialize mutex lock!\n");
                        }
                    }
                }
                cJSON_Delete(ext);
            }
        }
    }

    if (server_cfg->enable)
    {
        /*
        {
            "mode": "master_slave",
            "addr": "E0:51:24:CC:53:A3",
            "addr_type": "public",
            "Services": [{
                "uuid": "01ff0100-ba5e-f4ee-5ca1-eb1e5e4b1ce0",
                "Characteristics": [{
                    "uuid": "01ff0101-ba5e-f4ee-5ca1-eb1e5e4b1ce0",
                    "Flags": "write-without-response,read"
                }]
            }]
        }
        */
        for (i = 0; i < var->nodes_cfg_table->node_cnt; i++)
        {
            node_cfg_t *node_cfg = &var->nodes_cfg_table->node[i];
            if (node_cfg->port == BLE)
            {
                cJSON *ext = cJSON_Parse(node_cfg->ext_data);
                int slot = -1;

                GET_JSON_VALUE_INT(ext, "slot", slot);
                if (slot == var->slot)
                {
                    char mode[16] = {0};
                    GET_JSON_VALUE_STRING(ext, "mode", mode);
                    if (strcmp(mode, "master") == 0 || strcmp(mode, "master_slave") == 0)
                    {
                        cJSON *services = cJSON_GetObjectItem(ext, "Services");
                        if (!services)
                        {
                            cJSON_Delete(ext);
                            continue;
                        }

                        server_cfg->service_cnt = cJSON_GetArraySize(services);
                        if (server_cfg->service_cnt > 0)
                        {
                            int j = 0;
                            server_cfg->services = calloc(server_cfg->service_cnt, sizeof(ble_gatt_service_cfg_t));
                            for (j = 0; j < server_cfg->service_cnt; j++)
                            {
                                ble_gatt_service_cfg_t *service_cfg = &server_cfg->services[j];
                                cJSON *service = cJSON_GetArrayItem(services, j);
                                if (service)
                                {
                                    GET_JSON_VALUE_DY_STRING(service, "uuid", service_cfg->uuid);
                                    service_cfg->primary = true;
                                    cJSON *chrcs = cJSON_GetObjectItem(service, "Characteristics");
                                    service_cfg->num_char = cJSON_GetArraySize(chrcs);
                                    service_cfg->chars = calloc(service_cfg->num_char, sizeof(ble_gatt_service_char_t));
                                    int k = 0;
                                    dy_syslog(LOG_DEBUG, "service_cfg->num_char:%d\n", service_cfg->num_char);

                                    for (k = 0; k < service_cfg->num_char; k++)
                                    {
                                        ble_gatt_service_char_t *chr_cfg = &service_cfg->chars[k];
                                        cJSON *chr = cJSON_GetArrayItem(chrcs, k);
                                        char *flags;

                                        GET_JSON_VALUE_DY_STRING(chr, "uuid", chr_cfg->uuid);
                                        GET_JSON_VALUE_DY_STRING(chr, "Flags", flags);
                                        chr_cfg->Flags = g_strsplit(flags, ",", -1);
                                    }
                                }
                            }
                        }
                    }
                }
                cJSON_Delete(ext);
            }
        }
    }

    return true;
}
