/*
 * Copyright 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <memory>
#include <unordered_map>

#include "hci/acl_manager/le_acl_connection.h"
#include "hci/address.h"
#include "l2cap/internal/scheduler_fifo.h"
#include "l2cap/le/internal/link.h"
#include "os/handler.h"
#include "os/log.h"

#include "l2cap/le/internal/link_manager.h"

namespace bluetooth {
namespace l2cap {
namespace le {
namespace internal {

void LinkManager::ConnectFixedChannelServices(hci::AddressWithType address_with_type,
                                              PendingFixedChannelConnection pending_fixed_channel_connection) {
  // Check if there is any service registered
  auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
  if (fixed_channel_services.empty()) {
    // If so, return error
    pending_fixed_channel_connection.handler_->Post(common::BindOnce(
        std::move(pending_fixed_channel_connection.on_fail_callback_),
        FixedChannelManager::ConnectionResult{
            .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED}));
    return;
  }
  // Otherwise, check if device has an ACL connection
  auto* link = GetLink(address_with_type);
  if (link != nullptr) {
    // If device already have an ACL connection
    // Check if all registered services have an allocated channel and allocate one if not already allocated
    int num_new_channels = 0;
    for (auto& fixed_channel_service : fixed_channel_services) {
      if (link->IsFixedChannelAllocated(fixed_channel_service.first)) {
        // This channel is already allocated for this link, do not allocated twice
        continue;
      }
      // Allocate channel for newly registered fixed channels
      auto fixed_channel_impl = link->AllocateFixedChannel(
          fixed_channel_service.first, SecurityPolicy::NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK);
      fixed_channel_service.second->NotifyChannelCreation(
          std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
      num_new_channels++;
    }
    // Declare connection failure if no new channels are created
    if (num_new_channels == 0) {
      pending_fixed_channel_connection.handler_->Post(common::BindOnce(
          std::move(pending_fixed_channel_connection.on_fail_callback_),
          FixedChannelManager::ConnectionResult{
              .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL}));
    }
    // No need to create ACL connection, return without saving any pending connections
    return;
  }
  // If not, create new ACL connection
  // Add request to pending link list first
  auto pending_link = pending_links_.find(address_with_type);
  if (pending_link == pending_links_.end()) {
    // Create pending link if not exist
    pending_links_.try_emplace(address_with_type);
    pending_link = pending_links_.find(address_with_type);
  }
  pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection));
  // Then create new ACL connection
  acl_manager_->CreateLeConnection(address_with_type, /* is_direct */ true);
}

void LinkManager::ConnectDynamicChannelServices(
    hci::AddressWithType device, Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm) {
  auto* link = GetLink(device);
  if (link == nullptr) {
    acl_manager_->CreateLeConnection(device, /* is_direct */ true);
    pending_dynamic_channels_[device].push_back(std::make_pair(psm, std::move(pending_dynamic_channel_connection)));
    return;
  }
  link->SendConnectionRequest(psm, std::move(pending_dynamic_channel_connection));
}

Link* LinkManager::GetLink(hci::AddressWithType address_with_type) {
  if (links_.find(address_with_type) == links_.end()) {
    return nullptr;
  }
  return &links_.find(address_with_type)->second;
}

void LinkManager::OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type,
                                     std::unique_ptr<hci::acl_manager::LeAclConnection> acl_connection) {
  // Same link should not be connected twice
  hci::AddressWithType connected_address_with_type = acl_connection->GetRemoteAddress();
  uint16_t handle = acl_connection->GetHandle();
  ASSERT_LOG(GetLink(connected_address_with_type) == nullptr, "%s is connected twice without disconnection",
             acl_connection->GetRemoteAddress().ToString().c_str());
  links_.try_emplace(connected_address_with_type, l2cap_handler_, std::move(acl_connection), parameter_provider_,
                     dynamic_channel_service_manager_, fixed_channel_service_manager_, this);
  auto* link = GetLink(connected_address_with_type);

  if (link_property_callback_handler_ != nullptr) {
    link_property_callback_handler_->CallOn(
        link_property_listener_,
        &LinkPropertyListener::OnLinkConnected,
        connected_address_with_type,
        handle,
        link->GetRole());
  }

  // Remove device from pending links list, if any
  pending_links_.erase(connecting_address_with_type);

  link->ReadRemoteVersionInformation();
}

void LinkManager::OnLeConnectFail(hci::AddressWithType address_with_type, hci::ErrorCode reason) {
  // Notify all pending links for this device
  auto pending_link = pending_links_.find(address_with_type);
  if (pending_link == pending_links_.end()) {
    // There is no pending link, exit
    LOG_INFO("Connection to %s failed without a pending link", address_with_type.ToString().c_str());
    return;
  }
  for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) {
    pending_fixed_channel_connection.handler_->Post(common::BindOnce(
        std::move(pending_fixed_channel_connection.on_fail_callback_),
        FixedChannelManager::ConnectionResult{
            .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason}));
  }
  // Remove entry in pending link list
  pending_links_.erase(pending_link);
}

void LinkManager::OnDisconnect(bluetooth::hci::AddressWithType address_with_type) {
  auto* link = GetLink(address_with_type);
  ASSERT_LOG(link != nullptr, "Device %s is disconnected but not in local database",
             address_with_type.ToString().c_str());
  if (links_with_pending_packets_.count(address_with_type) != 0) {
    disconnected_links_.emplace(address_with_type);
  } else {
    links_.erase(address_with_type);
  }

  if (link_property_callback_handler_ != nullptr) {
    link_property_callback_handler_->CallOn(
        link_property_listener_, &LinkPropertyListener::OnLinkDisconnected, address_with_type);
  }
}

void LinkManager::RegisterLinkPropertyListener(os::Handler* handler, LinkPropertyListener* listener) {
  link_property_callback_handler_ = handler;
  link_property_listener_ = listener;
}

void LinkManager::OnReadRemoteVersionInformationComplete(
    hci::ErrorCode hci_status,
    hci::AddressWithType address_with_type,
    uint8_t lmp_version,
    uint16_t manufacturer_name,
    uint16_t sub_version) {
  if (link_property_callback_handler_ != nullptr) {
    link_property_callback_handler_->CallOn(
        link_property_listener_,
        &LinkPropertyListener::OnReadRemoteVersionInformation,
        hci_status,
        address_with_type,
        lmp_version,
        manufacturer_name,
        sub_version);
  }

  auto* link = GetLink(address_with_type);
  // Allocate and distribute channels for all registered fixed channel services
  auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
  for (auto& fixed_channel_service : fixed_channel_services) {
    auto fixed_channel_impl = link->AllocateFixedChannel(
        fixed_channel_service.first, SecurityPolicy::NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK);
    fixed_channel_service.second->NotifyChannelCreation(
        std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
  }
  if (pending_dynamic_channels_.find(address_with_type) != pending_dynamic_channels_.end()) {
    for (auto& psm_callback : pending_dynamic_channels_[address_with_type]) {
      link->SendConnectionRequest(psm_callback.first, std::move(psm_callback.second));
    }
    pending_dynamic_channels_.erase(address_with_type);
  }
}

void LinkManager::OnPendingPacketChange(hci::AddressWithType remote, int num_packets) {
  if (disconnected_links_.count(remote) != 0 && num_packets == 0) {
    links_.erase(remote);
    links_with_pending_packets_.erase(remote);
  } else if (num_packets != 0) {
    links_with_pending_packets_.emplace(remote);
  } else {
    links_with_pending_packets_.erase(remote);
  }
}

}  // namespace internal
}  // namespace le
}  // namespace l2cap
}  // namespace bluetooth
