// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#ifndef __ACProject_h__
#define __ACProject_h__

// CProject specialization for ac++ project files

#include <string>
using std::string;
#include <set>
using std::set;
#include <filesystem>

class ACConfig;
namespace clang {
  class CompilerInstance;
  class Rewriter;
}
#include "ACBase/PathManager.h"
#include "ACBase/Config.h"

#include <libxml/tree.h>

#include "ACErrorStream.h"
#include "ACBase/ErrorStream.h" // FIXME: we should no longer require this class
#include "ACFileID.h"

class ACProject : public ACBase::PathManager {
  ACErrorStream &_err;
  ACBase::ErrorStream _puma_err; // FIXME: we should no longer require this object
  clang::CompilerInstance *_ci;
  ACBase::Config _puma_config;
  set<ACFileID> _closed_files;
  set<ACFileID> _virtual_files;
  int _backend_standard; // e.g. 1998 for C++98, 2017 for C++17
  bool _tricore_hack; // as long as Clang does not support tricore we need special treatment, which is indicated with this flag

  // list of aspect header files in the project
  std::list<std::filesystem::path> aspect_headers_;
  mutable std::set<std::filesystem::path> aspect_headers_canonical_;

        // Add all files from the XML project description to the project
  void addFiles (xmlDocPtr doc, xmlNodePtr node, const string& xpath);

public:
  ACProject (ACErrorStream &, int &argc, char **&argv);
  ~ACProject ();
  ACBase::Config &config () { return _puma_config; }
  void configure_project_file_manager(const ACBase::Config &c);

  // access the list of aspect header paths in the project
  const std::list<std::filesystem::path> &aspect_headers () const { return aspect_headers_; }
  std::list<std::filesystem::path> &aspect_headers () { return aspect_headers_; }

  // checks whether the given file is an aspect header
  bool is_aspect_header (const std::filesystem::path filename) const;

  // check whether the passed c++ version, e.g. 2014 for C++14, is supported by the backend compiler
  bool backend_supports_cxx(int version) const { return _backend_standard >= version; }

  // check whether the tricore hack is activated
  bool tricore_hack() const { return _tricore_hack; }

  // load the project file
  bool loadProject (string acprj);

  // Add a new *virtual* file to the project.
  ACFileID addVirtualFile (const string &filename, const string &contents = "");

  // Remove a virtual file
  void removeVirtualFile (ACFileID fid);

  bool isVirtualFile (ACFileID fid) {
    return _virtual_files.find(fid) != _virtual_files.end();
  }

  // Create an instance of the clang compiler frontend.
  void create_compiler_instance (ACConfig &conf);
  clang::CompilerInstance *get_compiler_instance () const { return _ci; }
  ACErrorStream &err () const { return _err; }

  // Add a forced include to the front end
  void add_forced_include (const string &file);

  //Remove a forced include from the front end
  void remove_forced_include (const string &file);

  // Remove all forced includes
  void remove_forced_includes ();

  // Get the list of forced includes from the front end as a vector of filenames
  void get_forced_includes (std::vector<std::string> &forced_includes);

  // Generate a path for including 'to' from within the file 'from'
  string include_path(const string &from, const string &to);

  void save () const; // needed by Weaver class
  void close (ACFileID fid); // needed by Weaver class
};

#endif /* __ACProject_h__ */
