// Copyright 2020 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 SRC_TRANSFORM_TRANSFORM_H_
#define SRC_TRANSFORM_TRANSFORM_H_

#include <memory>
#include <unordered_map>
#include <utility>

#include "src/castable.h"
#include "src/program.h"

namespace tint {
namespace transform {

/// Data is the base class for transforms that accept extra input or emit extra
/// output information along with a Program.
class Data : public Castable<Data> {
 public:
  /// Constructor
  Data();

  /// Copy constructor
  Data(const Data&);

  /// Destructor
  ~Data() override;

  /// Assignment operator
  /// @returns this Data
  Data& operator=(const Data&);
};

/// DataMap is a map of Data unique pointers keyed by the Data's ClassID.
class DataMap {
 public:
  /// Constructor
  DataMap();

  /// Move constructor
  DataMap(DataMap&&);

  /// Constructor
  /// @param data_unique_ptrs a variadic list of additional data unique_ptrs
  /// produced by the transform
  template <typename... DATA>
  explicit DataMap(DATA... data_unique_ptrs) {
    PutAll(std::forward<DATA>(data_unique_ptrs)...);
  }

  /// Destructor
  ~DataMap();

  /// Move assignment operator
  /// @param rhs the DataMap to move into this DataMap
  /// @return this DataMap
  DataMap& operator=(DataMap&& rhs);

  /// Adds the data into DataMap keyed by the ClassID of type T.
  /// @param data the data to add to the DataMap
  template <typename T>
  void Put(std::unique_ptr<T>&& data) {
    static_assert(std::is_base_of<Data, T>::value,
                  "T does not derive from Data");
    map_[&TypeInfo::Of<T>()] = std::move(data);
  }

  /// Creates the data of type `T` with the provided arguments and adds it into
  /// DataMap keyed by the ClassID of type T.
  /// @param args the arguments forwarded to the constructor for type T
  template <typename T, typename... ARGS>
  void Add(ARGS&&... args) {
    Put(std::make_unique<T>(std::forward<ARGS>(args)...));
  }

  /// @returns a pointer to the Data placed into the DataMap with a call to
  /// Put()
  template <typename T>
  T const* Get() const {
    auto it = map_.find(&TypeInfo::Of<T>());
    if (it == map_.end()) {
      return nullptr;
    }
    return static_cast<T*>(it->second.get());
  }

  /// Add moves all the data from other into this DataMap
  /// @param other the DataMap to move into this DataMap
  void Add(DataMap&& other) {
    for (auto& it : other.map_) {
      map_.emplace(it.first, std::move(it.second));
    }
    other.map_.clear();
  }

 private:
  template <typename T0>
  void PutAll(T0&& first) {
    Put(std::forward<T0>(first));
  }

  template <typename T0, typename... Tn>
  void PutAll(T0&& first, Tn&&... remainder) {
    Put(std::forward<T0>(first));
    PutAll(std::forward<Tn>(remainder)...);
  }

  std::unordered_map<const TypeInfo*, std::unique_ptr<Data>> map_;
};

/// The return type of Run()
class Output {
 public:
  /// Constructor
  Output();

  /// Constructor
  /// @param program the program to move into this Output
  explicit Output(Program&& program);

  /// Constructor
  /// @param program_ the program to move into this Output
  /// @param data_ a variadic list of additional data unique_ptrs produced by
  /// the transform
  template <typename... DATA>
  Output(Program&& program_, DATA... data_)
      : program(std::move(program_)), data(std::forward<DATA>(data_)...) {}

  /// The transformed program. May be empty on error.
  Program program;

  /// Extra output generated by the transforms.
  DataMap data;
};

/// Interface for Program transforms
class Transform : public Castable<Transform> {
 public:
  /// Constructor
  Transform();
  /// Destructor
  ~Transform() override;

  /// Runs the transform on `program`, returning the transformation result.
  /// @param program the source program to transform
  /// @param data optional extra transform-specific input data
  /// @returns the transformation result
  virtual Output Run(const Program* program, const DataMap& data = {}) const;

  /// @param program the program to inspect
  /// @param data optional extra transform-specific input data
  /// @returns true if this transform should be run for the given program
  virtual bool ShouldRun(const Program* program,
                         const DataMap& data = {}) const;

 protected:
  /// Runs the transform using the CloneContext built for transforming a
  /// program. Run() is responsible for calling Clone() on the CloneContext.
  /// @param ctx the CloneContext primed with the input program and
  /// ProgramBuilder
  /// @param inputs optional extra transform-specific input data
  /// @param outputs optional extra transform-specific output data
  virtual void Run(CloneContext& ctx,
                   const DataMap& inputs,
                   DataMap& outputs) const;

  /// Removes the statement `stmt` from the transformed program.
  /// RemoveStatement handles edge cases, like statements in the initializer and
  /// continuing of for-loops.
  /// @param ctx the clone context
  /// @param stmt the statement to remove when the program is cloned
  static void RemoveStatement(CloneContext& ctx, const ast::Statement* stmt);

  /// CreateASTTypeFor constructs new ast::Type nodes that reconstructs the
  /// semantic type `ty`.
  /// @param ctx the clone context
  /// @param ty the semantic type to reconstruct
  /// @returns a ast::Type that when resolved, will produce the semantic type
  /// `ty`.
  static const ast::Type* CreateASTTypeFor(CloneContext& ctx,
                                           const sem::Type* ty);
};

}  // namespace transform
}  // namespace tint

#endif  // SRC_TRANSFORM_TRANSFORM_H_
