/*
 * Copyright 2020 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 "hci/facade/le_initiator_address_facade.h"

#include <condition_variable>
#include <memory>
#include <mutex>

#include "common/bind.h"
#include "grpc/grpc_event_queue.h"
#include "hci/acl_manager.h"
#include "hci/facade/le_initiator_address_facade.grpc.pb.h"
#include "hci/facade/le_initiator_address_facade.pb.h"
#include "hci/hci_packets.h"
#include "packet/raw_builder.h"

using ::grpc::ServerAsyncResponseWriter;
using ::grpc::ServerAsyncWriter;
using ::grpc::ServerContext;

using ::bluetooth::packet::RawBuilder;

namespace bluetooth {
namespace hci {
namespace facade {

class LeInitiatorAddressFacadeService : public LeInitiatorAddressFacade::Service {
 public:
  LeInitiatorAddressFacadeService(AclManager* acl_manager, ::bluetooth::os::Handler* facade_handler)
      : acl_manager_(acl_manager),
        address_manager_(acl_manager_->GetLeAddressManager()),
        facade_handler_(facade_handler) {
    ASSERT(facade_handler_ != nullptr);
  }

  ::grpc::Status SetPrivacyPolicyForInitiatorAddress(
      ::grpc::ServerContext* context, const PrivacyPolicy* request, ::google::protobuf::Empty* writer) override {
    Address address = Address::kEmpty;
    LeAddressManager::AddressPolicy address_policy =
        static_cast<LeAddressManager::AddressPolicy>(request->address_policy());
    if (address_policy == LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS) {
      ASSERT(Address::FromString(request->address_with_type().address().address(), address));
    }
    AddressWithType address_with_type(address, static_cast<AddressType>(request->address_with_type().type()));
    crypto_toolbox::Octet16 irk = {};
    auto request_irk_length = request->rotation_irk().end() - request->rotation_irk().begin();
    if (request_irk_length == crypto_toolbox::OCTET16_LEN) {
      std::vector<uint8_t> irk_data(request->rotation_irk().begin(), request->rotation_irk().end());
      std::copy_n(irk_data.begin(), crypto_toolbox::OCTET16_LEN, irk.begin());
    } else {
      ASSERT(request_irk_length == 0);
    }
    auto minimum_rotation_time = std::chrono::milliseconds(request->minimum_rotation_time());
    auto maximum_rotation_time = std::chrono::milliseconds(request->maximum_rotation_time());
    acl_manager_->SetPrivacyPolicyForInitiatorAddress(
        address_policy, address_with_type, minimum_rotation_time, maximum_rotation_time);
    return ::grpc::Status::OK;
  }

  ::grpc::Status GetCurrentInitiatorAddress(
      ::grpc::ServerContext* context,
      const ::google::protobuf::Empty* request,
      ::bluetooth::facade::BluetoothAddressWithType* response) override {
    AddressWithType current = address_manager_->GetCurrentAddress();
    auto bluetooth_address = new ::bluetooth::facade::BluetoothAddress();
    bluetooth_address->set_address(current.GetAddress().ToString());
    response->set_type(static_cast<::bluetooth::facade::BluetoothAddressTypeEnum>(current.GetAddressType()));
    response->set_allocated_address(bluetooth_address);
    return ::grpc::Status::OK;
  }

  ::grpc::Status GetAnotherAddress(
      ::grpc::ServerContext* context,
      const ::google::protobuf::Empty* request,
      ::bluetooth::facade::BluetoothAddressWithType* response) override {
    AddressWithType another = address_manager_->GetAnotherAddress();
    auto bluetooth_address = new ::bluetooth::facade::BluetoothAddress();
    bluetooth_address->set_address(another.GetAddress().ToString());
    response->set_type(static_cast<::bluetooth::facade::BluetoothAddressTypeEnum>(another.GetAddressType()));
    response->set_allocated_address(bluetooth_address);
    return ::grpc::Status::OK;
  }

 private:
  AclManager* acl_manager_;
  LeAddressManager* address_manager_;
  ::bluetooth::os::Handler* facade_handler_;
};

void LeInitiatorAddressFacadeModule::ListDependencies(ModuleList* list) const {
  ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
  list->add<AclManager>();
}

void LeInitiatorAddressFacadeModule::Start() {
  ::bluetooth::grpc::GrpcFacadeModule::Start();
  service_ = new LeInitiatorAddressFacadeService(GetDependency<AclManager>(), GetHandler());
}

void LeInitiatorAddressFacadeModule::Stop() {
  delete service_;
  ::bluetooth::grpc::GrpcFacadeModule::Stop();
}

::grpc::Service* LeInitiatorAddressFacadeModule::GetService() const {
  return service_;
}

const ModuleFactory LeInitiatorAddressFacadeModule::Factory =
    ::bluetooth::ModuleFactory([]() { return new LeInitiatorAddressFacadeModule(); });

}  // namespace facade
}  // namespace hci
}  // namespace bluetooth
