#ifndef H_CORAL_STORAGE
#define H_CORAL_STORAGE
// This file is part of the Coral project.
// Please read the copyright notice in the LICENSE file.

#include <coral/lib/ref_counted.h>
#include <string>
#include <coral/core/Collection.h>
#include <coral/lib/helper_uuid.h>
#include <coral/core/io/xmi_reader_common.h>
#include <coral/lib/autovector.h>

/*
 * For stat
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

/*
 * Project is a mechanism to decide from which file a (root) element
 * came from. It's set for a root element in io_xmi_load_file
 *
 * Technically we ought to be able to use this (and a hacked Element
 * class) to implement load-on-demand models. This is N/A for now, though.
 *
 */
namespace coral {
     class EXPORTFWD_coral Element;

     class EXPORT_coral Project : public ref_counted {
     public:
	  typedef autounrefmap<const coral::io::_ref*,
		  coral::Element*,
		  coral::io::lt_std_ref>
		  old_loaded_ref_info_t;
     private:
	  /*
	   * True if storage is invalid. Used by copy/paste
	   * algorithms in the modeler.
	   */
	  bool m_isinvalid;
	  /*
	   * True if the project is a user project.
           */
	  bool m_isUserProject;
	  /*
	   * The true filename of this Project
	   */
	  std::string m_filename;
	  /* this is different from the "real" filename,
	   * it shows up in XMI files.
	   */
	  std::string m_hreffilename;
	  /*
	   * XMI format used previously. Empty if undefined.
	   */
	  std::string m_xmiformat;
	  // Ordered for practical purposes
	  Sequence* m_roots;
	  /*
	   * The old xmi:uuid etc data... that we got when loading
	   */
	  old_loaded_ref_info_t m_old_loaded_ref_info;
	  /*
	   * For making sure two Project objects never point
	   * to the same file.
	   */
	  dev_t m_device;
	  ino_t m_inode;

	  CORAL_HIDDEN void __setFilename_nocheck(const std::string& f);
	  CORAL_HIDDEN void __setHrefFilename(const std::string& f);
     public:
#ifndef SWIG
	  CORAL_HIDDEN Element* findRef(const coral::io::_ref*);
	  CORAL_HIDDEN old_loaded_ref_info_t& getOldInfo() throw () {
		  return m_old_loaded_ref_info;
	  }
	  CORAL_HIDDEN void fixLoadedRef();
#endif
	  Project();
	  ~Project() throw ();
	  std::string __str__() const;
	  bool isInvalid() const throw () { return m_isinvalid; }
	  bool isUserProject() const throw () { return m_isUserProject; }
	  void setUserProject(bool b) { m_isUserProject=b;}
	  void invalidate();
	    // @deprecated
	  void setInvalid(bool b) { coral_assert(b); invalidate(); }
	  std::string getXMIFormat() const { return m_xmiformat; }
	  void setXMIFormat(const std::string& s) { m_xmiformat = s; }
	  Sequence* contents() const throw () { return m_roots; }
	  void setFilename(const std::string& f);
	  const std::string& getFilename() const throw (){ return m_filename; }
	  const std::string& getHrefFilename() const throw () {
		  return m_hreffilename;
	  }
#ifdef COMPILING_coral
	  // use element.__getProject__ or __setProject__ instead of these
	  static Project* getProject(const Element*);
	  static void setProject(const Element*, Project*);
#endif
	  /* Return a reffed Project object for a particular filename. */
	  static coral::autounref<coral::Project>
	       getProjectByFilename(const std::string& filename,
				    const std::string& relative_path = "",
				    bool* did_create = NULL);
     };

     /**
      * Returns a vector of all active Projects, unreffed
      */
     std::vector<coral::Project*> getAllProjects();

     std::string getCanonicalFilename(const std::string& input);

     /*
      * Get the search path of Coral. By default, we only
      * search the current directory (relative to some other file),
      * the startup directory, and Coral's installation path.
      *
      */
     std::vector<std::string> getCoralPath();

     void setCoralPath(std::vector<std::string> s);

}


#endif
