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

#include <atomic>
#include <mutex>
#include <string>
#include <unordered_set>

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

#include "service/common/bluetooth/util/atomic_string.h"
#include "service/gatt_client.h"
#include "service/gatt_server.h"
#include "service/hal/bluetooth_interface.h"
#include "service/logging_helpers.h"
#include "service/low_energy_advertiser.h"
#include "service/low_energy_client.h"
#include "service/low_energy_scanner.h"

using std::lock_guard;
using std::mutex;

namespace bluetooth {

// static
const char Adapter::kDefaultAddress[] = "00:00:00:00:00:00";
// static
const char Adapter::kDefaultName[] = "not-initialized";

// TODO(armansito): The following constants come straight from
// packages/apps/Bluetooth/src/c/a/b/btservice/AdapterService.java. It would be
// nice to know if there were a way to obtain these values from the stack
// instead of hardcoding them here.

// The minimum number of advertising instances required for multi-advertisement
// support.
const int kMinAdvInstancesForMultiAdv = 5;

// Used when determining if offloaded scan filtering is supported.
const int kMinOffloadedFilters = 10;

// Used when determining if offloaded scan batching is supported.
const int kMinOffloadedScanStorageBytes = 1024;

void Adapter::Observer::OnAdapterStateChanged(Adapter* adapter,
                                              AdapterState prev_state,
                                              AdapterState new_state) {
  // Default implementation does nothing
}

void Adapter::Observer::OnDeviceConnectionStateChanged(
    Adapter* adapter, const std::string& device_address, bool connected) {
  // Default implementation does nothing
}

// The real Adapter implementation used in production.
class AdapterImpl : public Adapter, public hal::BluetoothInterface::Observer {
 public:
  AdapterImpl()
      : state_(ADAPTER_STATE_OFF),
        address_(kDefaultAddress),
        name_(kDefaultName) {
    memset(&local_le_features_, 0, sizeof(local_le_features_));
    hal::BluetoothInterface::Get()->AddObserver(this);
    ble_client_factory_.reset(new LowEnergyClientFactory(*this));
    ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
    ble_scanner_factory_.reset(new LowEnergyScannerFactory(*this));
    gatt_client_factory_.reset(new GattClientFactory());
    gatt_server_factory_.reset(new GattServerFactory());
    hal::BluetoothInterface::Get()->GetHALInterface()->get_adapter_properties();
  }

  ~AdapterImpl() override {
    hal::BluetoothInterface::Get()->RemoveObserver(this);
  }

  void AddObserver(Adapter::Observer* observer) override {
    lock_guard<mutex> lock(observers_lock_);
    observers_.AddObserver(observer);
  }

  void RemoveObserver(Adapter::Observer* observer) override {
    lock_guard<mutex> lock(observers_lock_);
    observers_.RemoveObserver(observer);
  }

  AdapterState GetState() const override { return state_.load(); }

  bool IsEnabled() const override { return state_.load() == ADAPTER_STATE_ON; }

  bool Enable(bool start_restricted) override {
    AdapterState current_state = GetState();
    if (current_state != ADAPTER_STATE_OFF) {
      LOG(INFO) << "Adapter not disabled - state: "
                << AdapterStateToString(current_state);
      return false;
    }

    // Set the state before calling enable() as there might be a race between
    // here and the AdapterStateChangedCallback.
    state_ = ADAPTER_STATE_TURNING_ON;
    NotifyAdapterStateChanged(current_state, state_);

    int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable(
        start_restricted);
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "Failed to enable Bluetooth - status: "
                 << BtStatusText((const bt_status_t)status);
      state_ = ADAPTER_STATE_OFF;
      NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_ON, state_);
      return false;
    }

    return true;
  }

  bool Disable() override {
    if (!IsEnabled()) {
      LOG(INFO) << "Adapter is not enabled";
      return false;
    }

    AdapterState current_state = GetState();

    // Set the state before calling enable() as there might be a race between
    // here and the AdapterStateChangedCallback.
    state_ = ADAPTER_STATE_TURNING_OFF;
    NotifyAdapterStateChanged(current_state, state_);

    int status = hal::BluetoothInterface::Get()->GetHALInterface()->disable();
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "Failed to disable Bluetooth - status: "
                 << BtStatusText((const bt_status_t)status);
      state_ = current_state;
      NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_OFF, state_);
      return false;
    }

    return true;
  }

  std::string GetName() const override { return name_.Get(); }

  bool SetName(const std::string& name) override {
    bt_bdname_t hal_name;
    size_t max_name_len = sizeof(hal_name.name);

    // Include the \0 byte in size measurement.
    if (name.length() >= max_name_len) {
      LOG(ERROR) << "Given name \"" << name << "\" is larger than maximum"
                 << " allowed size: " << max_name_len;
      return false;
    }

    strncpy(reinterpret_cast<char*>(hal_name.name), name.c_str(),
            name.length() + 1);

    VLOG(1) << "Setting adapter name: " << name;

    if (!SetAdapterProperty(BT_PROPERTY_BDNAME, &hal_name, sizeof(hal_name))) {
      LOG(ERROR) << "Failed to set adapter name: " << name;
      return false;
    }

    return true;
  }

  std::string GetAddress() const override { return address_.Get(); }

  bool IsMultiAdvertisementSupported() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
  }

  bool IsDeviceConnected(const std::string& device_address) override {
    lock_guard<mutex> lock(connected_devices_lock_);
    return connected_devices_.find(device_address) != connected_devices_.end();
  }

  int GetTotalNumberOfTrackableAdvertisements() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.total_trackable_advertisers;
  }

  bool IsOffloadedFilteringSupported() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.max_adv_filter_supported >= kMinOffloadedFilters;
  }

  bool IsOffloadedScanBatchingSupported() override {
    lock_guard<mutex> lock(local_le_features_lock_);
    return local_le_features_.scan_result_storage_size >=
           kMinOffloadedScanStorageBytes;
  }

  LowEnergyClientFactory* GetLowEnergyClientFactory() const override {
    return ble_client_factory_.get();
  }

  LowEnergyAdvertiserFactory* GetLeAdvertiserFactory() const override {
    return ble_advertiser_factory_.get();
  }

  LowEnergyScannerFactory* GetLeScannerFactory() const override {
    return ble_scanner_factory_.get();
  }

  GattClientFactory* GetGattClientFactory() const override {
    return gatt_client_factory_.get();
  }

  GattServerFactory* GetGattServerFactory() const override {
    return gatt_server_factory_.get();
  }

  // hal::BluetoothInterface::Observer overrides.
  void AdapterStateChangedCallback(bt_state_t state) override {
    LOG(INFO) << "Adapter state changed: " << BtStateText(state);

    AdapterState prev_state = GetState();

    switch (state) {
      case BT_STATE_OFF:
        state_ = ADAPTER_STATE_OFF;
        break;

      case BT_STATE_ON:
        state_ = ADAPTER_STATE_ON;
        break;

      default:
        NOTREACHED();
    }

    NotifyAdapterStateChanged(prev_state, GetState());
  }

  void AdapterPropertiesCallback(bt_status_t status, int num_properties,
                                 bt_property_t* properties) override {
    LOG(INFO) << "Adapter properties changed";

    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "status: " << BtStatusText(status);
      return;
    }

    for (int i = 0; i < num_properties; i++) {
      bt_property_t* property = properties + i;
      switch (property->type) {
        case BT_PROPERTY_BDADDR: {
          std::string address =
              BtAddrString(reinterpret_cast<RawAddress*>(property->val));
          LOG(INFO) << "Adapter address changed: " << address;
          address_.Set(address);
          break;
        }
        case BT_PROPERTY_BDNAME: {
          bt_bdname_t* hal_name = reinterpret_cast<bt_bdname_t*>(property->val);
          std::string name = reinterpret_cast<char*>(hal_name->name);
          LOG(INFO) << "Adapter name changed: " << name;
          name_.Set(name);
          break;
        }
        case BT_PROPERTY_LOCAL_LE_FEATURES: {
          lock_guard<mutex> lock(local_le_features_lock_);
          if (property->len != sizeof(bt_local_le_features_t)) {
            LOG(WARNING) << "Malformed value received for property: "
                         << "BT_PROPERTY_LOCAL_LE_FEATURES";
            break;
          }
          bt_local_le_features_t* features =
              reinterpret_cast<bt_local_le_features_t*>(property->val);
          memcpy(&local_le_features_, features, sizeof(*features));
          LOG(INFO) << "Supported LE features updated";
          break;
        }
        default:
          VLOG(1) << "Unhandled adapter property: "
                  << BtPropertyText(property->type);
          break;
      }

      // TODO(armansito): notify others of the updated properties
    }
  }

  void SSPRequestCallback(RawAddress*, bt_bdname_t*, uint32_t, bt_ssp_variant_t,
                          uint32_t pass_key) override {
    LOG(INFO) << "Passkey is: " << pass_key;
  }

  void AclStateChangedCallback(bt_status_t status,
                               const RawAddress& remote_bdaddr,
                               bt_acl_state_t state) override {
    std::string device_address = BtAddrString(&remote_bdaddr);
    bool connected = (state == BT_ACL_STATE_CONNECTED);
    LOG(INFO) << "ACL state changed: " << device_address
              << " - connected: " << (connected ? "true" : "false");

    // If this is reported with an error status, I suppose the best thing we can
    // do is to log it and ignore the event.
    if (status != BT_STATUS_SUCCESS) {
      LOG(ERROR) << "status: " << BtStatusText(status);
      return;
    }

    // Introduce a scope to manage |connected_devices_lock_| with RAII.
    {
      lock_guard<mutex> lock(connected_devices_lock_);
      if (connected)
        connected_devices_.insert(device_address);
      else
        connected_devices_.erase(device_address);
    }

    lock_guard<mutex> lock(observers_lock_);
    FOR_EACH_OBSERVER(
        Adapter::Observer, observers_,
        OnDeviceConnectionStateChanged(this, device_address, connected));
  }

  // Sends a request to set the given HAL adapter property type and value.
  bool SetAdapterProperty(bt_property_type_t type, void* value, int length) {
    CHECK(length > 0);
    CHECK(value);

    bt_property_t property;
    property.len = length;
    property.val = value;
    property.type = type;

    int status =
        hal::BluetoothInterface::Get()->GetHALInterface()->set_adapter_property(
            &property);
    if (status != BT_STATUS_SUCCESS) {
      VLOG(1) << "Failed to set property";
      return false;
    }

    return true;
  }

  // Helper for invoking the AdapterStateChanged observer method.
  void NotifyAdapterStateChanged(AdapterState prev_state,
                                 AdapterState new_state) {
    if (prev_state == new_state) return;

    lock_guard<mutex> lock(observers_lock_);
    FOR_EACH_OBSERVER(Adapter::Observer, observers_,
                      OnAdapterStateChanged(this, prev_state, new_state));
  }

 private:
  // The current adapter state.
  std::atomic<AdapterState> state_;

  // The Bluetooth device address of the local adapter in string from
  // (i.e.. XX:XX:XX:XX:XX:XX)
  util::AtomicString address_;

  // The current local adapter name.
  util::AtomicString name_;

  // The current set of supported LE features as obtained from the stack. The
  // values here are all initially set to 0 and updated when the corresponding
  // adapter property has been received from the stack.
  std::mutex local_le_features_lock_;
  bt_local_le_features_t local_le_features_;

  // List of observers that are interested in notifications from us.
  std::mutex observers_lock_;
  base::ObserverList<Adapter::Observer> observers_;

  // List of devices addresses that are currently connected.
  std::mutex connected_devices_lock_;
  std::unordered_set<std::string> connected_devices_;

  // Factory used to create per-app LowEnergyClient instances.
  std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;

  // Factory used to create per-app LeAdvertiser instances.
  std::unique_ptr<LowEnergyAdvertiserFactory> ble_advertiser_factory_;

  // Factory used to create per-app LeScanner instances.
  std::unique_ptr<LowEnergyScannerFactory> ble_scanner_factory_;

  // Factory used to create per-app GattClient instances.
  std::unique_ptr<GattClientFactory> gatt_client_factory_;

  // Factory used to create per-app GattServer instances.
  std::unique_ptr<GattServerFactory> gatt_server_factory_;

  DISALLOW_COPY_AND_ASSIGN(AdapterImpl);
};

// static
std::unique_ptr<Adapter> Adapter::Create() {
  return std::unique_ptr<Adapter>(new AdapterImpl());
}

}  // namespace bluetooth
