/**
 * Iterate over routing table and remove entries with value as part of any trail.
 *
 * @param cls closure
 * @param key current public key
 * @param value value in the hash map
 * @return #GNUNET_YES if we should continue to iterate,
 *         #GNUNET_NO if not.
 */
static int
remove_matching_trails (void *cls,
			const struct GNUNET_HashCode *key,
			void *value)
{
  struct RoutingTrail *remove_trail = value;
  struct GNUNET_PeerIdentity *disconnected_peer = cls;
  struct GNUNET_HashCode trail_id = *key;
  struct GNUNET_PeerIdentity my_identity;

  /* If disconnected_peer is next_hop, then send a trail teardown message through
   * prev_hop in direction from destination to source. */
  if (0 == GNUNET_CRYPTO_cmp_peer_identity (&remove_trail->next_hop,
                                            disconnected_peer))
  {
    my_identity = *GDS_NEIGHBOURS_get_id ();
    if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
                                              &remove_trail->prev_hop))
    {
      GDS_NEIGHBOURS_send_trail_teardown (&trail_id,
                                          GDS_ROUTING_DEST_TO_SRC,
                                          &remove_trail->prev_hop);
    }
  }

  /* If disconnected_peer is prev_hop, then send a trail teardown through
   * next_hop in direction from Source to Destination. */
  if (0 == GNUNET_CRYPTO_cmp_peer_identity (&remove_trail->prev_hop,
                                            disconnected_peer))
  {
    my_identity = *GDS_NEIGHBOURS_get_id ();

    if (0 != GNUNET_CRYPTO_cmp_peer_identity (&my_identity,
                                              &remove_trail->next_hop))
    {
      GDS_NEIGHBOURS_send_trail_teardown (&trail_id,
                                          GDS_ROUTING_SRC_TO_DEST,
                                          &remove_trail->next_hop);
    }
  }

  GNUNET_assert (GNUNET_YES ==
                   GNUNET_CONTAINER_multihashmap_remove (routing_table,
                                                         &trail_id,
                                                         remove_trail));
  GNUNET_free (remove_trail);
  return GNUNET_YES;
}
/**
 * @brief Schedule a operation on given peer
 *
 * Avoids scheduling an operation twice.
 *
 * @param peer the peer we want to schedule the operation for once it gets live
 *
 * @return #GNUNET_YES if the operation was scheduled
 *         #GNUNET_NO  otherwise
 */
int
Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
                          const PeerOp peer_op)
{
  struct PeerPendingOp pending_op;
  struct PeerContext *peer_ctx;

  if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
  {
    return GNUNET_NO;
  }
  GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));

  //TODO if LIVE/ONLINE execute immediately

  if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
  {
    peer_ctx = get_peer_ctx (peer);
    pending_op.op = peer_op;
    pending_op.op_cls = NULL;
    GNUNET_array_append (peer_ctx->pending_ops,
                         peer_ctx->num_pending_ops,
                         pending_op);
    return GNUNET_YES;
  }
  return GNUNET_NO;
}
/**
 * @brief Add peer to known peers.
 *
 * This function is called on new peer_ids from 'external' sources
 * (client seed, cadet get_peers(), ...)
 *
 * @param peer the new #GNUNET_PeerIdentity
 *
 * @return #GNUNET_YES if peer was inserted
 *         #GNUNET_NO  otherwise (if peer was already known or
 *                     peer was #own_identity)
 */
int
Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
{
  if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
       (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) )
  {
    return GNUNET_NO; /* We already know this peer - nothing to do */
  }
  (void) create_peer_ctx (peer);
  return GNUNET_YES;
}
/**
 * @brief Try connecting to a peer to see whether it is online
 *
 * If not known yet, insert into known peers
 *
 * @param peer the peer whose liveliness is to be checked
 * @return #GNUNET_YES if peer had to be inserted
 *         #GNUNET_NO  otherwise (if peer was already known or
 *                     peer was #own_identity)
 */
int
Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
{
  struct PeerContext *peer_ctx;
  int ret;

  if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity))
  {
    return GNUNET_NO;
  }
  ret = Peers_insert_peer (peer);
  peer_ctx = get_peer_ctx (peer);
  if (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE))
  {
    check_peer_live (peer_ctx);
  }
  return ret;
}
/**
 * Reinitialise all previously initialised sampler elements with the given value.
 *
 * Used to get rid of a PeerID.
 *
 * @param sampler the sampler to reinitialise a sampler element in.
 * @param id the id of the sampler elements to update.
 */
  void
RPS_sampler_reinitialise_by_value (struct RPS_Sampler *sampler,
                                   const struct GNUNET_PeerIdentity *id)
{
  uint32_t i;
  struct RPS_SamplerElement *trash_entry;

  for ( i = 0 ; i < sampler->sampler_size ; i++ )
  {
    if ( 0 == GNUNET_CRYPTO_cmp_peer_identity(id, &(sampler->sampler_elements[i]->peer_id)) )
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG, "Reinitialising sampler\n");
      trash_entry = GNUNET_new (struct RPS_SamplerElement);
      *trash_entry = *(sampler->sampler_elements[i]);
      to_file (trash_entry->file_name,
               "--- non-active");
      RPS_sampler_elem_reinit (sampler->sampler_elements[i]);
    }
  }