#include "common.h"

static void connect_device_setup(DBusMessageIter *iter, void *user_data)
{
    ble_slave_dev_t *slave_dev = user_data;
    DBusMessageIter dict;

    dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
                                     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
                                         DBUS_TYPE_STRING_AS_STRING
                                             DBUS_TYPE_VARIANT_AS_STRING
                                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
                                     &dict);

    if (slave_dev->addr != NULL)
        g_dbus_dict_append_entry(&dict, "Address", DBUS_TYPE_STRING,
                                 &slave_dev->addr);

    if (slave_dev->AddressType)
        g_dbus_dict_append_entry(&dict, "AddressType",
                                 DBUS_TYPE_STRING,
                                 &slave_dev->AddressType);

    dbus_message_iter_close_container(iter, &dict);
}

static void connect_device_reply(DBusMessage *message, void *user_data)
{
    DBusError error;

    dbus_error_init(&error);
    if (dbus_set_error_from_message(&error, message) == TRUE)
    {
        bt_shell_printf("connect device failed: %s\n", error.name);
        dbus_error_free(&error);
        return bt_shell_noninteractive_quit(EXIT_FAILURE);
    }

    bt_shell_printf("SetDiscoveryFilter success\n");

    return;
}

static void connect_reply(DBusMessage *message, void *user_data)
{
    GDBusProxy *proxy = user_data;
    DBusError error;

    dbus_error_init(&error);

    if (dbus_set_error_from_message(&error, message) == TRUE)
    {
        bt_shell_printf("Failed to connect: %s\n", error.name);
        dbus_error_free(&error);
        return bt_shell_noninteractive_quit(EXIT_FAILURE);
    }

    bt_shell_printf("Connection successful\n");

    return bt_shell_noninteractive_quit(EXIT_SUCCESS);
}

void start_discovery_reply(DBusMessage *message, void *user_data)
{
    struct adapter *adapter = user_data;
    DBusError error;

    dbus_error_init(&error);

    if (dbus_set_error_from_message(&error, message) == TRUE)
    {
        dy_syslog(LOG_DEBUG, "Failed to %s discovery: %s\n",
               "start", error.name);
        dbus_error_free(&error);
        return bt_shell_noninteractive_quit(EXIT_FAILURE);
    }

    adapter->discover_stated = true;

    dy_syslog(LOG_DEBUG, "Discovery started\n");
    /* Leave the discovery running even on noninteractive mode */
}

void stop_discovery_reply(DBusMessage *message, void *user_data)
{
    struct adapter *adapter = user_data;
    DBusError error;

    dbus_error_init(&error);

    if (dbus_set_error_from_message(&error, message) == TRUE)
    {
        dy_syslog(LOG_DEBUG, "Failed to %s discovery: %s\n",
               "stop", error.name);
        dbus_error_free(&error);
        return bt_shell_noninteractive_quit(EXIT_FAILURE);
    }
    adapter->discover_stated = false;

    dy_syslog(LOG_DEBUG, "Discovery stopped\n");
    /* Leave the discovery running even on noninteractive mode */
}

void *connect_devs_loop(void *arg)
{
    ble_slave_cfg_t *slave_cfg = arg;
    GDBusProxy *proxy;
    struct adapter *adapter;
    int i;
    int flag = 0;

    adapter = slave_cfg->adapter;

    while (true)
    {
        flag = 0;
        for (i = 0; i < slave_cfg->dev_cnt; i++)
        {
            ble_slave_dev_t *slave_dev = &slave_cfg->slave[i];
            if (slave_dev->state != SLAVE_DEV_CONNECTED)
            {
                slave_dev->state = SLAVE_DEV_CONNECTING;
                proxy = find_proxy_by_address(adapter->devices, slave_dev->addr);
                if (proxy)
                {
                    dy_syslog(LOG_DEBUG, "known device, use proxy to connect\n");
                    if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
                                                 proxy, NULL) == FALSE)
                    {
                        bt_shell_printf("Failed to connect\n");
                    }
                }
                else
                {
                    flag = 1;
                }
                dy_syslog(LOG_DEBUG, "Attempting to connect to %s\n", slave_dev->addr);
            }
        }

        if (flag == 1)
        {
            if (adapter->discover_stated)
            {
                dy_syslog(LOG_DEBUG, "already start the discovery\n");
            }
            else
            {
                // need start discovery to find the device
                dy_syslog(LOG_DEBUG, "have unkown devices, need start the discorvery\n");
                g_dbus_proxy_method_call(adapter->proxy, "StartDiscovery", NULL, start_discovery_reply, adapter, NULL);
            }
        }
        else
        {
            if (adapter->discover_stated)
            {
                // need start discovery to find the device
                dy_syslog(LOG_DEBUG, "all devices known, need stop the discorvery\n");
                g_dbus_proxy_method_call(adapter->proxy, "StopDiscovery", NULL, stop_discovery_reply, adapter, NULL);
            }
            else
            {
                dy_syslog(LOG_DEBUG, "already stop the discovery\n");
            }
        }

        sleep(10);
    }
}

bool start_connect(ble_slave_cfg_t *slave_cfg)
{
    pthread_t tid;

    int ret = pthread_create(&tid, NULL, connect_devs_loop, (void *)slave_cfg);
    if (ret != 0)
    {
        dy_syslog(LOG_DEBUG, "pthread_create failed:%s\n", ret);
    }

    return true;
}
