#pragma once

#include "cmConfigure.h" // IWYU pragma: keep

#include <set>

#include "cmCommonTargetGenerator.h"
#include "cmGlobalFASTBuildGenerator.h"
#include "cmOSXBundleGenerator.h"

class cmCustomCommandGenerator;
class cmGeneratedFileStream;
class cmLocalFASTBuildGenerator;

/** \class cmFASTBuildTargetGenerator
 * \brief Base class for FASTBuild target generation
 */
class cmFASTBuildTargetGenerator : public cmCommonTargetGenerator
{
public:
  /// Create a cmFASTBuildTargetGenerator according to the @a target's type.
  static cmFASTBuildTargetGenerator* New(cmGeneratorTarget* target);

  /// Constructior
  cmFASTBuildTargetGenerator(cmGeneratorTarget* target);

  /// Destructor
  ~cmFASTBuildTargetGenerator() override;

  /// Must be redefined in inherited classes to create target structure
  virtual void Generate() {}

  /// Overriden to do nothing?
  void AddIncludeFlags(std::string& flags, std::string const& lang,
                       const std::string& config) override;

  /// Makes a path relative to directory containing the build file if possible.
  std::string ConvertToFASTBuildPath(const std::string& path) const;

  /// Gets target generator's name
  std::string GetName();

  /// Returns languages needed by the target
  virtual std::vector<std::string> GetLanguages()
  {
    return std::vector<std::string>();
  }

  /// Returns cmMakeFile pointer
  cmMakefile* GetMakefile() const { return this->Makefile; }

  /// Returns cmGeneratorTarget pointer
  cmGeneratorTarget* GetGeneratorTarget() const
  {
    return this->GeneratorTarget;
  }

protected:
  /// see cmCommonTargetGenerator::GetClangTidyReplacementsFilePath
  std::string GetClangTidyReplacementsFilePath(
    std::string const& directory, cmSourceFile const& source,
    std::string const& config) const override;

  /// Returns configuration name
  std::string GetConfigName();

  /// Return the global generator
  cmGlobalFASTBuildGenerator* GetGlobalGenerator() const;

  /// Returns the filestream of the generated build file.
  cmGeneratedFileStream& GetBuildFileStream() const
  {
    return *this->GetGlobalGenerator()->GetBuildFileStream();
  }

  /// Returns associated local generator
  cmLocalFASTBuildGenerator* GetLocalGenerator() const
  {
    return this->LocalGenerator;
  }

  /// Returns target's name
  std::string GetTargetName() const;

  /// Generate commands for custom command build step.
  std::vector<cmGlobalFASTBuildGenerator::FASTBuildExecNode> GenerateCommands(
    const std::string& buildStep = "");

  /// Returns Custom Target name
  std::string GetCustomCommandTargetName(const cmCustomCommand& cc,
                                         const std::string& extra = "") const;

  /// Check if a custom command is configuration dependent or not.
  static bool isConfigDependant(const cmCustomCommandGenerator* ccg);

  /// Escape ^, $ and replace FASTBUILD_DOLLAR_TAG by $
  static void UnescapeFASTBuildVariables(std::string& string);
  /// Do not understand for now
  static void UnescapeFASTBuildDefines(std::string& string);

  /// Resolve config variable
  static void ResolveFASTBuildVariables(std::string& string,
                                        const std::string& configName);

  // write rules for Mac OS X Application Bundle content.
  struct MacOSXContentGeneratorType
    : cmOSXBundleGenerator::MacOSXContentGeneratorType
  {
    MacOSXContentGeneratorType(cmFASTBuildTargetGenerator* g)
      : Generator(g)
    {
    }

    void operator()(cmSourceFile const& source, const char* pkgloc,
                    const std::string& config) override;

  private:
    cmFASTBuildTargetGenerator* Generator;
  };
  friend struct MacOSXContentGeneratorType;

  MacOSXContentGeneratorType* MacOSXContentGenerator;
  // Properly initialized by sub-classes.
  cmOSXBundleGenerator* OSXBundleGenerator;
  std::set<std::string> MacContentFolders;

  std::vector<std::string> ExtraFiles;

private:
  // Associated local generator
  cmLocalFASTBuildGenerator* LocalGenerator;

  // Map of custom command aliases.
  using CustomCommandAliasMap = std::map<std::pair<const cmCustomCommand*, std::string>,
                                        std::set<std::string>>;
  static CustomCommandAliasMap s_customCommandAliases;
};
