// Copyright 2015 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 "modules/bluetooth/BluetoothRemoteGATTCharacteristic.h"

#include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/DOMException.h"
#include "core/events/Event.h"
#include "core/inspector/ConsoleMessage.h"
#include "modules/bluetooth/Bluetooth.h"
#include "modules/bluetooth/BluetoothCharacteristicProperties.h"
#include "modules/bluetooth/BluetoothDevice.h"
#include "modules/bluetooth/BluetoothError.h"
#include "modules/bluetooth/BluetoothRemoteGATTDescriptor.h"
#include "modules/bluetooth/BluetoothRemoteGATTService.h"
#include "modules/bluetooth/BluetoothRemoteGATTUtils.h"
#include "modules/bluetooth/BluetoothUUID.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"

#include <memory>
#include <utility>

namespace blink {

BluetoothRemoteGATTCharacteristic::BluetoothRemoteGATTCharacteristic(
    ExecutionContext* context,
    mojom::blink::WebBluetoothRemoteGATTCharacteristicPtr characteristic,
    BluetoothRemoteGATTService* service,
    BluetoothDevice* device)
    : ContextLifecycleObserver(context),
      characteristic_(std::move(characteristic)),
      service_(service),
      device_(device) {
  properties_ =
      BluetoothCharacteristicProperties::Create(characteristic_->properties);
}

BluetoothRemoteGATTCharacteristic* BluetoothRemoteGATTCharacteristic::Create(
    ExecutionContext* context,
    mojom::blink::WebBluetoothRemoteGATTCharacteristicPtr characteristic,
    BluetoothRemoteGATTService* service,
    BluetoothDevice* device) {
  return new BluetoothRemoteGATTCharacteristic(
      context, std::move(characteristic), service, device);
}

void BluetoothRemoteGATTCharacteristic::SetValue(DOMDataView* dom_data_view) {
  value_ = dom_data_view;
}

void BluetoothRemoteGATTCharacteristic::RemoteCharacteristicValueChanged(
    const Vector<uint8_t>& value) {
  if (!GetGatt()->connected())
    return;
  this->SetValue(BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(value));
  DispatchEvent(Event::Create(EventTypeNames::characteristicvaluechanged));
}

void BluetoothRemoteGATTCharacteristic::ContextDestroyed(ExecutionContext*) {
  Dispose();
}

void BluetoothRemoteGATTCharacteristic::Dispose() {
  client_bindings_.CloseAllBindings();
}

const WTF::AtomicString& BluetoothRemoteGATTCharacteristic::InterfaceName()
    const {
  return EventTargetNames::BluetoothRemoteGATTCharacteristic;
}

ExecutionContext* BluetoothRemoteGATTCharacteristic::GetExecutionContext()
    const {
  return ContextLifecycleObserver::GetExecutionContext();
}

void BluetoothRemoteGATTCharacteristic::AddedEventListener(
    const AtomicString& event_type,
    RegisteredEventListener& registered_listener) {
  EventTargetWithInlineData::AddedEventListener(event_type,
                                                registered_listener);
}

void BluetoothRemoteGATTCharacteristic::ReadValueCallback(
    ScriptPromiseResolver* resolver,
    mojom::blink::WebBluetoothResult result,
    const Optional<Vector<uint8_t>>& value) {
  if (!resolver->GetExecutionContext() ||
      resolver->GetExecutionContext()->IsContextDestroyed())
    return;

  // If the device is disconnected, reject.
  if (!GetGatt()->RemoveFromActiveAlgorithms(resolver)) {
    resolver->Reject(
        BluetoothError::CreateNotConnectedException(BluetoothOperation::kGATT));
    return;
  }

  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
    DCHECK(value);
    DOMDataView* dom_data_view =
        BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(value.value());
    SetValue(dom_data_view);
    DispatchEvent(Event::Create(EventTypeNames::characteristicvaluechanged));
    resolver->Resolve(dom_data_view);
  } else {
    resolver->Reject(BluetoothError::CreateDOMException(result));
  }
}

ScriptPromise BluetoothRemoteGATTCharacteristic::readValue(
    ScriptState* script_state) {
  if (!GetGatt()->connected()) {
    return ScriptPromise::RejectWithDOMException(
        script_state,
        BluetoothError::CreateNotConnectedException(BluetoothOperation::kGATT));
  }

  if (!GetGatt()->device()->IsValidCharacteristic(
          characteristic_->instance_id)) {
    return ScriptPromise::RejectWithDOMException(
        script_state, CreateInvalidCharacteristicError());
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  ScriptPromise promise = resolver->Promise();
  GetGatt()->AddToActiveAlgorithms(resolver);

  mojom::blink::WebBluetoothService* service =
      device_->GetBluetooth()->Service();
  service->RemoteCharacteristicReadValue(
      characteristic_->instance_id,
      ConvertToBaseCallback(
          WTF::Bind(&BluetoothRemoteGATTCharacteristic::ReadValueCallback,
                    WrapPersistent(this), WrapPersistent(resolver))));

  return promise;
}

void BluetoothRemoteGATTCharacteristic::WriteValueCallback(
    ScriptPromiseResolver* resolver,
    const Vector<uint8_t>& value,
    mojom::blink::WebBluetoothResult result) {
  if (!resolver->GetExecutionContext() ||
      resolver->GetExecutionContext()->IsContextDestroyed())
    return;

  // If the device is disconnected, reject.
  if (!GetGatt()->RemoveFromActiveAlgorithms(resolver)) {
    resolver->Reject(
        BluetoothError::CreateNotConnectedException(BluetoothOperation::kGATT));
    return;
  }

  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
    SetValue(BluetoothRemoteGATTUtils::ConvertWTFVectorToDataView(value));
    resolver->Resolve();
  } else {
    resolver->Reject(BluetoothError::CreateDOMException(result));
  }
}

ScriptPromise BluetoothRemoteGATTCharacteristic::writeValue(
    ScriptState* script_state,
    const DOMArrayPiece& value) {
  if (!GetGatt()->connected()) {
    return ScriptPromise::RejectWithDOMException(
        script_state,
        BluetoothError::CreateNotConnectedException(BluetoothOperation::kGATT));
  }

  if (!GetGatt()->device()->IsValidCharacteristic(
          characteristic_->instance_id)) {
    return ScriptPromise::RejectWithDOMException(
        script_state, CreateInvalidCharacteristicError());
  }

  // Partial implementation of writeValue algorithm:
  // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue

  // If bytes is more than 512 bytes long (the maximum length of an attribute
  // value, per Long Attribute Values) return a promise rejected with an
  // InvalidModificationError and abort.
  if (value.ByteLength() > 512)
    return ScriptPromise::RejectWithDOMException(
        script_state, DOMException::Create(kInvalidModificationError,
                                           "Value can't exceed 512 bytes."));

  // Let valueVector be a copy of the bytes held by value.
  Vector<uint8_t> value_vector;
  value_vector.Append(value.Bytes(), value.ByteLength());

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  ScriptPromise promise = resolver->Promise();
  GetGatt()->AddToActiveAlgorithms(resolver);

  mojom::blink::WebBluetoothService* service =
      device_->GetBluetooth()->Service();
  service->RemoteCharacteristicWriteValue(
      characteristic_->instance_id, value_vector,
      ConvertToBaseCallback(WTF::Bind(
          &BluetoothRemoteGATTCharacteristic::WriteValueCallback,
          WrapPersistent(this), WrapPersistent(resolver), value_vector)));

  return promise;
}

void BluetoothRemoteGATTCharacteristic::NotificationsCallback(
    ScriptPromiseResolver* resolver,
    mojom::blink::WebBluetoothResult result) {
  if (!resolver->GetExecutionContext() ||
      resolver->GetExecutionContext()->IsContextDestroyed())
    return;

  // If the device is disconnected, reject.
  if (!GetGatt()->RemoveFromActiveAlgorithms(resolver)) {
    resolver->Reject(
        BluetoothError::CreateNotConnectedException(BluetoothOperation::kGATT));
    return;
  }

  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
    resolver->Resolve(this);
  } else {
    resolver->Reject(BluetoothError::CreateDOMException(result));
  }
}

ScriptPromise BluetoothRemoteGATTCharacteristic::startNotifications(
    ScriptState* script_state) {
  if (!GetGatt()->connected()) {
    return ScriptPromise::RejectWithDOMException(
        script_state,
        BluetoothError::CreateNotConnectedException(BluetoothOperation::kGATT));
  }

  if (!GetGatt()->device()->IsValidCharacteristic(
          characteristic_->instance_id)) {
    return ScriptPromise::RejectWithDOMException(
        script_state, CreateInvalidCharacteristicError());
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  ScriptPromise promise = resolver->Promise();
  GetGatt()->AddToActiveAlgorithms(resolver);

  mojom::blink::WebBluetoothService* service =
      device_->GetBluetooth()->Service();
  mojom::blink::WebBluetoothCharacteristicClientAssociatedPtrInfo ptr_info;
  auto request = mojo::MakeRequest(&ptr_info);
  client_bindings_.AddBinding(this, std::move(request));

  service->RemoteCharacteristicStartNotifications(
      characteristic_->instance_id, std::move(ptr_info),
      ConvertToBaseCallback(
          WTF::Bind(&BluetoothRemoteGATTCharacteristic::NotificationsCallback,
                    WrapPersistent(this), WrapPersistent(resolver))));

  return promise;
}

ScriptPromise BluetoothRemoteGATTCharacteristic::stopNotifications(
    ScriptState* script_state) {
  if (!GetGatt()->connected()) {
    return ScriptPromise::RejectWithDOMException(
        script_state,
        BluetoothError::CreateNotConnectedException(BluetoothOperation::kGATT));
  }

  if (!GetGatt()->device()->IsValidCharacteristic(
          characteristic_->instance_id)) {
    return ScriptPromise::RejectWithDOMException(
        script_state, CreateInvalidCharacteristicError());
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  ScriptPromise promise = resolver->Promise();
  GetGatt()->AddToActiveAlgorithms(resolver);

  mojom::blink::WebBluetoothService* service =
      device_->GetBluetooth()->Service();
  service->RemoteCharacteristicStopNotifications(
      characteristic_->instance_id,
      ConvertToBaseCallback(
          WTF::Bind(&BluetoothRemoteGATTCharacteristic::NotificationsCallback,
                    WrapPersistent(this), WrapPersistent(resolver),
                    mojom::blink::WebBluetoothResult::SUCCESS)));
  return promise;
}

ScriptPromise BluetoothRemoteGATTCharacteristic::getDescriptor(
    ScriptState* script_state,
    const StringOrUnsignedLong& descriptor_uuid,
    ExceptionState& exception_state) {
  String descriptor =
      BluetoothUUID::getDescriptor(descriptor_uuid, exception_state);
  if (exception_state.HadException())
    return exception_state.Reject(script_state);

  return GetDescriptorsImpl(script_state,
                            mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE,
                            descriptor);
}

ScriptPromise BluetoothRemoteGATTCharacteristic::getDescriptors(
    ScriptState* script_state,
    ExceptionState&) {
  return GetDescriptorsImpl(
      script_state, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE);
}

ScriptPromise BluetoothRemoteGATTCharacteristic::getDescriptors(
    ScriptState* script_state,
    const StringOrUnsignedLong& descriptor_uuid,
    ExceptionState& exception_state) {
  String descriptor =
      BluetoothUUID::getDescriptor(descriptor_uuid, exception_state);
  if (exception_state.HadException())
    return exception_state.Reject(script_state);

  return GetDescriptorsImpl(
      script_state, mojom::blink::WebBluetoothGATTQueryQuantity::MULTIPLE,
      descriptor);
}

ScriptPromise BluetoothRemoteGATTCharacteristic::GetDescriptorsImpl(
    ScriptState* script_state,
    mojom::blink::WebBluetoothGATTQueryQuantity quantity,
    const String& descriptors_uuid) {
  if (!GetGatt()->connected()) {
    return ScriptPromise::RejectWithDOMException(
        script_state, BluetoothError::CreateNotConnectedException(
                          BluetoothOperation::kDescriptorsRetrieval));
  }

  if (!GetGatt()->device()->IsValidCharacteristic(
          characteristic_->instance_id)) {
    return ScriptPromise::RejectWithDOMException(
        script_state, CreateInvalidCharacteristicError());
  }

  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
  ScriptPromise promise = resolver->Promise();
  GetGatt()->AddToActiveAlgorithms(resolver);

  mojom::blink::WebBluetoothService* service =
      device_->GetBluetooth()->Service();
  service->RemoteCharacteristicGetDescriptors(
      characteristic_->instance_id, quantity, descriptors_uuid,
      ConvertToBaseCallback(WTF::Bind(
          &BluetoothRemoteGATTCharacteristic::GetDescriptorsCallback,
          WrapPersistent(this), descriptors_uuid, characteristic_->instance_id,
          quantity, WrapPersistent(resolver))));

  return promise;
}

// Callback that allows us to resolve the promise with a single descriptor
// or with a vector owning the descriptors.
void BluetoothRemoteGATTCharacteristic::GetDescriptorsCallback(
    const String& requested_descriptor_uuid,
    const String& characteristic_instance_id,
    mojom::blink::WebBluetoothGATTQueryQuantity quantity,
    ScriptPromiseResolver* resolver,
    mojom::blink::WebBluetoothResult result,
    Optional<Vector<mojom::blink::WebBluetoothRemoteGATTDescriptorPtr>>
        descriptors) {
  if (!resolver->GetExecutionContext() ||
      resolver->GetExecutionContext()->IsContextDestroyed())
    return;

  // If the device is disconnected, reject.
  if (!service_->device()->gatt()->RemoveFromActiveAlgorithms(resolver)) {
    resolver->Reject(BluetoothError::CreateNotConnectedException(
        BluetoothOperation::kDescriptorsRetrieval));
    return;
  }

  if (result == mojom::blink::WebBluetoothResult::SUCCESS) {
    DCHECK(descriptors);

    if (quantity == mojom::blink::WebBluetoothGATTQueryQuantity::SINGLE) {
      DCHECK_EQ(1u, descriptors->size());
      resolver->Resolve(
          service_->device()->GetOrCreateBluetoothRemoteGATTDescriptor(
              std::move(descriptors.value()[0]), this));
      return;
    }

    HeapVector<Member<BluetoothRemoteGATTDescriptor>> gatt_descriptors;
    gatt_descriptors.ReserveInitialCapacity(descriptors->size());
    for (auto& descriptor : descriptors.value()) {
      gatt_descriptors.push_back(
          service_->device()->GetOrCreateBluetoothRemoteGATTDescriptor(
              std::move(descriptor), this));
    }
    resolver->Resolve(gatt_descriptors);
  } else {
    if (result == mojom::blink::WebBluetoothResult::DESCRIPTOR_NOT_FOUND) {
      resolver->Reject(BluetoothError::CreateDOMException(
          BluetoothErrorCode::kDescriptorNotFound,
          "No Descriptors matching UUID " + requested_descriptor_uuid +
              " found in Characteristic with UUID " + uuid() + "."));
    } else {
      resolver->Reject(BluetoothError::CreateDOMException(result));
    }
  }
}

DOMException*
BluetoothRemoteGATTCharacteristic::CreateInvalidCharacteristicError() {
  return BluetoothError::CreateDOMException(
      BluetoothErrorCode::kInvalidCharacteristic,
      "Characteristic with UUID " + uuid() +
          " is no longer valid. Remember to retrieve the characteristic again "
          "after reconnecting.");
}

DEFINE_TRACE(BluetoothRemoteGATTCharacteristic) {
  visitor->Trace(service_);
  visitor->Trace(properties_);
  visitor->Trace(value_);
  visitor->Trace(device_);
  EventTargetWithInlineData::Trace(visitor);
  ContextLifecycleObserver::Trace(visitor);
}

}  // namespace blink
