// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SRC_DEVICES_USB_TESTING_DESCRIPTOR_BUILDER_DESCRIPTOR_BUILDER_H_
#define SRC_DEVICES_USB_TESTING_DESCRIPTOR_BUILDER_DESCRIPTOR_BUILDER_H_
#include <zircon/hw/usb.h>

#include <cstdint>
#include <vector>

namespace usb {
static void VectorAppend(std::vector<uint8_t>& vector, const void* data, size_t size) {
  vector.insert(vector.end(), static_cast<const uint8_t*>(data),
                static_cast<const uint8_t*>(data) + size);
}

template <typename T>
static void VectorAppend(std::vector<uint8_t>& vector, T value) {
  VectorAppend(vector, &value, sizeof(value));
}

static inline uint8_t EpIndexToAddress(uint8_t index) {
  return static_cast<uint8_t>((index & 0xF) | ((index & 0x10) << 3));
}

constexpr uint8_t kInEndpointStart = 17;
constexpr uint8_t kOutEndpointStart = 1;

class EndpointBuilder {
 public:
  explicit EndpointBuilder(uint8_t config_num, uint8_t endpoint_type, uint8_t endpoint_index,
                           bool in) {
    base_desc_.bmAttributes = endpoint_type;
    base_desc_.bLength = sizeof(base_desc_);
    base_desc_.bDescriptorType = USB_DT_ENDPOINT;
    base_desc_.bEndpointAddress =
        EpIndexToAddress(endpoint_index + (in ? kInEndpointStart : kOutEndpointStart));
  }

  std::vector<uint8_t> Generate() const {
    size_t total = sizeof(base_desc_) + descriptors_.size();
    std::vector<uint8_t> data;
    data.reserve(total);
    VectorAppend(data, base_desc_);
    VectorAppend(data, descriptors_.data(), descriptors_.size());
    return data;
  }

 private:
  std::vector<uint8_t> descriptors_;
  usb_endpoint_descriptor_t base_desc_ = {};
};

class InterfaceBuilder {
 public:
  explicit InterfaceBuilder(uint8_t config_num) {
    base_desc_.bNumEndpoints = 0;
    base_desc_.bLength = sizeof(base_desc_);
    base_desc_.bDescriptorType = USB_DT_INTERFACE;
  }

  void AddEndpoint(const EndpointBuilder& builder) {
    auto data = builder.Generate();
    AddEndpoint(data.data(), data.size());
  }
  void AddEndpoint(void* desc, size_t desc_length) {
    VectorAppend(descriptors_, desc, desc_length);
    base_desc_.bNumEndpoints++;
  }

  std::vector<uint8_t> Generate() const {
    size_t total = sizeof(base_desc_) + descriptors_.size();
    std::vector<uint8_t> data;
    data.reserve(total);
    VectorAppend(data, base_desc_);
    VectorAppend(data, descriptors_.data(), descriptors_.size());
    return data;
  }

 private:
  std::vector<uint8_t> descriptors_;
  usb_interface_descriptor_t base_desc_ = {};
};

class ConfigurationBuilder {
 public:
  explicit ConfigurationBuilder(uint8_t config_num) {
    base_desc_.bNumInterfaces = 0;
    base_desc_.iConfiguration = config_num;
    base_desc_.bLength = sizeof(base_desc_);
    base_desc_.bDescriptorType = USB_DT_CONFIG;
  }

  void AddInterface(const InterfaceBuilder& builder) {
    auto data = builder.Generate();
    AddInterface(data.data(), data.size());
  }
  void AddInterface(void* interface_desc, size_t interface_desc_length) {
    VectorAppend(descriptors_, interface_desc, interface_desc_length);
    base_desc_.bNumInterfaces++;
  }

  std::vector<uint8_t> Generate() const {
    size_t total = sizeof(base_desc_) + descriptors_.size();
    std::vector<uint8_t> data;
    data.reserve(total);
    VectorAppend(data, base_desc_);
    VectorAppend(data, descriptors_.data(), descriptors_.size());
    return data;
  }

 private:
  std::vector<uint8_t> descriptors_;
  usb_configuration_descriptor_t base_desc_ = {};
};

class DeviceDescriptorBuilder {
 public:
  explicit DeviceDescriptorBuilder() {
    base_desc_.bNumConfigurations = 0;
    base_desc_.bLength = sizeof(base_desc_);
    base_desc_.bDescriptorType = USB_DT_DEVICE;
  }

  void AddConfiguration(const ConfigurationBuilder& builder) {
    auto data = builder.Generate();
    AddConfiguration(data.data(), data.size());
  }
  void AddConfiguration(void* config_desc, size_t config_desc_length) {
    VectorAppend(descriptors_, config_desc, config_desc_length);
    base_desc_.bNumConfigurations++;
  }

  std::vector<uint8_t> Generate() {
    size_t total = sizeof(base_desc_) + descriptors_.size();
    std::vector<uint8_t> data;
    data.reserve(total);
    VectorAppend(data, base_desc_);
    VectorAppend(data, descriptors_.data(), descriptors_.size());
    return data;
  }

 private:
  std::vector<uint8_t> descriptors_;
  usb_device_descriptor_t base_desc_ = {};
};
}  // namespace usb
#endif  // SRC_DEVICES_USB_TESTING_DESCRIPTOR_BUILDER_DESCRIPTOR_BUILDER_H_
