/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#pragma once

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

#include <memory>
#include <string>
#include <vector>

class cmGlobalGenerator;
class cmMakefile;

/** \class cmExternalMakefileProjectGenerator
 * \brief Base class for generators for "External Makefile based IDE projects".
 *
 * cmExternalMakefileProjectGenerator is a base class for generators
 * for "external makefile based projects", i.e. IDE projects which work
 * an already existing makefiles.
 * See cmExtraEclipseCDT4Generator as an example.
 * After the makefiles have been generated by one of the Makefile
 * generators, the Generate() method is called and this generator
 * can iterate over the local generators and/or projects to produce the
 * project files for the IDE.
 */
class cmExternalMakefileProjectGenerator
{
public:
  virtual ~cmExternalMakefileProjectGenerator() = default;

  virtual void EnableLanguage(std::vector<std::string> const& languages,
                              cmMakefile*, bool optional);

  //! set the global generator which will generate the makefiles
  virtual void SetGlobalGenerator(cmGlobalGenerator* generator)
  {
    this->GlobalGenerator = generator;
  }

  //! Return the list of global generators supported by this extra generator
  const std::vector<std::string>& GetSupportedGlobalGenerators() const
  {
    return this->SupportedGlobalGenerators;
  }

  /** Create a full name from the given global generator name and the
   * extra generator name
   */
  static std::string CreateFullGeneratorName(
    const std::string& globalGenerator, const std::string& extraGenerator);

  //! Generate the project files, the Makefiles have already been generated
  virtual void Generate() = 0;

  void SetName(const std::string& n) { this->Name = n; }
  std::string GetName() const { return this->Name; }

  virtual bool Open(const std::string& bindir, const std::string& projectName,
                    bool dryRun);

protected:
  //! Contains the names of the global generators support by this generator.
  std::vector<std::string> SupportedGlobalGenerators;
  //! the global generator which creates the makefiles
  const cmGlobalGenerator* GlobalGenerator = nullptr;

  std::string Name;
};

class cmExternalMakefileProjectGeneratorFactory
{
public:
  cmExternalMakefileProjectGeneratorFactory(std::string n, std::string doc);
  virtual ~cmExternalMakefileProjectGeneratorFactory();

  std::string GetName() const;
  std::string GetDocumentation() const;
  std::vector<std::string> GetSupportedGlobalGenerators() const;
  std::vector<std::string> Aliases;

  virtual std::unique_ptr<cmExternalMakefileProjectGenerator>
  CreateExternalMakefileProjectGenerator() const = 0;

  void AddSupportedGlobalGenerator(const std::string& base);

private:
  std::string Name;
  std::string Documentation;
  std::vector<std::string> SupportedGlobalGenerators;
};

template <class T>
class cmExternalMakefileProjectGeneratorSimpleFactory
  : public cmExternalMakefileProjectGeneratorFactory
{
public:
  cmExternalMakefileProjectGeneratorSimpleFactory(const std::string& n,
                                                  const std::string& doc)
    : cmExternalMakefileProjectGeneratorFactory(n, doc)
  {
  }

  std::unique_ptr<cmExternalMakefileProjectGenerator>
  CreateExternalMakefileProjectGenerator() const override
  {
    std::unique_ptr<cmExternalMakefileProjectGenerator> p(new T);
    p->SetName(this->GetName());
    return p;
  }
};
