#ifndef UnixFile_hpp
#define UnixFile_hpp


#include <sys/stat.h>
#include <unistd.h>
//#include <sys/types.h>    // neccessary for mode_t when using the glibc (?)

#include <string>

#include "File.hpp"
#include "Date.hpp"

using namespace std;

// Last changed: 2001-06-07
 
/**
  @short Represents Unix' file mode (access rights).
  For now, this class is used internally in class UnixFile only.
  */
class UnixFileMode {
  protected:      mode_t  filemode;             // Typ importiert!
  public:         
                  UnixFileMode() { }
                  UnixFileMode( mode_t fm);
                  string toString()  const;
                  mode_t getMode()  const { return filemode; }
};


/**
 *  @short Represents files/directories on Unix filesystems
 *
 *  This class' instances represent files that appear on an
 *  Unix filesystem, including all types like
 *  regular files, directories, symbolic links and
 *  other 'special' files.
 *  The file represented may or may not exist on the filesystem.
 *
 *  Instances are created by giving the file's access path.
 *  A special mode may be used: "AS_IS" for stating (symbolic) links 
 *  as they are (default) or "DEREF" for automatically 'dereferencing' a symbolic link.
 *  The file's existence and properties may be queried.
 *
 *  Most proporties are defined only on existing files. 
 *  Only the following properties may be queried in any case:
 *  File name, path, existance. 
 *  The actual meaning of some properties may depend on the operating system and/or the actual file type.
 *
 *  (Almost) all properties are cached by the respective instance.
 *  The properties are read initially on creation 
 *  and are updated on calls to sync().
 *
 *  @author Michael Weers
 *  @version 0.8.5
 */
class UnixFile : public File {
                                            // class constants
  public: 
    static const  short int  AS_IS= 0, DEREF= 1;

    static const  char REGFILE='-', DIRECTORY='d', SYMLINK='l',
                       BLOCK_DEVICE='b', CHAR_DEVICE='c',
                       PIPE='p', SOCKET='s';

    /** The path separator */
    static const  char separator= '/';

    /** enumeration type for the internal state's values */
    enum State { NOT_EXISTING, ACCESS_DENIED, NORMAL};  
    
                                            // instance attributes
                  State state;
  protected:
                                    // internal mode (AS_IS or DEREF) 
                  short int  stat_mode;
                                        // file info attributes
                  string    fullname;                                            
                  char      type;
                  off_t     size;

                  Date      status_change_time,
                            access_time,
                            modification_time;

                  int       owner,  group;

                  UnixFileMode fileMode;

                  /** Points to an object representing the linked-to file, if
                  if the instance represents a symbolic link, NULL otherwise. <P>
                  Important! That object still has the name and path from the 
                  the instance, because it was created with UnixFile(...,DEREF)
                  */
                  UnixFile* linkedFile;  

                                        // Constructors, assignment operator
  public:
                  /** Initializes the instance with the given path/filename.
                    @param full_ file name and/or path
                    @param mode  List mode
                    @param force_canonical  Constuct the instance with the
                      canonical and absolute path for the given path
                   */
                  UnixFile( const string& full_, 
                            const short int  mode= AS_IS,
                            const bool force_canonical= false );
                                
                  UnixFile( const UnixFile&);
                  UnixFile& operator= (const UnixFile&);
            
         virtual  ~UnixFile();


                                        // high level query functions

                  /** Queries if the file behaves as a container
                      for other files. Primarily this is true for direcories. 
                      On Unix filesystems,
                      this function also returns true if file is a symbolic
                      link to a direcory. */
         virtual  bool isNavigable()  const;      // overwrite        
         
                  /** Queries if the file is a 'navigable' and can be seen 
		      as a "sub-navigable". Basically, this is
		      false for a symbolic link to one of its parent
		      directories.
		      It is also false for the special directories '.' and '..'.
		      It prevents from infinite recursion when doing recursive
		      walks through the directory structure*/
		  // Does not mean that link always points to a subdirectoy!!!
                  bool isSubNavigable()  const;

                  bool isSpecialDirectory()  const {
                    string name= getName();
                    return name=="." || name=="..";
                  }


                                        // general query functions

                  /** Queries the file's existence. 
                      @return  true if file exists (and information about it
                      could be obtained).
                  */
         virtual  bool exists()  const;           // overwrite
	 
	          /** Returns the file type. The result is one of the file type constants. */
                  char getType()  const { return type; }

	 /** check for 'file equality' (same name and path) */
         virtual  bool equals( UnixFile& f)  const;
	 
	          /** Checks if the file specification was given as an absolute path */
	          bool isAbsolute()  const;

         virtual  bool isDirectory()  const;      // overwrite
         virtual  bool isFile()  const;           // overwrite
         virtual  bool isLink()  const;
                  bool isBrokenLink()  const;
         
                  /** Returns if a regular file is an executable (applies on
                      regular files only) */
                  bool isExecutable()  const;

                  /** Returns the file's name (without path) */
         virtual  string getName()  const;          // overwrite

                  /** Returns the file's access path (without its own name).
                    The result is generally a pathname of the directory the file is
                    contained in.
                    Precisely, the result is access path part of the path specificaton
                    the object was created from, and if that was given as a relative path
                    the result is also a relative path. <P>
                    If the file has no path specification (the file is
                    contained in the current direcory), '.' is returned.
                    The parent of the root directory is '/' (by definition).
                    The result is never an empty string. */
         virtual  string getParent()  const;          // overwrite

                  /** Returns the file's complete path with name */
         virtual  string getPath()  const;      // overwrite
                  /** Returns the file's complete path with name. Deprecated. */
         virtual  string getFullName()  const { return fullname; }
         
                  /** Returns the absolute path for the file. */
                  string getAbsolutePath()  const;

                  /** Returns the canonical absolute path for the file */
                  string getCanonicalPath()  const;
                  
                  /** Returns the file name extension or an empty string if the file has none */
         virtual  string getNameExtension()  const;

                  /** Returns the link name for symbolic links, as it is stored on the filesystem.*/
                  string getLinkName()  const;

                  off_t getSize()  const;

                  /** Returns the file's mode (as an integer value)*/
                  mode_t getMode()  const { return fileMode.getMode(); }

                  string getAttributeString()  const;
                  
                  int getOwnerID()  const { return owner; }

                  /** Return the owner's user name (login). An empty string indicates that
                  there is no name corresponding to the user ID. 
                  @param generate If true and no name is present, generate one. 
                  */
                  string getOwner( bool = false)  const;

                  /** Return the owner real name (full name) or empty string*/
                  string getOwnerName()  const;
                  
                  int getGroupID()  const { return group; }
                  string getGroup( bool = false)  const;
                  
                  const Date&  getLastModified()  const { return modification_time;}
                  const Date&  getLastAccessed()  const { return access_time; }
                  const Date&  getLastStatusChanged()  const { return status_change_time; }

                                        // control actions
                  void sync();
                                        // static member functions
     static       string getAbsolutePath( const string& path);
     static       string getCanonicalPath( string path); 
     
                  /** Returns an absolute path for the file that this instance links to directly. */
     private:
                  string getAbsoluteDirectLinkPath()  const;
}; // class UnixFile

#endif
