#include "common.h"

static DBusConnection *dbus_conn = NULL;
static GList *ctrl_list = NULL;
static char *auto_register_agent = NULL;
static GDBusProxy *agent_manager;

ble_var_t *var = NULL;

static void print_adapter(GDBusProxy *proxy, const char *description)
{
    DBusMessageIter iter;
    const char *address, *name;

    if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
        return;

    dbus_message_iter_get_basic(&iter, &address);

    if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
        dbus_message_iter_get_basic(&iter, &name);
    else
        name = "<unknown>";

    dy_syslog(LOG_DEBUG, "%s%s%sController %s %s\n",
           description ? "[" : "",
           description ?: "",
           description ? "] " : "",
           address, name);
}

static void print_device(GDBusProxy *proxy, const char *description)
{
    DBusMessageIter iter;
    const char *address, *name;

    if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
        return;

    dbus_message_iter_get_basic(&iter, &address);

    if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
        dbus_message_iter_get_basic(&iter, &name);
    else
        name = "<unknown>";

    dy_syslog(LOG_DEBUG, "%s%s%sDevice %s %s\n",
           description ? "[" : "",
           description ?: "",
           description ? "] " : "",
           address, name);
}

static void print_fixed_iter(const char *label, const char *name,
                             DBusMessageIter *iter)
{
    dbus_bool_t *valbool;
    dbus_uint32_t *valu32;
    dbus_uint16_t *valu16;
    dbus_int16_t *vals16;
    unsigned char *byte;
    int len;

    switch (dbus_message_iter_get_arg_type(iter))
    {
    case DBUS_TYPE_BOOLEAN:
        dbus_message_iter_get_fixed_array(iter, &valbool, &len);

        if (len <= 0)
            return;

        dy_syslog(LOG_DEBUG, "%s%s:\n", label, name);
        bt_shell_hexdump((void *)valbool, len * sizeof(*valbool));

        break;
    case DBUS_TYPE_UINT32:
        dbus_message_iter_get_fixed_array(iter, &valu32, &len);

        if (len <= 0)
            return;

        dy_syslog(LOG_DEBUG, "%s%s:\n", label, name);
        bt_shell_hexdump((void *)valu32, len * sizeof(*valu32));

        break;
    case DBUS_TYPE_UINT16:
        dbus_message_iter_get_fixed_array(iter, &valu16, &len);

        if (len <= 0)
            return;

        dy_syslog(LOG_DEBUG, "%s%s:\n", label, name);
        bt_shell_hexdump((void *)valu16, len * sizeof(*valu16));

        break;
    case DBUS_TYPE_INT16:
        dbus_message_iter_get_fixed_array(iter, &vals16, &len);

        if (len <= 0)
            return;

        dy_syslog(LOG_DEBUG, "%s%s:\n", label, name);
        bt_shell_hexdump((void *)vals16, len * sizeof(*vals16));

        break;
    case DBUS_TYPE_BYTE:
        dbus_message_iter_get_fixed_array(iter, &byte, &len);

        if (len <= 0)
            return;

        dy_syslog(LOG_DEBUG, "%s%s:\n", label, name);
        bt_shell_hexdump((void *)byte, len * sizeof(*byte));

        break;
    default:
        return;
    };
}

static void print_iter(const char *label, const char *name,
                       DBusMessageIter *iter)
{
    dbus_bool_t valbool;
    dbus_uint32_t valu32;
    dbus_uint16_t valu16;
    dbus_int16_t vals16;
    unsigned char byte;
    const char *valstr;
    DBusMessageIter subiter;
    char *entry;

    if (iter == NULL)
    {
        dy_syslog(LOG_DEBUG, "%s%s is nil\n", label, name);
        return;
    }

    switch (dbus_message_iter_get_arg_type(iter))
    {
    case DBUS_TYPE_INVALID:
        dy_syslog(LOG_DEBUG, "%s%s is invalid\n", label, name);
        break;
    case DBUS_TYPE_STRING:
    case DBUS_TYPE_OBJECT_PATH:
        dbus_message_iter_get_basic(iter, &valstr);
        dy_syslog(LOG_DEBUG, "%s%s: %s\n", label, name, valstr);
        break;
    case DBUS_TYPE_BOOLEAN:
        dbus_message_iter_get_basic(iter, &valbool);
        dy_syslog(LOG_DEBUG, "%s%s: %s\n", label, name,
               valbool == TRUE ? "yes" : "no");
        break;
    case DBUS_TYPE_UINT32:
        dbus_message_iter_get_basic(iter, &valu32);
        dy_syslog(LOG_DEBUG, "%s%s: 0x%08x\n", label, name, valu32);
        break;
    case DBUS_TYPE_UINT16:
        dbus_message_iter_get_basic(iter, &valu16);
        dy_syslog(LOG_DEBUG, "%s%s: 0x%04x\n", label, name, valu16);
        break;
    case DBUS_TYPE_INT16:
        dbus_message_iter_get_basic(iter, &vals16);
        dy_syslog(LOG_DEBUG, "%s%s: %d\n", label, name, vals16);
        break;
    case DBUS_TYPE_BYTE:
        dbus_message_iter_get_basic(iter, &byte);
        dy_syslog(LOG_DEBUG, "%s%s: 0x%02x\n", label, name, byte);
        break;
    case DBUS_TYPE_VARIANT:
        dbus_message_iter_recurse(iter, &subiter);
        print_iter(label, name, &subiter);
        break;
    case DBUS_TYPE_ARRAY:
        dbus_message_iter_recurse(iter, &subiter);

        if (dbus_type_is_fixed(
                dbus_message_iter_get_arg_type(&subiter)))
        {
            print_fixed_iter(label, name, &subiter);
            break;
        }

        while (dbus_message_iter_get_arg_type(&subiter) !=
               DBUS_TYPE_INVALID)
        {
            print_iter(label, name, &subiter);
            dbus_message_iter_next(&subiter);
        }
        break;
    case DBUS_TYPE_DICT_ENTRY:
        dbus_message_iter_recurse(iter, &subiter);
        entry = g_strconcat(name, " Key", NULL);
        print_iter(label, entry, &subiter);
        g_free(entry);

        entry = g_strconcat(name, " Value", NULL);
        dbus_message_iter_next(&subiter);
        print_iter(label, entry, &subiter);
        g_free(entry);
        break;
    default:
        dy_syslog(LOG_DEBUG, "%s%s has unsupported type\n", label, name);
        break;
    }
}

static void print_property(GDBusProxy *proxy, const char *name)
{
    DBusMessageIter iter;

    if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
        return;

    print_iter("\t", name, &iter);
}

static void print_uuid(const char *uuid)
{
    const char *text;

    text = bt_uuidstr_to_str(uuid);
    if (text)
    {
        char str[26];
        unsigned int n;

        str[sizeof(str) - 1] = '\0';

        n = snprintf(str, sizeof(str), "%s", text);
        if (n > sizeof(str) - 1)
        {
            str[sizeof(str) - 2] = '.';
            str[sizeof(str) - 3] = '.';
            if (str[sizeof(str) - 4] == ' ')
                str[sizeof(str) - 4] = '.';

            n = sizeof(str) - 1;
        }

        dy_syslog(LOG_DEBUG, "\tUUID: %s%*c(%s)\n", str, 26 - n, ' ', uuid);
    }
    else
        dy_syslog(LOG_DEBUG, "\tUUID: %*c(%s)\n", 26, ' ', uuid);
}

static void print_uuids(GDBusProxy *proxy)
{
    DBusMessageIter iter, value;

    if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
        return;

    dbus_message_iter_recurse(&iter, &value);

    while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING)
    {
        const char *uuid;

        dbus_message_iter_get_basic(&value, &uuid);

        print_uuid(uuid);

        dbus_message_iter_next(&value);
    }
}

static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
{
    DBusMessageIter iter;
    const char *adapter, *path;

    if (!master)
        return FALSE;

    if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
        return FALSE;

    dbus_message_iter_get_basic(&iter, &adapter);
    path = g_dbus_proxy_get_path(master);

    if (!strcmp(path, adapter))
        return TRUE;

    return FALSE;
}

static struct adapter *find_ctrl(GList *source, const char *path)
{
    GList *list;
    for (list = g_list_first(source); list; list = g_list_next(list))
    {
        struct adapter *adapter = list->data;
        if (!strcasecmp(g_dbus_proxy_get_path(adapter->proxy), path))
            return adapter;
    }

    return NULL;
}

struct adapter *find_parent(GDBusProxy *device)
{
    GList *list;

    for (list = g_list_first(ctrl_list); list; list = g_list_next(list))
    {
        struct adapter *adapter = list->data;

        if (device_is_child(device, adapter->proxy) == TRUE)
            return adapter;
    }
    return NULL;
}

static GDBusProxy *find_parent_device(struct adapter *adapter, GDBusProxy *proxy)
{
    GDBusProxy *device;
    GList *list;

    for (list = g_list_first(adapter->devices); list; list = g_list_next(list))
    {
        GDBusProxy *device = list->data;
        if (!strcasecmp(g_dbus_proxy_get_path(device), g_dbus_proxy_get_path(proxy)))
            return device;
    }

    return NULL;
}

static void device_added(GDBusProxy *proxy)
{
    DBusMessageIter iter;
    struct adapter *adapter = find_parent(proxy);

    if (!adapter)
    {
        dy_syslog(LOG_DEBUG, "no parent adapter found\n");
        return;
    }

    adapter->devices = g_list_append(adapter->devices, proxy);

    adapter->dev_changed_ts = time(NULL);
    DBusMessageIter addr_iter;

    if (g_dbus_proxy_get_property(proxy, "Address",
                                  &addr_iter) == TRUE)
    {
        const char *address = NULL;

        dbus_message_iter_get_basic(&addr_iter,
                                    &address);
        ble_slave_dev_t *slave = find_slave_dev_by_address(adapter, address);
        if (slave != NULL)
        {
            slave->proxy = proxy;
            dy_syslog(LOG_DEBUG, "set %s proxy:%p\n", address, proxy);
            DBusMessageIter conn_iter;
            if (g_dbus_proxy_get_property(proxy, "Connected", &conn_iter) == TRUE)
            {
                dbus_bool_t connected;
                dbus_message_iter_get_basic(&conn_iter, &connected);
                if (connected)
                {
                    slave->state = SLAVE_DEV_CONNECTED;
                }
            }
        }
    }

    print_device(proxy, COLORED_NEW);
    bt_shell_set_env(g_dbus_proxy_get_path(proxy), proxy);
}

static struct adapter *adapter_new(GDBusProxy *proxy)
{
    struct adapter *adapter = g_malloc0(sizeof(struct adapter));

    ctrl_list = g_list_append(ctrl_list, adapter);
    var->ctrl_list = ctrl_list;
    var->ctrl_cnt++;
    adapter->var = var;

    ble_load_cfg(var, adapter, proxy);

    return adapter;
}

static void adapter_added(GDBusProxy *proxy)
{
    struct adapter *adapter;
    adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
    if (!adapter)
        adapter = adapter_new(proxy);

    adapter->proxy = proxy;

    print_adapter(proxy, COLORED_NEW);
    bt_shell_set_env(g_dbus_proxy_get_path(proxy), proxy);
}

static void ad_manager_added(GDBusProxy *proxy)
{
    struct adapter *adapter;
    adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
    if (!adapter)
        adapter = adapter_new(proxy);

    adapter->ad_proxy = proxy;
}

static void gatt_manager_added(GDBusProxy *proxy)
{
    struct adapter *adapter;
    adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
    if (!adapter)
        adapter = adapter_new(proxy);

    adapter->gm_proxy = proxy;
}

static void proxy_added(GDBusProxy *proxy, void *user_data)
{
    const char *interface;

    interface = g_dbus_proxy_get_interface(proxy);
    dy_syslog(LOG_DEBUG, "=====interface:%s, path:%s proxy:%p\n", interface, g_dbus_proxy_get_path(proxy), proxy);

    if (!strcmp(interface, "org.bluez.Device1"))
    {
        device_added(proxy);
    }
    else if (!strcmp(interface, "org.bluez.Adapter1"))
    {
        adapter_added(proxy);
    }
    else if (!strcmp(interface, "org.bluez.AgentManager1"))
    {
        if (!agent_manager)
        {
            agent_manager = proxy;
            if (auto_register_agent)
            {
                agent_register(dbus_conn, agent_manager, auto_register_agent);
            }
            var->agent_manager = proxy;
        }
    }
    else if (!strcmp(interface, "org.bluez.GattService1"))
    {
        gatt_add_service(proxy);
    }
    else if (!strcmp(interface, "org.bluez.GattCharacteristic1"))
    {
        gatt_add_characteristic(proxy);
    }
    else if (!strcmp(interface, "org.bluez.GattDescriptor1"))
    {
        gatt_add_descriptor(proxy);
    }
    else if (!strcmp(interface, "org.bluez.GattManager1"))
    {
        //gatt_manager_added(proxy);
        my_gatt_add_manager(proxy);
    }
    else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1"))
    {
        ad_manager_added(proxy);
    }
}

static void device_removed(GDBusProxy *proxy)
{
    struct adapter *adapter = find_parent(proxy);
    if (!adapter)
    {
        dy_syslog(LOG_DEBUG, "cannot find parent adapter\n");
        return;
    }

    adapter->devices = g_list_remove(adapter->devices, proxy);

    DBusMessageIter addr_iter;

    if (g_dbus_proxy_get_property(proxy, "Address",
                                  &addr_iter) == TRUE)
    {
        const char *address = NULL;

        dbus_message_iter_get_basic(&addr_iter,
                                    &address);
        ble_slave_dev_t *slave = find_slave_dev_by_address(adapter, address);
        if (slave != NULL)
        {
            slave->proxy = NULL;
            slave->state = SLAVE_DEV_NONE;
        }
    }

    print_device(proxy, COLORED_DEL);
    bt_shell_set_env(g_dbus_proxy_get_path(proxy), NULL);
}

static void adapter_removed(GDBusProxy *proxy)
{
    GList *ll;

    for (ll = g_list_first(ctrl_list); ll; ll = g_list_next(ll))
    {
        struct adapter *adapter = ll->data;

        if (adapter->proxy == proxy)
        {
            print_adapter(proxy, COLORED_DEL);
            bt_shell_set_env(g_dbus_proxy_get_path(proxy), NULL);
            ctrl_list = g_list_remove_link(ctrl_list, ll);
            g_list_free(adapter->devices);
            g_free(adapter);
            g_list_free(ll);
            return;
        }
    }
}

static void proxy_removed(GDBusProxy *proxy, void *user_data)
{
    const char *interface;

    interface = g_dbus_proxy_get_interface(proxy);

    if (!strcmp(interface, "org.bluez.Device1"))
    {
        device_removed(proxy);
    }
    else if (!strcmp(interface, "org.bluez.Adapter1"))
    {
        adapter_removed(proxy);
    }
    else if (!strcmp(interface, "org.bluez.AgentManager1"))
    {
        if (agent_manager == proxy)
        {
            agent_manager = NULL;
            if (auto_register_agent)
            {
                agent_unregister(dbus_conn, NULL);
            }
            var->agent_manager = NULL;
        }
    }
    else if (!strcmp(interface, "org.bluez.GattService1"))
    {
        gatt_remove_service(proxy);
    }
    else if (!strcmp(interface, "org.bluez.GattCharacteristic1"))
    {
        gatt_remove_characteristic(proxy);
    }
    else if (!strcmp(interface, "org.bluez.GattDescriptor1"))
    {
        gatt_remove_descriptor(proxy);
    }
    else if (!strcmp(interface, "org.bluez.GattManager1"))
    {
        my_gatt_remove_manager(proxy);
    }
    else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1"))
    {
        struct adapter *adapter;
        adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));

        ad_unregister(adapter, NULL);
    }
}

static void handle_ChrcChange(GDBusProxy *proxy, const char *name, DBusMessageIter *iter)
{
    DBusMessageIter subiter;
    char *entry;
    char *device_path = NULL;

    unsigned char *byte;
    int len = -1;

    if (iter == NULL)
    {
        dy_syslog(LOG_DEBUG, "%s is nil\n", name);
        return;
    }

    if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY)
    {
        dbus_message_iter_recurse(iter, &subiter);
        if (dbus_type_is_fixed(dbus_message_iter_get_arg_type(&subiter)))
        {
            if (dbus_message_iter_get_arg_type(&subiter) == DBUS_TYPE_BYTE)
            {
                dbus_message_iter_get_fixed_array(&subiter, &byte, &len);
            }
        }
    }

    if (len < 0)
    {
        byte = NULL;
        len = 0;
        goto done;
    }

    char *addr;
    char *uuid;
    DBusMessageIter iter_n;
    const char *path = g_dbus_proxy_get_path(proxy);
    if (path == NULL)
    {
        dy_syslog(LOG_DEBUG, "path is empty\n");
        goto done;
    }
    device_path = strndup(path, strlen("/org/bluez/hci0/dev_01_02_03_FF_6D_16"));

    GDBusProxy *device = bt_shell_get_env(device_path);
    if (device == NULL)
    {
        dy_syslog(LOG_DEBUG, "%s:%d\n", __FUNCTION__, __LINE__);
        goto done;
    }

    struct adapter *adapter = find_parent(device);
    if (adapter == NULL)
    {
        dy_syslog(LOG_DEBUG, "%s:%d\n", __FUNCTION__, __LINE__);
        goto done;
    }

    if (g_dbus_proxy_get_property(device, "Address", &iter_n))
        dbus_message_iter_get_basic(&iter_n, &addr);

    if (g_dbus_proxy_get_property(proxy, "UUID", &iter_n))
        dbus_message_iter_get_basic(&iter_n, &uuid);

    ble_slave_dev_t *slave = find_slave_dev_by_address(adapter, addr);
    ble_send_raw_data_to_pp(var, adapter->dev_id, slave, uuid, "write", byte, len);

done:
    if (device_path != NULL)
    {
        free(device_path);
    }
    return;
}

static void handle_AdapterChange(GDBusProxy *proxy, const char *name, DBusMessageIter *iter)
{
    if (iter == NULL)
    {
        dy_syslog(LOG_DEBUG, "%s is nil\n", name);
        return;
    }

    if (strcmp(name, "Powered") == 0)
    {
        dbus_bool_t Powered;

        dbus_message_iter_get_basic(iter, &Powered);
        if (Powered)
        {
            system("/etc/init.d/ble restart");
        }
        else
        {
            dy_syslog(LOG_DEBUG, "The adapter stoped\n");
            system("/etc/init.d/ble restart");
        }
    }
    return;
}

static void property_changed(GDBusProxy *proxy, const char *name,
                             DBusMessageIter *iter, void *user_data)
{
    const char *interface;
    struct adapter *ctrl;

    interface = g_dbus_proxy_get_interface(proxy);

    if (!strcmp(interface, "org.bluez.Device1"))
    {
        DBusMessageIter addr_iter;
        char *str;
        struct adapter *adapter = find_parent(proxy);

        if (adapter == NULL)
        {
            dy_syslog(LOG_DEBUG, "no parent adapter found\n");
            return;
        }
        adapter->dev_changed_ts = time(NULL);

        if (g_dbus_proxy_get_property(proxy, "Address",
                                      &addr_iter) == TRUE)
        {
            const char *address = NULL;

            dbus_message_iter_get_basic(&addr_iter,
                                        &address);
            str = g_strdup_printf("[" COLORED_CHG
                                  "] Device %s ",
                                  address);
            ble_slave_dev_t *slave = find_slave_dev_by_address(adapter, address);
            if (slave != NULL)
            {
                if (strcmp(name, "Connected") == 0)
                {
                    dbus_bool_t connected;

                    dbus_message_iter_get_basic(iter, &connected);

                    if (connected)
                    {
                        slave->state = SLAVE_DEV_CONNECTED;
                    }
                    else
                    {
                        slave->state = SLAVE_DEV_NONE;
                    }
                }
            }
        }
        else
            str = g_strdup("");

        print_iter(str, name, iter);
        g_free(str);
    }
    else if (!strcmp(interface, "org.bluez.Adapter1"))
    {
        DBusMessageIter addr_iter;
        char *str;

        if (g_dbus_proxy_get_property(proxy, "Address",
                                      &addr_iter) == TRUE)
        {
            const char *address;

            dbus_message_iter_get_basic(&addr_iter, &address);
            str = g_strdup_printf("[" COLORED_CHG
                                  "] Controller %s ",
                                  address);
        }
        else
            str = g_strdup("");

        handle_AdapterChange(proxy, name, iter);
        print_iter(str, name, iter);
        g_free(str);
    }
    else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1"))
    {
        DBusMessageIter addr_iter;
        char *str;

        ctrl = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
        if (!ctrl)
            return;

        if (g_dbus_proxy_get_property(ctrl->proxy, "Address",
                                      &addr_iter) == TRUE)
        {
            const char *address;

            dbus_message_iter_get_basic(&addr_iter, &address);
            str = g_strdup_printf("[" COLORED_CHG
                                  "] Controller %s ",
                                  address);
        }
        else
            str = g_strdup("");

        print_iter(str, name, iter);
        g_free(str);
    }
    else if (!strcmp(interface, "org.bluez.GattCharacteristic1"))
    {
        handle_ChrcChange(proxy, name, iter);
    }
    else
    {
        char *str;

        str = g_strdup_printf("[" COLORED_CHG "] Attribute %s ",
                              g_dbus_proxy_get_path(proxy));

        print_iter(str, name, iter);
        g_free(str);
    }
}

static void client_ready(GDBusClient *client, void *user_data)
{
    dy_syslog(LOG_DEBUG, "%s:%d\n", __FUNCTION__, __LINE__);
    start_work(var);
}

static void connect_handler(DBusConnection *connection, void *user_data)
{
    dy_syslog(LOG_DEBUG, "%s:%d\n", __FUNCTION__, __LINE__);
}

static void disconnect_handler(DBusConnection *connection, void *user_data)
{
    dy_syslog(LOG_DEBUG, "%s:%d\n", __FUNCTION__, __LINE__);
    g_list_free_full(ctrl_list, proxy_free);
    ctrl_list = NULL;
    var->ctrl_list = NULL;
}

static void message_handler(DBusConnection *connection,
                            DBusMessage *message, void *user_data)
{
    dy_syslog(LOG_DEBUG, "[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
           dbus_message_get_member(message));
}

int main(int argc, char *argv[])
{
    GDBusClient *client;
    int status;
    pthread_t thread_sup;

    openlog("BLE", LOG_PID, LOG_DAEMON);

    var = g_malloc0(sizeof(ble_var_t));
    if (var == NULL)
    {
        dy_syslog(LOG_DEBUG, "malloc failed\n");
        return -1;
    }
    mainloop_init();
    auto_register_agent = g_strdup("");

    dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
    g_dbus_attach_object_manager(dbus_conn);
    var->dbus_conn = dbus_conn;

    client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
    var->client = client;

    g_dbus_client_set_connect_watch(client, connect_handler, NULL);
    g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
    g_dbus_client_set_signal_watch(client, message_handler, NULL);

    g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
                                     property_changed, NULL);

    g_dbus_client_set_ready_watch(client, client_ready, NULL);
    dy_syslog(LOG_DEBUG, "%s:%d\n", __FUNCTION__, __LINE__);

    ble_mqtt_init(var);

    pthread_create(&thread_sup, NULL, ble_thread_loop, (void *)var);

    status = mainloop_run();

    g_dbus_client_unref(client);
    dbus_connection_unref(dbus_conn);
    g_list_free_full(ctrl_list, proxy_free);
    g_free(auto_register_agent);
    g_free(var);

    return status;
}
