/* Try to send a friend request to peer with public_key.
 * data is the data in the request and length is the length.
 * return -1 if failure.
 * return  0 if it sent the friend request directly to the friend.
 * return the number of peers it was routed through if it did not send it directly.
 */
int send_friendrequest(DHT *dht, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length)
{
    if (length + sizeof(nospam_num) > MAX_DATA_SIZE)
        return -1;

    uint8_t temp[MAX_DATA_SIZE];
    memcpy(temp, &nospam_num, sizeof(nospam_num));
    memcpy(temp + sizeof(nospam_num), data, length);
    uint8_t packet[MAX_DATA_SIZE];
    int len = create_request(dht->c->self_public_key, dht->c->self_secret_key, packet, public_key, temp,
                             length + sizeof(nospam_num),
                             CRYPTO_PACKET_FRIEND_REQ);

    if (len == -1)
        return -1;

    IP_Port ip_port = DHT_getfriendip(dht, public_key);

    if (ip_port.ip.uint32 == 1)
        return -1;

    if (ip_port.ip.uint32 != 0) {
        if (sendpacket(dht->c->lossless_udp->net->sock, ip_port, packet, len) != -1)
            return 0;

        return -1;
    }

    int num = route_tofriend(dht, public_key, packet, len);

    if (num == 0)
        return -1;

    return num;
}
/* Try to send the fakeid via the DHT instead of onion
 *
 * Even if this function succeeds, the friend might not recieve any data.
 *
 * return the number of packets sent on success
 * return -1 on failure.
 */
static int send_dht_fakeid(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32_t length)
{
    if ((uint32_t)friend_num >= onion_c->num_friends)
        return -1;

    if (!onion_c->friends_list[friend_num].is_fake_clientid)
        return -1;

    uint8_t nonce[crypto_box_NONCEBYTES];
    new_nonce(nonce);

    uint8_t temp[DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES + length];
    memcpy(temp, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES);
    memcpy(temp + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
    int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data,
                           length, temp + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);

    if ((uint32_t)len + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES != sizeof(temp))
        return -1;

    uint8_t packet[MAX_DATA_SIZE];
    len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet,
                         onion_c->friends_list[friend_num].fake_client_id, temp, sizeof(temp), FAKEID_DATA_ID);

    if (len == -1)
        return -1;

    return route_tofriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, packet, len);
}
/* Try to send a friendrequest to peer with public_key
   data is the data in the request and length is the length.
   return -1 if failure.
   return  0 if it sent the friend request directly to the friend.
   return the number of peers it was routed through if it did not send it directly.*/
int send_friendrequest(uint8_t * public_key, uint8_t * data, uint32_t length)
{
    uint8_t packet[MAX_DATA_SIZE];
    int len = create_request(packet, public_key, data, length, 32); /* 32 is friend request packet id */

    if (len == -1)
        return -1;

    IP_Port ip_port = DHT_getfriendip(public_key);

    if (ip_port.ip.i == 1)
        return -1;

    if (ip_port.ip.i != 0) {
        if (sendpacket(ip_port, packet, len) != -1)
            return 0;
        return -1;
    }

    int num = route_tofriend(public_key, packet, len);

    if (num == 0)
        return -1;

    return num;
}