// 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 "low_energy_advertising_manager.h"

#include <zircon/assert.h>

#include "low_energy_address_manager.h"
#include "peer.h"
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/common/random.h"
#include "src/connectivity/bluetooth/core/bt-host/common/slab_allocator.h"
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/util.h"
#include "src/lib/fxl/strings/string_printf.h"

namespace bt::gap {

namespace {

// Returns the matching minimum and maximum advertising interval values in controller timeslices.
hci::AdvertisingIntervalRange GetIntervalRange(AdvertisingInterval interval) {
  switch (interval) {
    case AdvertisingInterval::FAST1:
      return {kLEAdvertisingFastIntervalMin1, kLEAdvertisingFastIntervalMax1};
    case AdvertisingInterval::FAST2:
      return {kLEAdvertisingFastIntervalMin2, kLEAdvertisingFastIntervalMax2};
    case AdvertisingInterval::SLOW:
      return {kLEAdvertisingSlowIntervalMin, kLEAdvertisingSlowIntervalMax};
  }

  ZX_PANIC("unexpected advertising interval value");
  return {kLEAdvertisingSlowIntervalMin, kLEAdvertisingSlowIntervalMax};
}

}  // namespace

AdvertisementInstance::AdvertisementInstance() : id_(kInvalidAdvertisementId) {}

AdvertisementInstance::AdvertisementInstance(AdvertisementId id,
                                             fxl::WeakPtr<LowEnergyAdvertisingManager> owner)
    : id_(id), owner_(owner) {
  ZX_DEBUG_ASSERT(id_ != kInvalidAdvertisementId);
  ZX_DEBUG_ASSERT(owner_);
}

AdvertisementInstance::~AdvertisementInstance() { Reset(); }

void AdvertisementInstance::Move(AdvertisementInstance* other) {
  // Destroy the old advertisement instance if active and clear the contents.
  Reset();

  // Transfer the old data over and clear |other| so that it no longer owns its advertisement.
  owner_ = std::move(other->owner_);
  id_ = other->id_;
  other->id_ = kInvalidAdvertisementId;
}

void AdvertisementInstance::Reset() {
  if (owner_ && id_ != kInvalidAdvertisementId) {
    owner_->StopAdvertising(id_);
  }

  owner_.reset();
  id_ = kInvalidAdvertisementId;
}

class LowEnergyAdvertisingManager::ActiveAdvertisement final {
 public:
  // TODO(fxbug.dev/863): Don't randomly generate the ID of an advertisement.
  // Instead use a counter like other internal IDs once this ID is not visible
  // outside of bt-host.
  explicit ActiveAdvertisement(const DeviceAddress& address)
      : address_(address), id_(RandomPeerId().value()) {}

  ~ActiveAdvertisement() = default;

  const DeviceAddress& address() const { return address_; }
  AdvertisementId id() const { return id_; }

 private:
  DeviceAddress address_;
  AdvertisementId id_;

  DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ActiveAdvertisement);
};

LowEnergyAdvertisingManager::LowEnergyAdvertisingManager(
    hci::LowEnergyAdvertiser* advertiser, hci::LocalAddressDelegate* local_addr_delegate)
    : advertiser_(advertiser), local_addr_delegate_(local_addr_delegate), weak_ptr_factory_(this) {
  ZX_DEBUG_ASSERT(advertiser_);
  ZX_DEBUG_ASSERT(local_addr_delegate_);
}

LowEnergyAdvertisingManager::~LowEnergyAdvertisingManager() {
  // Turn off all the advertisements!
  for (const auto& ad : advertisements_) {
    advertiser_->StopAdvertising(ad.second->address());
  }
}

void LowEnergyAdvertisingManager::StartAdvertising(AdvertisingData data, AdvertisingData scan_rsp,
                                                   ConnectionCallback connect_callback,
                                                   AdvertisingInterval interval, bool anonymous,
                                                   bool include_tx_power_level,
                                                   AdvertisingStatusCallback status_callback) {
  // Can't be anonymous and connectable
  if (anonymous && connect_callback) {
    bt_log(DEBUG, "gap-le", "can't advertise anonymously and connectable!");
    status_callback(AdvertisementInstance(), hci::Status(HostError::kInvalidParameters));
    return;
  }

  // v5.1, Vol 3, Part C, Appendix A recommends the FAST1 parameters for connectable advertising and
  // FAST2 parameters for non-connectable advertising. Some Bluetooth controllers reject the FAST1
  // parameters for non-connectable advertising, hence we fall back to FAST2 in that case.
  if (interval == AdvertisingInterval::FAST1 && !connect_callback) {
    interval = AdvertisingInterval::FAST2;
  }
  hci::LowEnergyAdvertiser::AdvertisingOptions options(GetIntervalRange(interval), anonymous,
                                                       AdvFlag::kLEGeneralDiscoverableMode,
                                                       include_tx_power_level);

  auto self = weak_ptr_factory_.GetWeakPtr();

  // TODO(fxbug.dev/1335): The address used for legacy advertising must be
  // coordinated via |local_addr_delegate_| however a unique address can be
  // generated and assigned to each advertising set when the controller
  // supports 5.0 extended advertising. hci::LowEnergyAdvertiser needs to be
  // revised to not use device addresses to distinguish between advertising
  // instances especially since |local_addr_delegate_| is likely to return the
  // same address if called frequently.
  //
  // Revisit this logic when multi-advertising is supported.
  local_addr_delegate_->EnsureLocalAddress(
      [self, data = std::move(data), scan_rsp = std::move(scan_rsp), options,
       connect_cb = std::move(connect_callback),
       status_cb = std::move(status_callback)](const auto& address) mutable {
        if (!self)
          return;

        auto ad_ptr = std::make_unique<ActiveAdvertisement>(address);
        hci::LowEnergyAdvertiser::ConnectionCallback adv_conn_cb;
        if (connect_cb) {
          adv_conn_cb = [self, id = ad_ptr->id(), connect_cb = std::move(connect_cb)](auto link) {
            bt_log(DEBUG, "gap-le", "received new connection");

            if (!self)
              return;

            // remove the advertiser because advertising has stopped
            self->advertisements_.erase(id);
            connect_cb(id, std::move(link));
          };
        }
        auto status_cb_wrapper = [self, ad_ptr = std::move(ad_ptr),
                                  status_cb = std::move(status_cb)](hci::Status status) mutable {
          if (!self)
            return;

          if (!status) {
            status_cb(AdvertisementInstance(), status);
            return;
          }

          auto id = ad_ptr->id();
          self->advertisements_.emplace(id, std::move(ad_ptr));
          status_cb(AdvertisementInstance(id, self), status);
        };

        // Call StartAdvertising, with the callback
        self->advertiser_->StartAdvertising(address, data, scan_rsp, options,
                                            std::move(adv_conn_cb), std::move(status_cb_wrapper));
      });
}

bool LowEnergyAdvertisingManager::StopAdvertising(AdvertisementId advertisement_id) {
  auto it = advertisements_.find(advertisement_id);
  if (it == advertisements_.end())
    return false;

  advertiser_->StopAdvertising(it->second->address());
  advertisements_.erase(it);
  return true;
}

}  // namespace bt::gap
