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

#include "cmGlobalGenerator.h"

#include "cmGhsMultiGpj.h"
#include "cmGlobalGeneratorFactory.h"

class cmGeneratedFileStream;
class cmUVisionTargetGenerator;

class cmGlobalUVisionGenerator : public cmGlobalGenerator
{
public:
  cmGlobalUVisionGenerator(cmake* cm);
  ~cmGlobalUVisionGenerator();

  static cmGlobalGeneratorFactory* NewFactory()
  {
    return new cmGlobalGeneratorSimpleFactory<cmGlobalUVisionGenerator>();
  }
  void cmGlobalUVisionGenerator::AddExtraTargets(
    cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens);
  void AddExtraIDETargets();

  ///! create the correct local generator
  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;

  /// @return the name of this generator.
  static std::string GetActualName() { return "uVision"; }

  ///! Get the name for this generator
  std::string GetName() const override { return this->GetActualName(); }

  /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
  static void GetDocumentation(cmDocumentationEntry& entry);

  /**
   * Utilized by the generator factory to determine if this generator
   * supports toolsets.
   */
  static bool SupportsToolset() { return false; }

  /**
   * Utilized by the generator factory to determine if this generator
   * supports platforms.
   */
  static bool SupportsPlatform() { return false; }

  // Toolset / Platform Support
  //  bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
  //  bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;

  /**
   * Try to determine system information such as shared library
   * extension, pthreads, byte order etc.
   */
  void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
                      bool optional) override;
  /*
   * Determine what program to use for building the project.
   */
  bool FindMakeProgram(cmMakefile* mf) override;

  void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;

  // Target dependency sorting
  class TargetSet : public std::set<cmGeneratorTarget const*>
  {
  };
  class TargetCompare
  {
    std::string First;

  public:
    TargetCompare(std::string const& first)
      : First(first)
    {
    }
    bool operator()(cmGeneratorTarget const* l,
                    cmGeneratorTarget const* r) const;
  };
  class OrderedTargetDependSet;

  void appendProjectFile(std::string fileNameToUvProject)
  {
    //    cmSystemTools::Message("Appending " + fileNameToUvProject + " to
    //    Multi-Project List ");
    m_fullSubProjectNames.push_back(fileNameToUvProject);
  }
  void appendUtility(std::string& utilProject)
  {
    m_pendingPreBuildSteps.push_back(utilProject);
  }

  std::vector<std::string>& PreBuildSteps()
  {
    return this->m_pendingPreBuildSteps;
  }

protected:
  void Generate() override;

private:
  /* top-level project */
  void OutputTopLevelProject(cmLocalGenerator* root,
                             std::vector<cmLocalGenerator*>& generators);

  std::vector<std::string>
    m_pendingPreBuildSteps; //< collect all unused/unasigned prebuild cmds ..
                            // to be added to the "next" target
  std::vector<std::string>
    m_fullSubProjectNames; //< list of all generated sub project-file-names
};

class cmGlobalUVisionGenerator::OrderedTargetDependSet
  : public std::multiset<cmTargetDepend,
                         cmGlobalUVisionGenerator::TargetCompare>
{
  typedef std::multiset<cmTargetDepend,
                        cmGlobalUVisionGenerator::TargetCompare>
    derived;

public:
  typedef cmGlobalGenerator::TargetDependSet TargetDependSet;
  OrderedTargetDependSet(TargetDependSet const&, std::string const& first);
};

#endif // cmUVisionGenerator_h
