/* nwc_dir.hh
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2006-2017 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef NWC_DIR_HH
#define NWC_DIR_HH

#include "wdefines.h"

#include "nwc_fsentry.hh"
#include "aguix/refcount.hh"

#include <list>
#include <vector>
#include <memory>
#include <functional>

namespace NWC
{
  
  class File;
  class DirWalkCallBack;

  class Dir : public FSEntry
  {
  public:
    Dir( const std::string &fullname, bool follow_symlinks = false );
    Dir( const FSEntry &other, bool follow_symlinks = false );
    ~Dir();
    Dir( const Dir &other );
    Dir &operator=( const Dir &other );

    /**
     * readDir reads the content of the directory if it exists. In that case all previous entries
     * are removed
     * After reading the directory (or if the directory is not a real directory) the
     * sub directories are read if recursive == true */
    int readDir( bool recursive = true );

    typedef enum { NORMAL, RECURSIVE, RECURSIVE_DEMAND } walk_t;

    class WalkControlObj
    {
    public:
      WalkControlObj();
      ~WalkControlObj();
    
      typedef enum { NORMAL, ABORT, SKIP } mode_t;
      void setMode( mode_t newmode );
      mode_t getMode() const;
    private:
      mode_t _walk_mode;
    };

    WalkControlObj walk( DirWalkCallBack &dirit, walk_t walk_mode = NORMAL );
    int add( std::unique_ptr<FSEntry> ent );
    int add( const FSEntry &ent );
    int removeFromList( const std::string &name );
    int removeFromList( const std::string &name, int pos );

    //these two function could be merged into a single one
    virtual File  *createFile( const FSEntry &entry );
    virtual Dir   *createDir( const FSEntry &entry );
    virtual int    clearLists();
    virtual bool   isRealDir() const;
    virtual bool   isVirtual() const;
    
    FSEntry       *clone() const;

    size_t size() const;
    bool empty() const;

    virtual void setFollowSymlinks( bool nv );
    virtual bool getFollowSymlinks() const;
      virtual std::list< std::string> getFullnamesOfSubentries() const;

      virtual FSEntry *getEntryAtPos( size_t pos );

      virtual loff_t getBytesInDir() const;
      virtual void setBytesInDir( loff_t bytes );

      virtual int changeBasenameOfEntry( const std::string &newbasename,
                                         int pos,
                                         bool keep_dirtype = false );
      virtual void sort( std::function< bool( const FSEntry &lhs,
                                              const FSEntry &rhs ) > compare_cb );
  protected:
    virtual void handleDirEntry( const std::string &filename );
    int addEntry( const FSEntry &entry );

      virtual void walkHandleEntry( FSEntry *entry, DirWalkCallBack &dircb,
                                    WalkControlObj &cobj, const walk_t walk_mode );
  private:
    std::vector<FSEntry*> _subentries;

    typedef enum { VIRTUAL, FS_DIR, FS_DIR_READ } dir_t;
    dir_t _dirtype;

    bool _follow_symlinks;

      loff_t m_bytes_in_dir;

    void makeVirtual();
  };

  class DirWalkCallBack
  {
  public:
    DirWalkCallBack() {}
    virtual ~DirWalkCallBack() {}

      virtual int visit( File &file, Dir::WalkControlObj &cobj ) { return 0; }
      virtual int visitEnterDir( Dir &dir, Dir::WalkControlObj &cobj ) { return 0; }
      virtual int visitLeaveDir( Dir &dir, Dir::WalkControlObj &cobj ) { return 0; }
      virtual int prepareDirWalk( const Dir &dir, Dir::WalkControlObj &cobj,
                                  std::list< RefCount< FSEntry > > &return_add_entries,
                                  std::list< RefCount< FSEntry > > &return_skip_entries ) { return 0; }
  };

}

#endif
