// Copyright 2017 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 "transport.h"

#include <lib/async/default.h>
#include <lib/zx/channel.h>
#include <zircon/assert.h>
#include <zircon/status.h>

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

namespace bt::hci {

fit::result<std::unique_ptr<Transport>> Transport::Create(
    std::unique_ptr<DeviceWrapper> hci_device) {
  auto transport = std::unique_ptr<Transport>(new Transport(std::move(hci_device)));
  if (!transport->command_channel()) {
    return fit::error();
  }
  return fit::ok(std::move(transport));
}

Transport::Transport(std::unique_ptr<DeviceWrapper> hci_device)
    : hci_device_(std::move(hci_device)), weak_ptr_factory_(this) {
  ZX_ASSERT(hci_device_);

  bt_log(INFO, "hci", "initializing HCI");

  // Obtain command channel handle.
  zx::channel channel = hci_device_->GetCommandChannel();
  if (!channel.is_valid()) {
    bt_log(ERROR, "hci", "failed to obtain command channel handle");
    return;
  }

  // We watch for handle errors and closures to perform the necessary clean up.
  WatchChannelClosed(channel, cmd_channel_wait_);

  auto command_channel_result = CommandChannel::Create(this, std::move(channel));
  if (command_channel_result.is_error()) {
    return;
  }
  command_channel_ = command_channel_result.take_value();
  command_channel_->set_channel_timeout_cb(fit::bind_member(this, &Transport::OnChannelError));
}

Transport::~Transport() {
  ZX_ASSERT(thread_checker_.is_thread_valid());

  bt_log(INFO, "hci", "transport shutting down");

  if (acl_data_channel_) {
    acl_data_channel_->ShutDown();
  }
  if (command_channel_) {
    command_channel_->ShutDown();
  }

  cmd_channel_wait_.Cancel();
  if (acl_data_channel_) {
    acl_channel_wait_.Cancel();
  }

  bt_log(INFO, "hci", "transport shut down complete");
}

bool Transport::InitializeACLDataChannel(const DataBufferInfo& bredr_buffer_info,
                                         const DataBufferInfo& le_buffer_info) {
  // Obtain ACL data channel handle.
  zx::channel channel = hci_device_->GetACLDataChannel();
  if (!channel.is_valid()) {
    bt_log(ERROR, "hci", "failed to obtain ACL data channel handle");
    return false;
  }

  // We watch for handle errors and closures to perform the necessary clean up.
  WatchChannelClosed(channel, acl_channel_wait_);

  acl_data_channel_ = AclDataChannel::Create(this, std::move(channel));
  acl_data_channel_->Initialize(bredr_buffer_info, le_buffer_info);

  return true;
}

bt_vendor_features_t Transport::GetVendorFeatures() { return hci_device_->GetVendorFeatures(); }

fit::result<DynamicByteBuffer> Transport::EncodeVendorCommand(bt_vendor_command_t command,
                                                              bt_vendor_params_t& params) {
  return hci_device_->EncodeVendorCommand(command, params);
}

void Transport::SetTransportClosedCallback(fit::closure callback) {
  ZX_ASSERT(callback);
  ZX_ASSERT(!closed_cb_);
  closed_cb_ = std::move(callback);
}

void Transport::WatchChannelClosed(const zx::channel& channel, Waiter& wait) {
  wait.set_object(channel.get());
  wait.set_trigger(ZX_CHANNEL_PEER_CLOSED);
  zx_status_t status = wait.Begin(async_get_default_dispatcher());
  if (status != ZX_OK) {
    bt_log(ERROR, "hci", "failed to set up closed handler: %s", zx_status_get_string(status));
    wait.set_object(ZX_HANDLE_INVALID);
  }
}

void Transport::OnChannelClosed(async_dispatcher_t* dispatcher, async::WaitBase* wait,
                                zx_status_t status, const zx_packet_signal_t* signal) {
  if (status != ZX_OK) {
    bt_log(ERROR, "hci", "channel error: %s", zx_status_get_string(status));
  } else {
    ZX_DEBUG_ASSERT(signal->observed & ZX_CHANNEL_PEER_CLOSED);
  }
  NotifyClosedCallback();
}

void Transport::NotifyClosedCallback() {
  // Clear the handlers so that we stop receiving events.
  cmd_channel_wait_.Cancel();
  if (acl_data_channel_) {
    acl_channel_wait_.Cancel();
  }

  bt_log(INFO, "hci", "channel(s) were closed");
  if (closed_cb_) {
    closed_cb_();
  }
}

void Transport::OnChannelError() {
  bt_log(ERROR, "hci", "channel error");

  // TODO(fxbug.dev/52588): remove calls to ShutDown() here as Host will destroy Transport in closed
  // callback
  if (acl_data_channel_) {
    acl_data_channel_->ShutDown();
  }
  if (command_channel_) {
    command_channel_->ShutDown();
  }

  NotifyClosedCallback();
}

}  // namespace bt::hci
