// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "dynamic_channel_registry.h"

#include <zircon/assert.h>

#include "src/connectivity/bluetooth/core/bt-host/common/log.h"

namespace bt {
namespace l2cap {
namespace internal {

DynamicChannelRegistry::~DynamicChannelRegistry() {
  // Clean up connected channels.
  for (auto& id_and_chan : channels_) {
    auto& chan = id_and_chan.second;
    if (chan->IsConnected()) {
      chan->Disconnect();
    }
  }
}

// Run return callbacks on the L2CAP thread. LogicalLink takes care of out-of-
// thread dispatch for delivering the pointer to the channel.
void DynamicChannelRegistry::OpenOutbound(PSM psm,
                                          DynamicChannelCallback open_cb) {
  const ChannelId id = FindAvailableChannelId();
  if (id == kInvalidChannelId) {
    bt_log(ERROR, "l2cap", "No dynamic channel IDs available");
    open_cb(nullptr);
    return;
  }

  auto iter = channels_.emplace(id, MakeOutbound(psm, id)).first;
  ActivateChannel(iter->second.get(), std::move(open_cb), true);
}

void DynamicChannelRegistry::CloseChannel(ChannelId local_cid) {
  DynamicChannel* channel = FindChannel(local_cid);
  if (!channel) {
    return;
  }

  ZX_DEBUG_ASSERT(channel->IsConnected());
  channel->Disconnect();
  RemoveChannel(channel);
}

DynamicChannelRegistry::DynamicChannelRegistry(
    ChannelId largest_channel_id, DynamicChannelCallback close_cb,
    ServiceRequestCallback service_request_cb)
    : largest_channel_id_(largest_channel_id),
      close_cb_(std::move(close_cb)),
      service_request_cb_(std::move(service_request_cb)) {
  ZX_DEBUG_ASSERT(largest_channel_id_ >= kFirstDynamicChannelId);
  ZX_DEBUG_ASSERT(close_cb_);
  ZX_DEBUG_ASSERT(service_request_cb_);
}

DynamicChannel* DynamicChannelRegistry::RequestService(PSM psm,
                                                       ChannelId local_cid,
                                                       ChannelId remote_cid) {
  ZX_DEBUG_ASSERT(local_cid != kInvalidChannelId);

  DynamicChannelCallback return_chan_cb = service_request_cb_(psm);
  if (!return_chan_cb) {
    bt_log(WARN, "l2cap", "No service found for PSM %#.4x from %#.4x", psm,
           remote_cid);
    return nullptr;
  }

  auto iter =
      channels_.emplace(local_cid, MakeInbound(psm, local_cid, remote_cid))
          .first;
  ActivateChannel(iter->second.get(), std::move(return_chan_cb), false);
  return iter->second.get();
}

ChannelId DynamicChannelRegistry::FindAvailableChannelId() const {
  for (ChannelId id = kFirstDynamicChannelId; id != largest_channel_id_ + 1;
       id++) {
    if (channels_.count(id) == 0) {
      return id;
    }
  }

  return kInvalidChannelId;
}

DynamicChannel* DynamicChannelRegistry::FindChannel(ChannelId local_cid) const {
  auto iter = channels_.find(local_cid);
  if (iter == channels_.end()) {
    return nullptr;
  }
  return iter->second.get();
}

void DynamicChannelRegistry::ActivateChannel(DynamicChannel* channel,
                                             DynamicChannelCallback open_cb,
                                             bool pass_failed) {
  // It's safe to capture |this| here because the callback will be owned by the
  // DynamicChannel, which this registry owns.
  auto return_chan = [this, channel, open_cb = std::move(open_cb),
                      pass_failed]() {
    if (channel->IsOpen()) {
      open_cb(channel);
      return;
    }

    bt_log(TRACE, "l2cap",
           "Failed to open dynamic channel %#.4x (remote %#.4x) for PSM %#.4x",
           channel->local_cid(), channel->remote_cid(), channel->psm());

    // TODO(NET-1084): Maybe negotiate channel parameters here? For now, just
    // disconnect the channel.
    if (channel->IsConnected()) {
      channel->Disconnect();
    }
    if (pass_failed) {
      open_cb(nullptr);
    }

    // This lambda is owned by the channel, so captures are no longer valid
    // after this call.
    RemoveChannel(channel);
  };

  channel->Open(std::move(return_chan));
}

void DynamicChannelRegistry::OnChannelDisconnected(DynamicChannel* channel) {
  if (channel->opened()) {
    close_cb_(channel);
  }
  RemoveChannel(channel);
}

void DynamicChannelRegistry::RemoveChannel(DynamicChannel* channel) {
  ZX_DEBUG_ASSERT(channel);
  ZX_DEBUG_ASSERT(!channel->IsConnected());

  auto iter = channels_.find(channel->local_cid());
  if (iter == channels_.end()) {
    return;
  }

  if (channel != iter->second.get()) {
    return;
  }

  channels_.erase(iter);
}

}  // namespace internal
}  // namespace l2cap
}  // namespace bt
