//
//  Copyright (C) 2015 Google, Inc.
//
//  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 "service/hal/bluetooth_gatt_interface.h"

#include <mutex>
#define _LIBCPP_BUILDING_SHARED_MUTEX
#include <shared_mutex>
#undef _LIBCPP_BUILDING_SHARED_MUTEX

#include <base/logging.h>
#include <base/observer_list.h>

#include "service/hal/bluetooth_interface.h"
#include "service/logging_helpers.h"

using std::lock_guard;
using std::unique_lock;
using std::shared_lock;
using std::mutex;
using std::shared_timed_mutex;

namespace bluetooth {
namespace hal {

namespace {

// The global BluetoothGattInterface instance.
BluetoothGattInterface* g_interface = nullptr;

// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
// use unique_lock. If only accessing |g_interface| use shared lock.
//TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
// timed methods. Change to shared_mutex when we upgrade to C++14
shared_timed_mutex g_instance_lock;

// Helper for obtaining the observer lists. This is forward declared here
// and defined below since it depends on BluetoothInterfaceImpl.
base::ObserverList<BluetoothGattInterface::ClientObserver>*
    GetClientObservers();
base::ObserverList<BluetoothGattInterface::ServerObserver>*
    GetServerObservers();

#define FOR_EACH_CLIENT_OBSERVER(func) \
  FOR_EACH_OBSERVER(BluetoothGattInterface::ClientObserver, \
                    *GetClientObservers(), func)

#define FOR_EACH_SERVER_OBSERVER(func) \
  FOR_EACH_OBSERVER(BluetoothGattInterface::ServerObserver, \
                    *GetServerObservers(), func)

#define VERIFY_INTERFACE_OR_RETURN() \
  do { \
    if (!g_interface) { \
      LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
      return; \
    } \
  } while (0)

void RegisterClientCallback(int status, int client_if, bt_uuid_t* app_uuid) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(app_uuid);

  FOR_EACH_CLIENT_OBSERVER(
      RegisterClientCallback(g_interface, status, client_if, *app_uuid));
}

void ScanResultCallback(bt_bdaddr_t* bda, int rssi, uint8_t* adv_data) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(bda);
  CHECK(adv_data);

  VLOG(2) << __func__ << " - BD_ADDR: " << BtAddrString(bda)
          << " RSSI: " << rssi;
  FOR_EACH_CLIENT_OBSERVER(
    ScanResultCallback(g_interface, *bda, rssi, adv_data));
}

void ConnectCallback(int conn_id, int status, int client_if, bt_bdaddr_t* bda) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(bda);

  VLOG(2) << __func__ << " - status: " << status
          << " client_if: " << client_if
          << " - BD_ADDR: " << BtAddrString(bda)
          << " - conn_id: " << conn_id;

  FOR_EACH_CLIENT_OBSERVER(
    ConnectCallback(g_interface, conn_id, status, client_if, *bda));
}

void DisconnectCallback(int conn_id, int status, int client_if,
                        bt_bdaddr_t* bda) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(bda);

  VLOG(2) << __func__ << " - conn_id: " << conn_id
             << " - status: " << status
             << " client_if: " << client_if
             << " - BD_ADDR: " << BtAddrString(bda);
  FOR_EACH_CLIENT_OBSERVER(
    DisconnectCallback(g_interface, conn_id, status, client_if, *bda));
}

void SearchCompleteCallback(int conn_id, int status) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();

  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " - status: " << status;
  FOR_EACH_CLIENT_OBSERVER(
    SearchCompleteCallback(g_interface, conn_id, status));
}

void SearchResultCallback(int conn_id, btgatt_srvc_id_t *srvc_id) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();

  VLOG(2) << __func__ << " - conn_id: " << conn_id;
  // do not propagate this event, will do service discovery with new HAL call
}

void RegisterForNotificationCallback(int conn_id, int registered, int status,
                                      btgatt_srvc_id_t *srvc_id,
                                      btgatt_gatt_id_t *char_id) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();

  LOG(INFO) << __func__ << " - conn_id: " << conn_id
          << " - status: " << status
          << " - registered: " << registered
          << " - srvc_id: " << (srvc_id ? srvc_id->id.inst_id : 0)
          << " - char_id: " << (char_id ? char_id->inst_id : 0);
  FOR_EACH_CLIENT_OBSERVER(
    RegisterForNotificationCallback(g_interface, conn_id, status, registered,
                                    srvc_id, char_id));
}

void NotifyCallback(int conn_id, btgatt_notify_params_t *p_data) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();

  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " - address: " << BtAddrString(&p_data->bda)
          << " - srvc_id: " << (p_data ? p_data->srvc_id.id.inst_id : 0)
          << " - char_id: " << (p_data ? p_data->char_id.inst_id : 0)
          << " - len: " << p_data->len
          << " - is_notify: " << p_data->is_notify;

  FOR_EACH_CLIENT_OBSERVER(
    NotifyCallback(g_interface, conn_id, p_data));
}

void WriteCharacteristicCallback(int conn_id, int status,
      btgatt_write_params_t *p_data) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();

  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " - status: " << status;

  FOR_EACH_CLIENT_OBSERVER(
    WriteCharacteristicCallback(g_interface, conn_id, status, p_data));
}

void WriteDescriptorCallback(int conn_id, int status,
      btgatt_write_params_t *p_data) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();

  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " - status: " << status;

  FOR_EACH_CLIENT_OBSERVER(
    WriteDescriptorCallback(g_interface, conn_id, status, p_data));
}

void ListenCallback(int status, int client_if) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(ListenCallback(g_interface, status, client_if));
}

void MtuChangedCallback(int conn_id, int status, int mtu) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VERIFY_INTERFACE_OR_RETURN();

  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " status: " << status
          << " mtu: " << mtu;

  FOR_EACH_CLIENT_OBSERVER(MtuChangedCallback(g_interface, conn_id, status, mtu));
}

void MultiAdvEnableCallback(int client_if, int status) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(
      MultiAdvEnableCallback(g_interface, client_if, status));
}

void MultiAdvUpdateCallback(int client_if, int status) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(
      MultiAdvUpdateCallback(g_interface, client_if, status));
}

void MultiAdvDataCallback(int client_if, int status) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(
      MultiAdvDataCallback(g_interface, client_if, status));
}

void MultiAdvDisableCallback(int client_if, int status) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(
      MultiAdvDisableCallback(g_interface, client_if, status));
}

void GetGattDbCallback(int conn_id, btgatt_db_element_t *db, int size) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id << " size: " << size;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(
      GetGattDbCallback(g_interface, conn_id, db, size));
}

void ServicesRemovedCallback(int conn_id, uint16_t start_handle, uint16_t end_handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " start_handle: " << start_handle
          << " end_handle: " << end_handle;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(
      ServicesRemovedCallback(g_interface, conn_id, start_handle, end_handle));
}

void ServicesAddedCallback(int conn_id, btgatt_db_element_t *added, int added_count) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " added_count: " << added_count;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_CLIENT_OBSERVER(
      ServicesAddedCallback(g_interface, conn_id, added, added_count));
}

void RegisterServerCallback(int status, int server_if, bt_uuid_t* app_uuid) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(app_uuid);

  FOR_EACH_SERVER_OBSERVER(
      RegisterServerCallback(g_interface, status, server_if, *app_uuid));
}

void ConnectionCallback(int conn_id, int server_if, int connected,
                        bt_bdaddr_t* bda) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id
          << " server_if: " << server_if << " connected: " << connected;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(bda);

  FOR_EACH_SERVER_OBSERVER(
      ConnectionCallback(g_interface, conn_id, server_if, connected, *bda));
}

void ServiceAddedCallback(
    int status,
    int server_if,
    btgatt_srvc_id_t* srvc_id,
    int srvc_handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
          << " handle: " << srvc_handle;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(srvc_id);

  FOR_EACH_SERVER_OBSERVER(ServiceAddedCallback(
      g_interface, status, server_if, *srvc_id, srvc_handle));
}

void CharacteristicAddedCallback(
    int status, int server_if,
    bt_uuid_t* uuid,
    int srvc_handle,
    int char_handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
          << " srvc_handle: " << srvc_handle << " char_handle: " << char_handle;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(uuid);

  FOR_EACH_SERVER_OBSERVER(CharacteristicAddedCallback(
      g_interface, status, server_if, *uuid, srvc_handle, char_handle));
}

void DescriptorAddedCallback(
    int status, int server_if,
    bt_uuid_t* uuid,
    int srvc_handle,
    int desc_handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
          << " srvc_handle: " << srvc_handle << " desc_handle: " << desc_handle;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(uuid);

  FOR_EACH_SERVER_OBSERVER(DescriptorAddedCallback(
      g_interface, status, server_if, *uuid, srvc_handle, desc_handle));
}

void ServiceStartedCallback(int status, int server_if, int srvc_handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
          << " handle: " << srvc_handle;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_SERVER_OBSERVER(ServiceStartedCallback(
      g_interface, status, server_if, srvc_handle));
}

void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
          << " handle: " << srvc_handle;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_SERVER_OBSERVER(ServiceStoppedCallback(
      g_interface, status, server_if, srvc_handle));
}

void ServiceDeletedCallback(int status, int server_if, int srvc_handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
          << " handle: " << srvc_handle;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_SERVER_OBSERVER(ServiceDeletedCallback(
      g_interface, status, server_if, srvc_handle));
}

void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
                         int attr_handle, int offset, bool is_long) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
          << " attr_handle: " << attr_handle << " offset: " << offset
          << " is_long: " << is_long;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(bda);

  FOR_EACH_SERVER_OBSERVER(RequestReadCallback(
      g_interface, conn_id, trans_id, *bda, attr_handle, offset, is_long));
}

void RequestWriteCallback(int conn_id, int trans_id,
                          bt_bdaddr_t* bda,
                          int attr_handle, int offset, int length,
                          bool need_rsp, bool is_prep, uint8_t* value) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
          << " attr_handle: " << attr_handle << " offset: " << offset
          << " length: " << length << " need_rsp: " << need_rsp
          << " is_prep: " << is_prep;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(bda);

  FOR_EACH_SERVER_OBSERVER(RequestWriteCallback(
      g_interface, conn_id, trans_id, *bda, attr_handle, offset, length,
      need_rsp, is_prep, value));
}

void RequestExecWriteCallback(int conn_id, int trans_id,
                              bt_bdaddr_t* bda, int exec_write) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
          << " exec_write: " << exec_write;
  VERIFY_INTERFACE_OR_RETURN();
  CHECK(bda);

  FOR_EACH_SERVER_OBSERVER(RequestExecWriteCallback(
      g_interface, conn_id, trans_id, *bda, exec_write));
}

void ResponseConfirmationCallback(int status, int handle) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - status: " << status << " handle: " << handle;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_SERVER_OBSERVER(ResponseConfirmationCallback(
      g_interface, status, handle));
}

void IndicationSentCallback(int conn_id, int status) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id << " status: " << status;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_SERVER_OBSERVER(IndicationSentCallback(
      g_interface, conn_id, status));
}

void MtuChangedCallback(int conn_id, int mtu) {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  VLOG(2) << __func__ << " - conn_id: " << conn_id << " mtu: " << mtu;
  VERIFY_INTERFACE_OR_RETURN();

  FOR_EACH_SERVER_OBSERVER(MtuChangedCallback(g_interface, conn_id, mtu));
}

// The HAL Bluetooth GATT client interface callbacks. These signal a mixture of
// GATT client-role and GAP events.
const btgatt_client_callbacks_t gatt_client_callbacks = {
    RegisterClientCallback,
    ScanResultCallback,
    ConnectCallback,
    DisconnectCallback,
    SearchCompleteCallback,
    SearchResultCallback,
    nullptr,  // get_characteristic_cb
    nullptr,  // get_descriptor_cb
    nullptr,  // get_included_service_cb
    RegisterForNotificationCallback,
    NotifyCallback,
    nullptr,  // read_characteristic_cb
    WriteCharacteristicCallback,
    nullptr,  // read_descriptor_cb
    WriteDescriptorCallback,
    nullptr,  // execute_write_cb
    nullptr,  // read_remote_rssi_cb
    ListenCallback,
    MtuChangedCallback,
    nullptr,  // scan_filter_cfg_cb
    nullptr,  // scan_filter_param_cb
    nullptr,  // scan_filter_status_cb
    MultiAdvEnableCallback,
    MultiAdvUpdateCallback,
    MultiAdvDataCallback,
    MultiAdvDisableCallback,
    nullptr,  // congestion_cb
    nullptr,  // batchscan_cfg_storage_cb
    nullptr,  // batchscan_enb_disable_cb
    nullptr,  // batchscan_reports_cb
    nullptr,  // batchscan_threshold_cb
    nullptr,  // track_adv_event_cb
    nullptr,  // scan_parameter_setup_completed_cb
    GetGattDbCallback,
    ServicesRemovedCallback,
    ServicesAddedCallback,
};

const btgatt_server_callbacks_t gatt_server_callbacks = {
    RegisterServerCallback,
    ConnectionCallback,
    ServiceAddedCallback,
    nullptr,  // included_service_added_cb
    CharacteristicAddedCallback,
    DescriptorAddedCallback,
    ServiceStartedCallback,
    ServiceStoppedCallback,
    ServiceDeletedCallback,
    RequestReadCallback,
    RequestWriteCallback,
    RequestExecWriteCallback,
    ResponseConfirmationCallback,
    IndicationSentCallback,
    nullptr,  // congestion_cb
    MtuChangedCallback,
};

const btgatt_callbacks_t gatt_callbacks = {
  sizeof(btgatt_callbacks_t),
  &gatt_client_callbacks,
  &gatt_server_callbacks
};

}  // namespace

// BluetoothGattInterface implementation for production.
class BluetoothGattInterfaceImpl : public BluetoothGattInterface {
 public:
  BluetoothGattInterfaceImpl() : hal_iface_(nullptr) {
  }

  ~BluetoothGattInterfaceImpl() override {
    if (hal_iface_)
        hal_iface_->cleanup();
  }

  // BluetoothGattInterface overrides:
  void AddClientObserver(ClientObserver* observer) override {
    client_observers_.AddObserver(observer);
  }

  void RemoveClientObserver(ClientObserver* observer) override {
    client_observers_.RemoveObserver(observer);
  }

  void AddServerObserver(ServerObserver* observer) override {
    server_observers_.AddObserver(observer);
  }

  void RemoveServerObserver(ServerObserver* observer) override {
    server_observers_.RemoveObserver(observer);
  }

  const btgatt_client_interface_t* GetClientHALInterface() const override {
    return hal_iface_->client;
  }

  const btgatt_server_interface_t* GetServerHALInterface() const override {
    return hal_iface_->server;
  }

  // Initialize the interface.
  bool Initialize() {
    const bt_interface_t* bt_iface =
        BluetoothInterface::Get()->GetHALInterface();
    CHECK(bt_iface);

    const btgatt_interface_t* gatt_iface =
        reinterpret_cast<const btgatt_interface_t*>(
            bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
    if (!gatt_iface) {
      LOG(ERROR) << "Failed to obtain HAL GATT interface handle";
      return false;
    }

    bt_status_t status = gatt_iface->init(&gatt_callbacks);
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "Failed to initialize HAL GATT interface";
      return false;
    }

    hal_iface_ = gatt_iface;

    return true;
  }

  base::ObserverList<ClientObserver>* client_observers() {
    return &client_observers_;
  }

  base::ObserverList<ServerObserver>* server_observers() {
    return &server_observers_;
  }

 private:
  // List of observers that are interested in notifications from us.
  // We're not using a base::ObserverListThreadSafe, which it posts observer
  // events automatically on the origin threads, as we want to avoid that
  // overhead and simply forward the events to the upper layer.
  base::ObserverList<ClientObserver> client_observers_;
  base::ObserverList<ServerObserver> server_observers_;

  // The HAL handle obtained from the shared library. We hold a weak reference
  // to this since the actual data resides in the shared Bluetooth library.
  const btgatt_interface_t* hal_iface_;

  DISALLOW_COPY_AND_ASSIGN(BluetoothGattInterfaceImpl);
};

namespace {

base::ObserverList<BluetoothGattInterface::ClientObserver>*
GetClientObservers() {
  CHECK(g_interface);
  return static_cast<BluetoothGattInterfaceImpl*>(
      g_interface)->client_observers();
}

base::ObserverList<BluetoothGattInterface::ServerObserver>*
GetServerObservers() {
  CHECK(g_interface);
  return static_cast<BluetoothGattInterfaceImpl*>(
      g_interface)->server_observers();
}

}  // namespace

// Default observer implementations. These are provided so that the methods
// themselves are optional.
void BluetoothGattInterface::ClientObserver::RegisterClientCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* client_if */,
    const bt_uuid_t& /* app_uuid */) {
  // Do nothing.
}
void BluetoothGattInterface::ClientObserver::ScanResultCallback(
    BluetoothGattInterface* /* gatt_iface */,
    const bt_bdaddr_t& /* bda */,
    int /* rssi */,
    uint8_t* /* adv_data */) {
  // Do Nothing.
}

void BluetoothGattInterface::ClientObserver::ConnectCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* status */,
    int /* client_if */,
    const bt_bdaddr_t& /* bda */) {
  // Do nothing
}

void BluetoothGattInterface::ClientObserver::DisconnectCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* status */,
    int /* client_if */,
    const bt_bdaddr_t& /* bda */) {
  // Do nothing
}

void BluetoothGattInterface::ClientObserver::SearchCompleteCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* status */) {
  // Do nothing
}

void BluetoothGattInterface::ClientObserver::RegisterForNotificationCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* status */,
    int /* registered */,
    btgatt_srvc_id_t* /* srvc_id */,
    btgatt_gatt_id_t* /* char_id */) {
  // Do nothing
}

void BluetoothGattInterface::ClientObserver::NotifyCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    btgatt_notify_params_t* /* p_data */) {
  // Do nothing
}

void BluetoothGattInterface::ClientObserver::WriteCharacteristicCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* status */,
    btgatt_write_params_t* /* p_data */) {
  // Do nothing
}

void BluetoothGattInterface::ClientObserver::WriteDescriptorCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* status */,
    btgatt_write_params_t* /* p_data */) {
  // Do nothing
}

void BluetoothGattInterface::ClientObserver::ListenCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* client_if */) {
  // Do nothing.
}

void BluetoothGattInterface::ClientObserver::MtuChangedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* statis*/,
    int /* mtu */) {
  // Do nothing.
}

void BluetoothGattInterface::ClientObserver::MultiAdvEnableCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* client_if */) {
  // Do nothing.
}
void BluetoothGattInterface::ClientObserver::MultiAdvUpdateCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* client_if */) {
  // Do nothing.
}
void BluetoothGattInterface::ClientObserver::MultiAdvDataCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* client_if */) {
  // Do nothing.
}
void BluetoothGattInterface::ClientObserver::MultiAdvDisableCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* client_if */) {
  // Do nothing.
}

void BluetoothGattInterface::ClientObserver::GetGattDbCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    btgatt_db_element_t* /* gatt_db */,
    int /* size */) {
  // Do nothing.
}

void BluetoothGattInterface::ClientObserver::ServicesRemovedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    uint16_t /* start_handle */,
    uint16_t /* end_handle */) {
  // Do nothing.
}

void BluetoothGattInterface::ClientObserver::ServicesAddedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    btgatt_db_element_t* /* added */,
    int /* added_count */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::RegisterServerCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* server_if */,
    const bt_uuid_t& /* app_uuid */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::ConnectionCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* server_if */,
    int /* connected */,
    const bt_bdaddr_t& /* bda */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::ServiceAddedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* server_if */,
    const btgatt_srvc_id_t& /* srvc_id */,
    int /* srvc_handle */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::CharacteristicAddedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* server_if */,
    const bt_uuid_t& /* uuid */,
    int /* srvc_handle */,
    int /* char_handle */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::DescriptorAddedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* server_if */,
    const bt_uuid_t& /* uuid */,
    int /* srvc_handle */,
    int /* desc_handle */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::ServiceStartedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* server_if */,
    int /* srvc_handle */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::ServiceStoppedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* server_if */,
    int /* srvc_handle */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::ServiceDeletedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* server_if */,
    int /* srvc_handle */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::RequestReadCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* trans_id */,
    const bt_bdaddr_t& /* bda */,
    int /* attr_handle */,
    int /* offset */,
    bool /* is_long */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::RequestWriteCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* trans_id */,
    const bt_bdaddr_t& /* bda */,
    int /* attr_handle */,
    int /* offset */,
    int /* length */,
    bool /* need_rsp */,
    bool /* is_prep */,
    uint8_t* /* value */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::RequestExecWriteCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* trans_id */,
    const bt_bdaddr_t& /* bda */,
    int /* exec_write */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::ResponseConfirmationCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* status */,
    int /* handle */) {
  // Do nothing
}

void BluetoothGattInterface::ServerObserver::IndicationSentCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* status */) {
  // Do nothing.
}

void BluetoothGattInterface::ServerObserver::MtuChangedCallback(
    BluetoothGattInterface* /* gatt_iface */,
    int /* conn_id */,
    int /* mtu */) {
  // Do nothing.
}

// static
bool BluetoothGattInterface::Initialize() {
  unique_lock<shared_timed_mutex> lock(g_instance_lock);
  CHECK(!g_interface);

  std::unique_ptr<BluetoothGattInterfaceImpl> impl(
      new BluetoothGattInterfaceImpl());
  if (!impl->Initialize()) {
    LOG(ERROR) << "Failed to initialize BluetoothGattInterface";
    return false;
  }

  g_interface = impl.release();

  return true;
}

// static
void BluetoothGattInterface::CleanUp() {
  unique_lock<shared_timed_mutex> lock(g_instance_lock);
  CHECK(g_interface);

  delete g_interface;
  g_interface = nullptr;
}

// static
bool BluetoothGattInterface::IsInitialized() {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);

  return g_interface != nullptr;
}

// static
BluetoothGattInterface* BluetoothGattInterface::Get() {
  shared_lock<shared_timed_mutex> lock(g_instance_lock);
  CHECK(g_interface);
  return g_interface;
}

// static
void BluetoothGattInterface::InitializeForTesting(
    BluetoothGattInterface* test_instance) {
  unique_lock<shared_timed_mutex> lock(g_instance_lock);
  CHECK(test_instance);
  CHECK(!g_interface);

  g_interface = test_instance;
}

bt_status_t BluetoothGattInterface::StartScan(int client_id) {
  lock_guard<mutex> lock(scan_clients_lock_);

  // Scan already initiated for this client.
  if (scan_client_set_.find(client_id) != scan_client_set_.end()) {
    // Assume starting scan multiple times is not error, but warn user.
    LOG(WARNING) << "Scan already initiated for client";
    return BT_STATUS_SUCCESS;
  }

  // If this is the first scan client, then make a call into the stack. We
  // only do this when the reference count changes to or from 0.
  if (scan_client_set_.empty()) {
    bt_status_t status = GetClientHALInterface()->scan(true);
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "HAL call to scan failed";
      return status;
    }
  }

  scan_client_set_.insert(client_id);

  return BT_STATUS_SUCCESS;
}

bt_status_t BluetoothGattInterface::StopScan(int client_id) {
  lock_guard<mutex> lock(scan_clients_lock_);

  // Scan not initiated for this client.
  auto iter = scan_client_set_.find(client_id);
  if (iter == scan_client_set_.end()) {
    // Assume stopping scan multiple times is not error, but warn user.
    LOG(WARNING) << "Scan already stopped or not initiated for client";
    return BT_STATUS_SUCCESS;
  }

  if (scan_client_set_.size() == 1) {
    bt_status_t status = GetClientHALInterface()->scan(false);
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "HAL call to stop scan failed";
      return status;
    }
  }

  scan_client_set_.erase(iter);
  return BT_STATUS_SUCCESS;
}

}  // namespace hal
}  // namespace bluetooth
