#pragma once

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

#include "cmFASTBuildTargetGenerator.h"
#include "cmGlobalFASTBuildGenerator.h"

/** \class cmFASTBuildNormalTargetGenerator
 * \brief Class for FASTBuild compiler related target generation
 */
class cmFASTBuildNormalTargetGenerator : public cmFASTBuildTargetGenerator
{
public:
  /// Constructor
  cmFASTBuildNormalTargetGenerator(cmGeneratorTarget* gt);

  /// Destructor
  ~cmFASTBuildNormalTargetGenerator();

  /// Generates the target structure
  void Generate() override;

  /// Returns the languages needed by this target
  std::vector<std::string> GetLanguages() override;

private:
  // Generate ObjectList nodes for this target (e.g compilation of source files)
  std::vector<cmGlobalFASTBuildGenerator::FASTBuildObjectListNode>
  GenerateObjects();

  // Generate Linker nodes to create the real output of the target (e.g Exe, static or shared lib.)
  std::vector<cmGlobalFASTBuildGenerator::FASTBuildLinkerNode> GenerateLink(
    const std::vector<cmGlobalFASTBuildGenerator::FASTBuildObjectListNode>&
      objectLists);

  // Contains target's information
  struct FASTBuildTargetNames
  {
    std::string targetNameOut;
    std::string targetNameReal;
    std::string targetNameImport;
    std::string targetNamePDB;
    std::string targetNameSO;

    std::string targetOutput;
    std::string targetOutputReal;
    std::string targetOutputImplib;
    std::string targetOutputDir;
    std::string targetOutputPDBDir;
    std::string targetOutputCompilePDBDir;
  };

  /// Populate compiler flags for a source file of this target
  /// according to the associated language.
  void DetectCompilerFlags(std::string& compileFlags,
                           const cmSourceFile* source,
                           const std::string& language);

  /// Populate output directories for a target
  /// corresponding to the configuration sent as parameter.
  void DetectOutput(FASTBuildTargetNames& targetNamesOut,
                    const std::string& configName);

  /// Populate path to libraries to link with a target
  /// corresponding to the configuration sent as parameter.
  void DetectLinkerLibPaths(std::string& linkerLibPath,
                            const std::string& configName);
  /// Populate first arguments of link commands for a target
  /// corresponding to the configuration sent as parameter.
  bool DetectBaseLinkerCommand(std::string& command,
                               const std::string& configName);

  /// Append the link command for a target in the link commands list
  /// corresponding to the configuration sent as parameter.
  void ComputeLinkCmds(std::vector<std::string>& linkCmds,
                       std::string configName);

  /// Returns defines for a source file corresponding
  /// to the configuration and language sent as parameter.
  std::string ComputeDefines(const cmSourceFile* source,
                             const std::string& configName,
                             const std::string& language);

  /// Populate object libraries needed as source dependencies if there is ones
  /// corresponding to the configuration sent as parameter.
  void DetectTargetObjectDependencies(const std::string& configName,
                                      std::vector<std::string>& dependencies);

  /// Returns Manifest converted to a FASTBuild path.
  std::string GetManifestsAsFASTBuildPath();

  /// Returns all command lines as one string, concatenated
  /// to be interpreted by a command interpreter (cmd on Windows, bash on Linux for ex.)
  static std::string BuildCommandLine(
    const std::vector<std::string>& cmdLines);

  /// Splits a full command to executable/options.
  static void SplitExecutableAndFlags(const std::string& command,
                                      std::string& executable,
                                      std::string& options);

  /// Create tree directories contained if needed in the path sent as parameter.
  static void EnsureDirectoryExists(const std::string& path,
                                    const char* homeOutputDirectory);
};
