// This file is part of AspectC++.
// Copyright (C) 1999-2016  The AspectC++ developer team.
//                                                                
// 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 ACBASE_PathManager_H
#define ACBASE_PathManager_H

/** \file
 * Source and destination path and file management. */

#include "ErrorStream.h"
#include "PathIterator.h"
#include "ProjectFile.h"
#include <list>
#include <string>

namespace ACBase {

class RegComp;
class Config;

struct PathInfo {
  std::string src_path;
  std::string src_path_canonical;
  std::string dest_path;
};

/** \class PathManager PathManager.h Puma/PathManager.h
 * Source and destination path and file management. Source paths are
 * mapped to their destination paths. The source tree can be iterated
 * and new files can be added.
 * \ingroup common */
class PathManager {

  /** Project file's name to ProjectFile map type. */
  typedef std::map<std::string, ProjectFile> Map;
  /** Project file's name to ProjectFile map pair type. */
  typedef Map::value_type MapPair;
  /** Project file's name to ProjectFile map constant iterator type. */
  typedef Map::const_iterator MapConstIter;

  ErrorStream &err_;
  std::list<PathInfo> paths_;
  std::list<RegComp*> write_protected_path_patterns_;
  mutable Map m_files;
  bool has_dest_;
  bool has_src_;

public:
  /** Constructor.
   * \param err Error stream used to report errors. */
  PathManager(ErrorStream &err)
      : err_(err), has_dest_(false), has_src_(false) {
  }
  /** Copy-constructor: don't use it */
  PathManager(PathManager &other) = delete;
  /** Destructor. */
  virtual ~PathManager();

  /** Iterate the contents of the managed paths. Calls action() for every file found.
   * \param iterator The path iterator to use. */
  bool iterate(PathIterator &iterator) const;

  /** Add a source and destination paths pair.
   * \param srcPath The source path.
   * \param destPath The corresponding destination path. */
  virtual void add_path(const std::string &srcPath, const std::string &destPath);

  /** After adding the first path, the manager can answer whether the project
   *  has a destination or source path. Add addPath calls must be consistent!
   * \return Whether the project uses source paths
   */
  bool has_source_path() const { return has_src_; }
  
  /** After adding the first path, the manager can answer whether the project
   *  has a destination or source path. Add addPath calls must be consistent!
   * \return Whether the project uses destination paths
   */
  bool has_dest_path() const { return has_dest_; }

  /** Add a new file to the project file list
   * \param filename The filename.
   * \param destPath The corresponding destination path.
   * \return An iterator pointing to the file added. */
  MapConstIter add_file(const std::string &filename, const std::string &dest_path);

  /** Get the managed paths.
   * \return The list of managed paths. */
  const std::list<PathInfo> &paths() const { return paths_; }

  /** Add a pattern for a write-protected path.
   * \param pathPattern Regular expression for a path to write-protect. */
  void protect(const std::string &path_pattern);

  /** Check if the given path is write-protected.
   * \param path The path.
   * \return True if the path is write-protected. */
  bool is_protected(const std::string &path) const;

  /** Check whether a file does not exist in the destination directory or
   *  if the source has been changed.
   * \param file The path to the file in the source directory tree
   * \return Result of the check
   */
  bool is_newer (const std::string &file) const;

  /** Check if a given file is directly managed by this path manager or
   * is found below any of the managed paths.
   * \param filename The filename.
   * \return True if the file was found. */
  virtual bool is_below(const std::string &file) const {
    MapConstIter iter;
    return is_below(file, iter);
  }

  /** Configure the path manager.
   * \param config The configuration. */
  virtual void configure(const Config &config);

  /** Get the error stream used by this path manager.
   * \return A reference to the error stream. */
  ErrorStream &err() const {
    return err_;
  }

  /** Get the destination path of a given source path and write
   * it on the given output stream.
   * \param sourcePath The source path.
   * \param out The output stream.
   * \return True if the destination path was found. */
  bool get_dest_path(const std::string &source, std::ostream &out) const;

  void save (const std::string &name, bool is_modified, const char *content) const;

private:

/** Check if a given file is directly managed by this path manager or
   * is found below any of the managed paths. If the file is found then
   * its position is stored in the given iterator.
   * \param filename The filename.
   * \param iterator The iterator to store the position of the file.
   * \return True if the file was found. */
  bool is_below(const std::string &filename, MapConstIter &iterator) const;
};

} // namespace ACBase

#endif /* ACBASE_PathManager_H */
