// Copyright 2016 The Chromium 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 "device/bluetooth/bluetooth_remote_gatt_characteristic.h"

#include <utility>

#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "device/bluetooth/bluetooth_gatt_notify_session.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"

namespace device {

BluetoothRemoteGattCharacteristic::BluetoothRemoteGattCharacteristic()
    : weak_ptr_factory_(this) {}

BluetoothRemoteGattCharacteristic::~BluetoothRemoteGattCharacteristic() {
  while (!pending_notify_commands_.empty()) {
    pending_notify_commands_.front()->Cancel();
  }
}

std::vector<BluetoothRemoteGattDescriptor*>
BluetoothRemoteGattCharacteristic::GetDescriptors() const {
  std::vector<BluetoothRemoteGattDescriptor*> descriptors;
  descriptors.reserve(descriptors_.size());
  for (const auto& pair : descriptors_)
    descriptors.push_back(pair.second.get());
  return descriptors;
}

BluetoothRemoteGattDescriptor* BluetoothRemoteGattCharacteristic::GetDescriptor(
    const std::string& identifier) const {
  auto iter = descriptors_.find(identifier);
  return iter != descriptors_.end() ? iter->second.get() : nullptr;
}

std::vector<BluetoothRemoteGattDescriptor*>
BluetoothRemoteGattCharacteristic::GetDescriptorsByUUID(
    const BluetoothUUID& uuid) const {
  std::vector<BluetoothRemoteGattDescriptor*> descriptors;
  for (const auto& pair : descriptors_) {
    if (pair.second->GetUUID() == uuid)
      descriptors.push_back(pair.second.get());
  }

  return descriptors;
}

base::WeakPtr<device::BluetoothRemoteGattCharacteristic>
BluetoothRemoteGattCharacteristic::GetWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

bool BluetoothRemoteGattCharacteristic::IsNotifying() const {
  return !notify_sessions_.empty();
}

BluetoothRemoteGattCharacteristic::NotifySessionCommand::NotifySessionCommand(
    ExecuteCallback execute_callback,
    base::OnceClosure cancel_callback)
    : execute_callback_(std::move(execute_callback)),
      cancel_callback_(std::move(cancel_callback)) {}

BluetoothRemoteGattCharacteristic::NotifySessionCommand::
    ~NotifySessionCommand() = default;

void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute() {
  std::move(execute_callback_)
      .Run(COMMAND_NONE, RESULT_SUCCESS,
           BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
}

void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute(
    Type previous_command_type,
    Result previous_command_result,
    BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
  std::move(execute_callback_)
      .Run(previous_command_type, previous_command_result,
           previous_command_error_code);
}

void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Cancel() {
  std::move(cancel_callback_).Run();
}

void BluetoothRemoteGattCharacteristic::StartNotifySession(
    NotifySessionCallback callback,
    ErrorCallback error_callback) {
  StartNotifySessionInternal(base::nullopt, std::move(callback),
                             std::move(error_callback));
}

#if defined(OS_CHROMEOS)
void BluetoothRemoteGattCharacteristic::StartNotifySession(
    NotificationType notification_type,
    NotifySessionCallback callback,
    ErrorCallback error_callback) {
  StartNotifySessionInternal(notification_type, std::move(callback),
                             std::move(error_callback));
}
#endif

bool BluetoothRemoteGattCharacteristic::WriteWithoutResponse(
    base::span<const uint8_t> value) {
  NOTIMPLEMENTED();
  return false;
}

bool BluetoothRemoteGattCharacteristic::AddDescriptor(
    std::unique_ptr<BluetoothRemoteGattDescriptor> descriptor) {
  if (!descriptor)
    return false;

  auto* descriptor_raw = descriptor.get();
  return descriptors_
      .try_emplace(descriptor_raw->GetIdentifier(), std::move(descriptor))
      .second;
}

void BluetoothRemoteGattCharacteristic::StartNotifySessionInternal(
    const base::Optional<NotificationType>& notification_type,
    NotifySessionCallback callback,
    ErrorCallback error_callback) {
  auto repeating_error_callback =
      base::AdaptCallbackForRepeating(std::move(error_callback));
  NotifySessionCommand* command = new NotifySessionCommand(
      base::BindOnce(
          &BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
          GetWeakPtr(), notification_type, std::move(callback),
          repeating_error_callback),
      base::BindOnce(
          &BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
          GetWeakPtr(),
          base::BindOnce(repeating_error_callback,
                         BluetoothRemoteGattService::GATT_ERROR_FAILED)));

  pending_notify_commands_.push(base::WrapUnique(command));
  if (pending_notify_commands_.size() == 1) {
    command->Execute();
  }
}

void BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession(
    const base::Optional<NotificationType>& notification_type,
    NotifySessionCallback callback,
    ErrorCallback error_callback,
    NotifySessionCommand::Type previous_command_type,
    NotifySessionCommand::Result previous_command_result,
    BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
  // If the command that was resolved immediately before this command was run,
  // this command should be resolved with the same result.
  if (previous_command_type == NotifySessionCommand::COMMAND_START) {
    if (previous_command_result == NotifySessionCommand::RESULT_SUCCESS) {
      base::ThreadTaskRunnerHandle::Get()->PostTask(
          FROM_HERE,
          base::BindOnce(
              &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
              GetWeakPtr(), std::move(callback)));
      return;
    } else {
      base::ThreadTaskRunnerHandle::Get()->PostTask(
          FROM_HERE,
          base::BindOnce(
              &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
              GetWeakPtr(), std::move(error_callback),
              previous_command_error_code));
      return;
    }
  }

  if (!IsNotificationTypeSupported(notification_type)) {
    if (notification_type)
      LOG(ERROR) << "Characteristic doesn't support specified "
                 << "notification_type";
    else
      LOG(ERROR) << "Characteristic needs NOTIFY or INDICATE";
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE,
        base::BindOnce(
            &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
            GetWeakPtr(), std::move(error_callback),
            BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
    return;
  }

  // If the characteristic is already notifying, then we don't need to
  // subscribe again. All we need to do is call the success callback, which
  // will create and return a session object to the caller.
  if (IsNotifying()) {
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE,
        base::BindOnce(
            &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
            GetWeakPtr(), std::move(callback)));
    return;
  }

  // Find the Client Characteristic Configuration descriptor.
  std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
      GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
                               ClientCharacteristicConfigurationUuid());

  if (ccc_descriptor.size() != 1u) {
    LOG(ERROR) << "Found " << ccc_descriptor.size()
               << " client characteristic configuration descriptors.";
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE,
        base::BindOnce(
            &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
            GetWeakPtr(), std::move(error_callback),
            (ccc_descriptor.size() == 0)
                ? BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED
                : BluetoothRemoteGattService::GATT_ERROR_FAILED));
    return;
  }

  // Pass the Client Characteristic Configuration descriptor to
  // SubscribetoNotifications, which will write the correct value to it, and
  // do whatever else is needed to get the notifications flowing.
  SubscribeToNotifications(
      ccc_descriptor[0],
#if defined(OS_CHROMEOS)
      notification_type.value_or((GetProperties() & PROPERTY_NOTIFY)
                                     ? NotificationType::kNotification
                                     : NotificationType::kIndication),
#endif
      base::BindOnce(
          &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
          GetWeakPtr(), std::move(callback)),
      base::BindOnce(
          &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
          GetWeakPtr(), std::move(error_callback)));
}

void BluetoothRemoteGattCharacteristic::CancelStartNotifySession(
    base::OnceClosure callback) {
  std::unique_ptr<NotifySessionCommand> command =
      std::move(pending_notify_commands_.front());
  pending_notify_commands_.pop();
  std::move(callback).Run();
}

void BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess(
    NotifySessionCallback callback) {
  std::unique_ptr<NotifySessionCommand> command =
      std::move(pending_notify_commands_.front());

  std::unique_ptr<device::BluetoothGattNotifySession> notify_session(
      new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr()));
  notify_sessions_.insert(notify_session.get());
  std::move(callback).Run(std::move(notify_session));

  pending_notify_commands_.pop();
  if (!pending_notify_commands_.empty()) {
    pending_notify_commands_.front()->Execute(
        NotifySessionCommand::COMMAND_START,
        NotifySessionCommand::RESULT_SUCCESS,
        BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
  }
}

void BluetoothRemoteGattCharacteristic::OnStartNotifySessionError(
    ErrorCallback error_callback,
    BluetoothRemoteGattService::GattErrorCode error) {
  std::unique_ptr<NotifySessionCommand> command =
      std::move(pending_notify_commands_.front());

  std::move(error_callback).Run(error);

  pending_notify_commands_.pop();
  if (!pending_notify_commands_.empty()) {
    pending_notify_commands_.front()->Execute(
        NotifySessionCommand::COMMAND_START, NotifySessionCommand::RESULT_ERROR,
        error);
  }
}

void BluetoothRemoteGattCharacteristic::StopNotifySession(
    BluetoothGattNotifySession* session,
    base::OnceClosure callback) {
  auto repeating_callback =
      base::AdaptCallbackForRepeating(std::move(callback));
  NotifySessionCommand* command = new NotifySessionCommand(
      base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
                 GetWeakPtr(), session, repeating_callback),
      base::Bind(&BluetoothRemoteGattCharacteristic::CancelStopNotifySession,
                 GetWeakPtr(), repeating_callback));

  pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
  if (pending_notify_commands_.size() == 1) {
    command->Execute();
  }
}

void BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession(
    BluetoothGattNotifySession* session,
    base::OnceClosure callback,
    NotifySessionCommand::Type previous_command_type,
    NotifySessionCommand::Result previous_command_result,
    BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
  auto session_iterator = notify_sessions_.find(session);

  // If the session does not even belong to this characteristic, we return an
  // error right away.
  if (session_iterator == notify_sessions_.end()) {
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE,
        base::BindOnce(
            &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
            GetWeakPtr(), session, std::move(callback),
            BluetoothRemoteGattService::GATT_ERROR_FAILED));
    return;
  }

  // If there are more active sessions, then we return right away.
  if (notify_sessions_.size() > 1) {
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE,
        base::BindOnce(
            &BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
            GetWeakPtr(), session, std::move(callback)));
    return;
  }

  // Find the Client Characteristic Configuration descriptor.
  std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
      GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
                               ClientCharacteristicConfigurationUuid());

  if (ccc_descriptor.size() != 1u) {
    LOG(ERROR) << "Found " << ccc_descriptor.size()
               << " client characteristic configuration descriptors.";
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE,
        base::BindOnce(
            &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
            GetWeakPtr(), session, std::move(callback),
            BluetoothRemoteGattService::GATT_ERROR_FAILED));
    return;
  }

  auto repeating_callback =
      base::AdaptCallbackForRepeating(std::move(callback));
  UnsubscribeFromNotifications(
      ccc_descriptor[0],
      base::BindOnce(
          &BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
          GetWeakPtr(), session, repeating_callback),
      base::BindOnce(
          &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
          GetWeakPtr(), session, repeating_callback));
}

void BluetoothRemoteGattCharacteristic::CancelStopNotifySession(
    base::OnceClosure callback) {
  std::unique_ptr<NotifySessionCommand> command =
      std::move(pending_notify_commands_.front());
  pending_notify_commands_.pop();
  std::move(callback).Run();
}

void BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess(
    BluetoothGattNotifySession* session,
    base::OnceClosure callback) {
  std::unique_ptr<NotifySessionCommand> command =
      std::move(pending_notify_commands_.front());

  notify_sessions_.erase(session);

  std::move(callback).Run();

  pending_notify_commands_.pop();
  if (!pending_notify_commands_.empty()) {
    pending_notify_commands_.front()->Execute(
        NotifySessionCommand::COMMAND_STOP,
        NotifySessionCommand::RESULT_SUCCESS,
        BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
  }
}

void BluetoothRemoteGattCharacteristic::OnStopNotifySessionError(
    BluetoothGattNotifySession* session,
    base::OnceClosure callback,
    BluetoothRemoteGattService::GattErrorCode error) {
  std::unique_ptr<NotifySessionCommand> command =
      std::move(pending_notify_commands_.front());

  notify_sessions_.erase(session);

  std::move(callback).Run();

  pending_notify_commands_.pop();
  if (!pending_notify_commands_.empty()) {
    pending_notify_commands_.front()->Execute(
        NotifySessionCommand::COMMAND_STOP, NotifySessionCommand::RESULT_ERROR,
        error);
  }
}

bool BluetoothRemoteGattCharacteristic::IsNotificationTypeSupported(
    const base::Optional<NotificationType>& notification_type) {
  Properties properties = GetProperties();
  bool hasNotify = (properties & PROPERTY_NOTIFY) != 0;
  bool hasIndicate = (properties & PROPERTY_INDICATE) != 0;
  if (!notification_type)
    return hasNotify || hasIndicate;
  switch (notification_type.value()) {
    case NotificationType::kNotification:
      return hasNotify;
    case NotificationType::kIndication:
      return hasIndicate;
  }
}

}  // namespace device
