// Copyright 2013 The Flutter 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 FLUTTER_IMPELLER_RENDERER_VERTEX_BUFFER_BUILDER_H_
#define FLUTTER_IMPELLER_RENDERER_VERTEX_BUFFER_BUILDER_H_

#include <initializer_list>
#include <vector>

#include "impeller/base/strings.h"
#include "impeller/core/allocator.h"
#include "impeller/core/device_buffer.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/core/vertex_buffer.h"

namespace impeller {

template <class VertexType_, class IndexType_ = uint16_t>
class VertexBufferBuilder {
 public:
  using VertexType = VertexType_;
  using IndexType = IndexType_;

  VertexBufferBuilder() = default;

  ~VertexBufferBuilder() = default;

  constexpr impeller::IndexType GetIndexType() const {
    if (indices_.size() == 0) {
      return impeller::IndexType::kNone;
    }
    if constexpr (sizeof(IndexType) == 2) {
      return impeller::IndexType::k16bit;
    }
    if (sizeof(IndexType) == 4) {
      return impeller::IndexType::k32bit;
    }
    return impeller::IndexType::kUnknown;
  }

  void SetLabel(const std::string& label) { label_ = label; }

  void Reserve(size_t count) { return vertices_.reserve(count); }

  void ReserveIndices(size_t count) { return indices_.reserve(count); }

  bool HasVertices() const { return !vertices_.empty(); }

  size_t GetVertexCount() const { return vertices_.size(); }

  size_t GetIndexCount() const {
    return indices_.size() > 0 ? indices_.size() : vertices_.size();
  }

  const VertexType& Last() const {
    FML_DCHECK(!vertices_.empty());
    return vertices_.back();
  }

  VertexBufferBuilder& AppendVertex(VertexType_ vertex) {
    vertices_.emplace_back(std::move(vertex));
    return *this;
  }

  VertexBufferBuilder& AddVertices(
      std::initializer_list<VertexType_> vertices) {
    vertices_.reserve(vertices.size());
    for (auto& vertex : vertices) {
      vertices_.emplace_back(std::move(vertex));
    }
    return *this;
  }

  VertexBufferBuilder& AppendIndex(IndexType_ index) {
    indices_.emplace_back(index);
    return *this;
  }

  VertexBuffer CreateVertexBuffer(HostBuffer& host_buffer) const {
    VertexBuffer buffer;
    buffer.vertex_buffer = CreateVertexBufferView(host_buffer);
    buffer.index_buffer = CreateIndexBufferView(host_buffer);
    buffer.vertex_count = GetIndexCount();
    buffer.index_type = GetIndexType();
    return buffer;
  };

  VertexBuffer CreateVertexBuffer(Allocator& device_allocator) const {
    VertexBuffer buffer;
    // This can be merged into a single allocation.
    buffer.vertex_buffer = CreateVertexBufferView(device_allocator);
    buffer.index_buffer = CreateIndexBufferView(device_allocator);
    buffer.vertex_count = GetIndexCount();
    buffer.index_type = GetIndexType();
    return buffer;
  };

  void IterateVertices(const std::function<void(VertexType&)>& iterator) {
    for (auto& vertex : vertices_) {
      iterator(vertex);
    }
  }

 private:
  std::vector<VertexType> vertices_;
  std::vector<IndexType> indices_;
  std::string label_;

  BufferView CreateVertexBufferView(HostBuffer& buffer) const {
    return buffer.Emplace(vertices_.data(),
                          vertices_.size() * sizeof(VertexType),
                          alignof(VertexType));
  }

  BufferView CreateVertexBufferView(Allocator& allocator) const {
    auto buffer = allocator.CreateBufferWithCopy(
        reinterpret_cast<const uint8_t*>(vertices_.data()),
        vertices_.size() * sizeof(VertexType));
    if (!buffer) {
      return {};
    }
    if (!label_.empty()) {
      buffer->SetLabel(SPrintF("%s Vertices", label_.c_str()));
    }
    return DeviceBuffer::AsBufferView(buffer);
  }

  std::vector<IndexType> CreateIndexBuffer() const { return indices_; }

  BufferView CreateIndexBufferView(HostBuffer& buffer) const {
    const auto index_buffer = CreateIndexBuffer();
    if (index_buffer.size() == 0) {
      return {};
    }
    return buffer.Emplace(index_buffer.data(),
                          index_buffer.size() * sizeof(IndexType),
                          alignof(IndexType));
  }

  BufferView CreateIndexBufferView(Allocator& allocator) const {
    const auto index_buffer = CreateIndexBuffer();
    if (index_buffer.size() == 0) {
      return {};
    }
    auto buffer = allocator.CreateBufferWithCopy(
        reinterpret_cast<const uint8_t*>(index_buffer.data()),
        index_buffer.size() * sizeof(IndexType));
    if (!buffer) {
      return {};
    }
    if (!label_.empty()) {
      buffer->SetLabel(SPrintF("%s Indices", label_.c_str()));
    }
    return DeviceBuffer::AsBufferView(buffer);
  }
};

}  // namespace impeller

#endif  // FLUTTER_IMPELLER_RENDERER_VERTEX_BUFFER_BUILDER_H_
