/*
 * Copyright 2019 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 "packet/packet_builder.h"

#include <gtest/gtest.h>
#include <forward_list>
#include <memory>

using bluetooth::packet::BasePacketBuilder;
using bluetooth::packet::BitInserter;
using bluetooth::packet::PacketBuilder;
using std::vector;

namespace {
vector<uint8_t> count_all = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
};

vector<uint8_t> count_1 = {
    0x00,
    0x01,
    0x02,
};

vector<uint8_t> count_2 = {
    0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
};

vector<uint8_t> count_3 = {
    0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
};
}  // namespace

namespace bluetooth {
namespace packet {

template <bool little_endian>
class EndianBuilder : public PacketBuilder<little_endian> {
 public:
  EndianBuilder(uint8_t byte, uint16_t two_bytes, uint32_t four_bytes, uint64_t eight_bytes)
      : byte_(byte), two_bytes_(two_bytes), four_bytes_(four_bytes), eight_bytes_(eight_bytes) {}
  ~EndianBuilder() = default;

  virtual size_t size() const override {
    return sizeof(signature_) + sizeof(byte_) + sizeof(two_bytes_) + sizeof(four_bytes_) + sizeof(eight_bytes_);
  }

  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
    std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
    packet->reserve(size());
    BitInserter it(*packet);
    Serialize(it);
    return packet;
  }

  virtual void Serialize(BitInserter& it) const override {
    PacketBuilder<little_endian>::insert(signature_, it);
    PacketBuilder<little_endian>::insert(byte_, it);
    PacketBuilder<little_endian>::insert(two_bytes_, it);
    PacketBuilder<little_endian>::insert(four_bytes_, it);
    PacketBuilder<little_endian>::insert(eight_bytes_, it);
  }

 private:
  uint32_t signature_{(little_endian ? 0x03020100 : 0x00010203)};
  uint8_t byte_;
  uint16_t two_bytes_;
  uint32_t four_bytes_;
  uint64_t eight_bytes_;
};

class PacketBuilderEndianTest : public ::testing::Test {
 public:
  PacketBuilderEndianTest() = default;
  ~PacketBuilderEndianTest() = default;
};

TEST(PacketBuilderEndianTest, insertTest) {
  EndianBuilder<true> little(0x04, 0x0605, 0x0a090807, 0x1211100f0e0d0c0b);
  EndianBuilder<false> big(0x04, 0x0506, 0x0708090a, 0x0b0c0d0e0f101112);
  ASSERT_EQ(*big.FinalPacket(), *little.FinalPacket());
}

template <typename T>
class VectorBuilder : public PacketBuilder<true> {
 public:
  VectorBuilder(const std::vector<uint64_t> vect) {
    for (uint64_t element : vect) {
      vect_.push_back(static_cast<T>(element));
    }
  }
  ~VectorBuilder() = default;

  virtual size_t size() const override {
    return vect_.size() * sizeof(T);
  }

  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
    std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
    packet->reserve(size());
    BitInserter it(*packet);
    Serialize(it);
    return packet;
  }

  virtual void Serialize(BitInserter& it) const override {
    PacketBuilder<true>::insert_vector(vect_, it);
  }

 private:
  std::vector<T> vect_;
};

template <typename T>
class InsertElementsBuilder : public PacketBuilder<true> {
 public:
  InsertElementsBuilder(const std::vector<uint64_t> vect) {
    for (uint64_t element : vect) {
      vect_.push_back(static_cast<T>(element));
    }
  }
  virtual ~InsertElementsBuilder() = default;

  virtual size_t size() const override {
    return vect_.size() * sizeof(T);
  }

  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
    std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
    packet->reserve(size());
    BitInserter it(*packet);
    Serialize(it);
    return packet;
  }

  virtual void Serialize(BitInserter& it) const override {
    for (T elem : vect_) {
      PacketBuilder<true>::insert(elem, it);
    }
  }

 private:
  std::vector<T> vect_;
};

std::vector<uint64_t> vector_data{
    0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303, 0x7464544434241404,
    0x7565554535251505, 0x7666564636261606, 0x7767574737271707, 0x7868584838281808,
};

template <typename T>
class VectorBuilderTest : public ::testing::Test {
 public:
  VectorBuilderTest() = default;
  ~VectorBuilderTest() = default;

  void SetUp() {
    packet_1_ = std::shared_ptr<VectorBuilder<T>>(new VectorBuilder<T>(vector_data));
    packet_2_ = std::shared_ptr<InsertElementsBuilder<T>>(new InsertElementsBuilder<T>(vector_data));
  }

  void TearDown() {
    packet_1_.reset();
    packet_2_.reset();
  }

  std::shared_ptr<VectorBuilder<T>> packet_1_;
  std::shared_ptr<InsertElementsBuilder<T>> packet_2_;
};

using VectorBaseTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t>;
TYPED_TEST_CASE(VectorBuilderTest, VectorBaseTypes);

TYPED_TEST(VectorBuilderTest, insertVectorTest) {
  ASSERT_EQ(*(this->packet_1_->FinalPacket()), *(this->packet_2_->FinalPacket()));
}

class NestedBuilder : public PacketBuilder<true> {
 public:
  ~NestedBuilder() = default;

  virtual size_t size() const override {
    size_t payload_size = (payload_ ? payload_->size() : 0);
    return 1 + payload_size;
  }

  static std::unique_ptr<NestedBuilder> Create(uint8_t level) {
    return std::unique_ptr<NestedBuilder>(new NestedBuilder(level));
  }

  static std::unique_ptr<NestedBuilder> CreateNested(std::unique_ptr<BasePacketBuilder> payload, uint8_t level) {
    return std::unique_ptr<NestedBuilder>(new NestedBuilder(std::move(payload), level));
  }

  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
    std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
    packet->reserve(size());
    BitInserter it(*packet);
    Serialize(it);
    return packet;
  }

  virtual void Serialize(BitInserter& it) const override {
    PacketBuilder<true>::insert(level_, it);
    if (payload_) {
      payload_->Serialize(it);
    }
  }

 private:
  std::unique_ptr<BasePacketBuilder> payload_;
  uint8_t level_;

  NestedBuilder(std::unique_ptr<BasePacketBuilder> inner, uint8_t level) : payload_(std::move(inner)), level_(level) {}
  NestedBuilder(uint8_t level) : level_(level) {}
};

class BuilderBuilderTest : public ::testing::Test {};

TEST(BuilderBuilderTest, nestingTest) {
  std::unique_ptr<BasePacketBuilder> innermost = NestedBuilder::Create(0);
  std::unique_ptr<BasePacketBuilder> number_1 = NestedBuilder::CreateNested(std::move(innermost), 1);
  std::unique_ptr<BasePacketBuilder> number_2 = NestedBuilder::CreateNested(std::move(number_1), 2);
  std::unique_ptr<BasePacketBuilder> number_3 = NestedBuilder::CreateNested(std::move(number_2), 3);
  std::unique_ptr<BasePacketBuilder> number_4 = NestedBuilder::CreateNested(std::move(number_3), 4);
  std::unique_ptr<NestedBuilder> number_5 = NestedBuilder::CreateNested(std::move(number_4), 5);

  std::vector<uint8_t> count_down{5, 4, 3, 2, 1, 0};
  ASSERT_EQ(*number_5->FinalPacket(), count_down);
}
}  // namespace packet
}  // namespace bluetooth
