// Copyright 2021 The Tint Authors.
//
// 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.

#ifndef FUZZERS_TRANSFORM_BUILDER_H_
#define FUZZERS_TRANSFORM_BUILDER_H_

#include <string>
#include <vector>

#include "include/tint/tint.h"

#include "fuzzers/data_builder.h"

namespace tint {
namespace fuzzers {

/// Fuzzer utility class to build inputs for transforms and setup the transform
/// manager.
class TransformBuilder {
 public:
  /// @brief Initialize the data source using a data buffer as a seed
  /// @param data - pointer to a data buffer to use as a seed
  /// @param size - size of data buffer
  explicit TransformBuilder(const uint8_t* data, size_t size)
      : builder_(data, size) {}
  ~TransformBuilder() {}

  transform::Manager* manager() { return &manager_; }
  transform::DataMap* data_map() { return &data_map_; }
  DataBuilder* builder() { return &builder_; }

  /// Adds a transform and needed data to |manager_| and |data_map_|.
  /// @tparam T - A class that inherits from transform::Transform and has an
  ///             explicit specialization in AddTransformImpl.
  template <typename T>
  void AddTransform() {
    static_assert(std::is_base_of<transform::Transform, T>::value,
                  "T is not a transform::Transform");
    AddTransformImpl<T>::impl(this);
  }

  /// Helper that invokes Add*Transform for all of the platform independent
  /// passes.
  void AddPlatformIndependentPasses() {
    AddTransform<transform::Robustness>();
    AddTransform<transform::FirstIndexOffset>();
    AddTransform<transform::BindingRemapper>();
    AddTransform<transform::Renamer>();
    AddTransform<transform::SingleEntryPoint>();
    AddTransform<transform::VertexPulling>();
  }

 private:
  DataBuilder builder_;
  transform::Manager manager_;
  transform::DataMap data_map_;

  /// Implementation of AddTransform, specialized for each transform that is
  /// implemented. Default implementation intentionally deleted to cause compile
  /// error if unimplemented type passed in.
  /// @tparam T - A fuzzer transform
  template <typename T>
  struct AddTransformImpl;

  /// Implementation of AddTransform for transform::Robustness
  template <>
  struct AddTransformImpl<transform::Robustness> {
    /// Add instance of transform::Robustness to TransformBuilder
    /// @param tb - TransformBuilder to add transform to
    static void impl(TransformBuilder* tb) {
      tb->manager()->Add<transform::Robustness>();
    }
  };

  /// Implementation of AddTransform for transform::FirstIndexOffset
  template <>
  struct AddTransformImpl<transform::FirstIndexOffset> {
    /// Add instance of transform::FirstIndexOffset to TransformBuilder
    /// @param tb - TransformBuilder to add transform to
    static void impl(TransformBuilder* tb) {
      struct Config {
        uint32_t group;
        uint32_t binding;
      };

      Config config = tb->builder()->build<Config>();

      tb->data_map()->Add<tint::transform::FirstIndexOffset::BindingPoint>(
          config.binding, config.group);
      tb->manager()->Add<transform::FirstIndexOffset>();
    }
  };

  /// Implementation of AddTransform for transform::BindingRemapper
  template <>
  struct AddTransformImpl<transform::BindingRemapper> {
    /// Add instance of transform::BindingRemapper to TransformBuilder
    /// @param tb - TransformBuilder to add transform to
    static void impl(TransformBuilder* tb) {
      struct Config {
        uint8_t old_group;
        uint8_t old_binding;
        uint8_t new_group;
        uint8_t new_binding;
        ast::Access new_access;
      };

      std::vector<Config> configs = tb->builder()->vector<Config>();
      transform::BindingRemapper::BindingPoints binding_points;
      transform::BindingRemapper::AccessControls accesses;
      for (const auto& config : configs) {
        binding_points[{config.old_binding, config.old_group}] = {
            config.new_binding, config.new_group};
        accesses[{config.old_binding, config.old_group}] = config.new_access;
      }

      tb->data_map()->Add<transform::BindingRemapper::Remappings>(
          binding_points, accesses, tb->builder()->build<bool>());
      tb->manager()->Add<transform::BindingRemapper>();
    }
  };

  /// Implementation of AddTransform for transform::Renamer
  template <>
  struct AddTransformImpl<transform::Renamer> {
    /// Add instance of transform::Renamer to TransformBuilder
    /// @param tb - TransformBuilder to add transform to
    static void impl(TransformBuilder* tb) {
      tb->manager()->Add<transform::Renamer>();
    }
  };

  /// Implementation of AddTransform for transform::SingleEntryPoint
  template <>
  struct AddTransformImpl<transform::SingleEntryPoint> {
    /// Add instance of transform::SingleEntryPoint to TransformBuilder
    /// @param tb - TransformBuilder to add transform to
    static void impl(TransformBuilder* tb) {
      auto input = tb->builder()->build<std::string>();
      transform::SingleEntryPoint::Config cfg(input);

      tb->data_map()->Add<transform::SingleEntryPoint::Config>(cfg);
      tb->manager()->Add<transform::SingleEntryPoint>();
    }
  };  // struct AddTransformImpl<transform::SingleEntryPoint>

  /// Implementation of AddTransform for transform::VertexPulling
  template <>
  struct AddTransformImpl<transform::VertexPulling> {
    /// Add instance of transform::VertexPulling to TransformBuilder
    /// @param tb - TransformBuilder to add transform to
    static void impl(TransformBuilder* tb) {
      transform::VertexPulling::Config cfg;
      cfg.entry_point_name = tb->builder()->build<std::string>();
      cfg.vertex_state =
          tb->builder()->vector<transform::VertexBufferLayoutDescriptor>(
              GenerateVertexBufferLayoutDescriptor);
      cfg.pulling_group = tb->builder()->build<uint32_t>();

      tb->data_map()->Add<transform::VertexPulling::Config>(cfg);
      tb->manager()->Add<transform::VertexPulling>();
    }

   private:
    /// Generate an instance of transform::VertexAttributeDescriptor
    /// @param b - DataBuilder to use
    static transform::VertexAttributeDescriptor
    GenerateVertexAttributeDescriptor(DataBuilder* b) {
      transform::VertexAttributeDescriptor desc{};
      desc.format = b->enum_class<transform::VertexFormat>(
          static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
      desc.offset = b->build<uint32_t>();
      desc.shader_location = b->build<uint32_t>();
      return desc;
    }

    /// Generate an instance of VertexBufferLayoutDescriptor
    /// @param b - DataBuilder to use
    static transform::VertexBufferLayoutDescriptor
    GenerateVertexBufferLayoutDescriptor(DataBuilder* b) {
      transform::VertexBufferLayoutDescriptor desc;
      desc.array_stride = b->build<uint32_t>();
      desc.step_mode = b->enum_class<transform::VertexStepMode>(
          static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
      desc.attributes = b->vector<transform::VertexAttributeDescriptor>(
          GenerateVertexAttributeDescriptor);
      return desc;
    }
  };
};  // class TransformBuilder

}  // namespace fuzzers
}  // namespace tint

#endif  // FUZZERS_TRANSFORM_BUILDER_H_
