//-----------------------------------------------------------
// Copyright Christian Arnault LAL-Orsay CNRS
// arnault@lal.in2p3.fr
// Modified by garonne@lal.in2p3.fr
// See the complete license in cmt_license.txt "http://www.cecill.info". 
//-----------------------------------------------------------

#ifndef __cmt_use_h__
#define __cmt_use_h__

#include "cmt_map.h"
#include "cmt_include.h"
#include "cmt_script.h"
#include "cmt_pattern.h"
#include "cmt_scope_section.h"

class Package;
class UseProjectAction;

class Use
{
// Public class methods
public:
  typedef cmt_vector<Use> UseVector;
  typedef cmt_vector<Use*> UsePtrVector;

  static Use* action (const CmtSystem::cmt_string_vector& words, Use* use);
  static Use* find (const cmt_string& package,
                    const cmt_string& version = "",
                    const cmt_string& path = "");
  static int find_index (const cmt_string& package, 
                         const cmt_string& version, 
                         const cmt_string& path);
  static Use* find_valid (const cmt_string& package);
  //static void set_auto_imports_state (int use_index,
  //cmt_vector<bool>& auto_imports_states);
  static void set_auto_imports_state (const Use::UsePtrVector& uses,
				      cmt_vector<bool>& auto_imports_states);
  static void set_auto_imports_state (const Use::UsePtrVector& uses,
				      cmt_vector<bool>& auto_imports_states,
				      cmt_map <Use*, bool>& visited);
  static Use* add (const cmt_string& path,
                   const cmt_string& package,
                   const cmt_string& version,
                   const cmt_string& version_alias,
                   const cmt_string& path_alias,
                   const cmt_string& native_version,
                   Use* context_use,
                   const State specified_auto_imports = Unspecified);
  static void move (Use* use1);
  static void reorder (Use* use1, Use* use2);
  static void select_clients (const cmt_string& package,
                              const cmt_string& version);
  static void show_all (bool skip_discarded = false, ostream& out = cout, PrintMode mode = Csh); // Csh is default for ArgParser::mode
  //  static void show_all (bool skip_discarded = false, ostream& out = cout );
  //  static void show_all (bool skip_discarded = false);
  static void show_all (const cmt_string& prefix, bool skip_discarded = false,
			ostream& out = cout, PrintMode mode = Csh); // Csh is default for ArgParser::mode
  //  static void show_all (const cmt_string& prefix, bool skip_discarded = false);

  static Use& current ();
  static const Use& const_current ();

  static UseVector& get_instances ();
  static UsePtrVector& get_ordered_uses ();

  static void clear_all ();
  static void unselect_all ();
  static void undiscard_all ();
  static void fill_macro_all (cmt_string& buffer, const cmt_string& suffix);

  static Use* create (const cmt_string& path,
                      const cmt_string& package,
                      const cmt_string& version,
                      const cmt_string& version_alias,
                      const cmt_string& path_alias,
                      const cmt_string& n_version="");

  void add_sub_use(Use* use) 
  {
      this->sub_uses.push_back (use);
  }

// Private class methods
private:

// Public instance methods
public:
  Use ();
  Use (const cmt_string& new_package,
       const cmt_string& new_version,
       const cmt_string& new_path);
  ~Use ();
  void set (const cmt_string& new_package,
            const cmt_string& new_version,
            const cmt_string& new_path,
            const cmt_string& new_version_alias = "",
            const cmt_string& new_path_alias = "");
  void author_action (const CmtSystem::cmt_string_vector& words);
  void manager_action (const CmtSystem::cmt_string_vector& words);
  bool move_to (const cmt_string& native_version="", bool curdir = false);
  //  bool move_to (const cmt_string& native_version="");
  void discard ();
  void undiscard ();
  void apply_global_patterns ();
  void set_include_path (const cmt_string& new_path);
  void get_full_path (cmt_string& s) const;
  cmt_string get_full_path () const;
  void reduce_path (cmt_string& s) const;
  void get_cmtpath_and_offset (cmt_string& cmtpath, cmt_string& offset) const;
  bool get_strategy (const cmt_string& name) const;
  inline const cmt_string& get_realpath () const { return m_realpath; }

  void fill_includes_macro (cmt_string& buffer) const;
  void fill_macro (cmt_string& buffer, const cmt_string& suffix) const;
  void fill_standard_macros (cmt_string& buffer) const;
  void build_library_links (const cmt_string& cmtinstallarea, 
			    const cmt_string& tag, 
			    const cmt_string& shlibsuffix, 
			    const cmt_string& symlinkcmd) const;
  void remove_library_links (const cmt_string& cmtinstallarea, 
			     const cmt_string& tag, 
			     const cmt_string& shlibsuffix, 
			     const cmt_string& symunlinkcmd) const;
  
  bool get_all_clients (const cmt_string& to_name);

  bool get_paths (Use* to, UsePtrVector& list);

  bool located () const;

  void change_path (const cmt_string& path);
  void set_auto_imports (State context_state, State specified_state,
			 cmt_map <Use*, bool>& visited);
  //  void set_auto_imports (State new_state);
  //void set_auto_imports_state (cmt_vector<bool>& auto_imports_states,
  //cmt_map <Use*, bool>& visited);
  void set_native_version (bool state);
  bool has_native_version () const;

  Package* get_package () const;
  const cmt_string& get_package_name () const;
  void set_package_name (const cmt_string& name);

  int get_index () const;

  void show_cycles ();

  void push_scope_section (ScopeType type);
  void pop_scope_section ();
  void close_scope_sections ();

  ScopeType get_current_scope () const;

  Project* get_project ();
  cmt_string get_info () const;
  bool is_head_version (const cmt_string& version);
  void clear ();
  void absolute_library_path (const cmt_string& libname,
			      const cmt_string& shlibsuffix, 
			      CmtSystem::cmt_string_vector& paths) const;
// Public attributes
public:

  cmt_string specified_version;  /* idem                            */
  cmt_string specified_path;     /* idem                            */
  cmt_string version_alias;
  cmt_string path_alias;
  cmt_string author;             /* idem                            */
  cmt_string manager;            /* idem                            */

  cmt_string path;               /* expanded path                   */
  cmt_string version;            /* idem                            */
  cmt_string real_path;
  cmt_string native_version;     /* idem                            */
  CmtDirStyle style;             /* May be cmt, or mgr, or none_style */
  CmtStructuringStyle structuring_style; /* with or without version directory */

  cmt_string prefix;             /* upper case copy of package      */
  bool done;                     /* true when requirements file has
                                    already been read               */
  bool discarded;                /* discarded by version strategy   */
  bool selected;                 /* used for recursive access       */
  bool m_located;
  bool m_hidden;
  ScopeType initial_scope;

  UsePtrVector sub_uses;
  cmt_vector<ScopeType> sub_use_scopes;
  cmt_vector<State> sub_use_auto_imports;

 int m_index;  // Position within the ordered list of uses
  
  State auto_imports;

  Include::IncludeVector includes;
  cmt_string include_path;
  Script::ScriptVector scripts;
  ApplyPattern::ApplyPatternVector apply_patterns;
  IgnorePattern::IgnorePatternVector ignore_patterns;

// Private methods
private:
  //  void clear ();
  int reach_package (const cmt_string& current_path, const cmt_string& n_version="");
  void select ();
  void unselect ();
  bool is_selected ();
  bool is_client (const cmt_string& package,
                  const cmt_string& version);
  void show_sub_uses (cmt_map <Use*, bool>& visited,
		      const cmt_string& request, State specified_state,
		      bool skip_discarded = false, ostream& out = cout);
  //  void show_sub_uses (const cmt_string& request, bool skip_discarded = false);
  bool select_alternate ();
  Use* get_selected_version ();
  Use* set_selected_version (Use* selected_use);

  static bool need_new (const cmt_string& path,
                        const cmt_string& package,
                        const cmt_string& version,
                        const cmt_string& n_version,
                        Use** old_use,
			            Use* context_use);

  bool get_all_clients (Use* to, 
			const cmt_string& result, 
			cmt_map <cmt_string, Use*>& all_clients, 
			cmt_map <cmt_string, Use*>& all_clients_ok);

// Private attributes
private:

  Package* m_package;
  //cmt_string m_package_name; /* directly read from requirements */

  bool m_has_native_version;


  cmt_vector<ScopeSection> scope_sections;

  CmtSystem::cmt_string_vector alternate_versions;
  CmtSystem::cmt_string_vector alternate_paths;
  cmt_vector<bool> alternate_is_head_versions;

  CmtSystem::cmt_string_vector requests;

  cmt_regexp m_head_version; 
  cmt_string m_realpath; /* canonicalized absolute real_path */

  friend class UseProjectAction;
};

class Package
{
public:

  typedef cmt_map<cmt_string, Package> PackageMap;
  typedef cmt_vector<Package> PackageVector;

  static Package* find (const cmt_string& name);
  static Package* add (const cmt_string& name);

  static PackageVector& packages ();
  static PackageMap& package_map ();

  static void clear_all ();

  static bool get_version (cmt_string& version, const cmt_string& path = ".");
  static const cmt_string& get_version_file_name ();
  static bool get_name (cmt_string& name, const cmt_string& path = ".");

public:

  Package ();
  ~Package ();

  const cmt_string& get_name () const;
  void add_use (Use* use);
  void remove_use (Use* use);
  Use::UsePtrVector& get_uses ();

  bool is_cmt ();

private:
  bool m_is_cmt;

  cmt_string m_name;
  Use::UsePtrVector m_uses;
};

#endif
