#ifndef DirectoryList_hpp
#define DirectoryList_hpp

#include "UnixDirectoryLister.hpp"
#include "UnixFile.hpp"
#include <vector>

using namespace std;

// define CompareFunction_t as type: pointer to comparison functions
// (the strict weak ordering between two UnixFile objects)
typedef  bool (*CompareFunction_t) (UnixFile* f1, UnixFile* f2);

/**
  This class' instances represent a directory with its contents (entries).
  The directory entries are stored as UnixFile objects in a list with particular order.
  Internally, the "vector" template from the STL is used to implement the list.

  An instance is constructed by giving the directory representing it.
  A file (UnixFile object) may be inserted into the list via insert()
  Alternatively, the instance can be told to read its contents itself 
  with a call to list(). These two ways to fill the list should not be mixed.
  
  Currently, the only way to read the entries out of the list is to access the
  list directly.

  By default, the file's order is just like they appear on the filesystem or have 
  been inserted. The order can be changed.
  
  An instance may be in one of three states: 
  1. Directory does not exist.
  2. Directory exists but is not readable.
  3. Directory exists and is readable, the contained files can be queried.
  
  
  
  @author Michael Weers
  @version 0.7.2 1999-02-20
 */
class DirectoryList {
  public:
                 typedef vector<UnixFile*>  FileList_t;
                 
                 /** The list with the directories' entries */
                 vector<UnixFile*> file_list;
                 
  protected:
                 /** Allow doing directory listing via list() */
                 bool allow_listing;
                 /** False if the directory cannot be read. Readability is
                     is assumed as long as the opposite is not proven. */
                 bool readable;
   
                 UnixFile* dir;
                 
                 CompareFunction_t compareFunction;
  public:               
                 bool reversed_order;
  protected:               
                 // Statistics
                 long int allFilesCount, regFilesCount;
                 long long int regFilesSize;
   
  public:           
                 /** Initializes an (initially empty) instance
		  *  @param dir The directory the instance will represent.
		  *         The UnixFile object is adopted!
		  */
                 DirectoryList( UnixFile* dir, bool= true);   // adopts dir
		 
                 ~DirectoryList();

                 UnixFile& getDirectory();       // read access only!
                 
                 /** queries if dir exists */
                 bool directoryExists()  const {  return dir->exists(); }
                 /** dir exists and is readable */
                 bool isReadable()  const { return readable; }
                 /** no files in listing. dir may or may not exist */
                 bool isEmpty()  const { return file_list.size() == 0; }

                 /** Returns the overall size of all regular files */
                 long long int  getRegFilesSize()  const { return regFilesSize;}
                 /** Returns the number of regular files */
                 long int  getRegFilesCount()  const { return regFilesCount;}
                 /** Returns the total number of files (counting every type) */
                 long int  getAllFilesCount()  const { return allFilesCount; }

                 /** Checks if the given file is already in the DirectoryList */
                 vector<UnixFile*>::iterator  find( UnixFile* f);
                 
                 /** insert a file into the list manually. Non-existing files
                     will be ignored. */
                 void insert( UnixFile* f);      // adopts f
                 /** Inserts the given file, but assures it is contained 
                     in the list only once. */
                 void insert_unique( UnixFile* f);
                 
                 /** Empties the list (removes all contained files) */
                 void clear();

                 void syncStatistics();

		 /** List the files and insert them into the list.
                     This method should be only called for an empty list
                     and no files should be inserted afterwards manually. 
                     @param with_hidden_files  determines wether hidden
                     files are to be listed (true) or ignored (false)*/
                 void list( bool with_hidden_files= false, bool with_special_dirs= false);

                 /** Sets the comparison function to be used for ordering the list*/
                 void setCompareFunction( CompareFunction_t f);

                 /** Enforces ordering on the list */
                 void ReOrder();
};

// The file order criteria...

bool NamePrecedence(  UnixFile* f1,  UnixFile* f2);
bool ModDatePrecedence( UnixFile* f1,  UnixFile* f2);
bool AccessDatePrecedence( UnixFile* f1, UnixFile* f2);
bool StatusChangeDatePrecedence( UnixFile* f1, UnixFile* f2);
bool FileSizePrecedence( UnixFile* f1,  UnixFile* f2);
bool ExtensionPrecedence( UnixFile* f1,  UnixFile* f2);

/*
class APrecedence {
  public:
    virtual bool operator() ( UnixFile* f1, UnixFile* f2)=0;
    virtual ~APrecedence();
  protected: 
    APrecedence( APrecedence* next);
    APrecedence* m_next;
};

class DirectoriesFirst: public APrecedence  {
  public:
    DirectoriesFirst( APrecedence* = NULL);
    bool operator() ( UnixFile* f1, UnixFile* f2);
};

class NamesAlphabethical: public APrecedence {
  public:
    NamesAlphabethical( APrecedence* = NULL);
    bool operator() ( UnixFile* f1, UnixFile* f2);
};
*/

class Last {
  public:
    inline bool operator() ( UnixFile* f1, UnixFile* f2) {
      return false;
    }
};



template<typename Next>
class DirectoriesFirst {
    Next m_next;
  public:
    bool operator() ( UnixFile* f1, UnixFile* f2);
};

template<typename Next>
class ByName {
    Next m_next;
  public:
    bool operator() ( UnixFile* f1, UnixFile* f2);
};

#endif

