/* dmcacheentrynwc.hh
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2012-2024 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 DMCACHEENTRYNWC_HH
#define DMCACHEENTRYNWC_HH

#include "wdefines.h"
#include "nwc_dir.hh"
#include "aguix/refcount.hh"
#include <functional>
#include <future>

class DirBookmarksSettings;
class DirFilterSettings;
class DirSortSettings;
class NWCEntrySelectionState;

class DMCacheEntryNWC {
public:
    DMCacheEntryNWC( std::unique_ptr< NWC::Dir > dir,
                     DirFilterSettings *dir_filter_sets,
                     DirSortSettings *dir_sort_sets,
                     DirBookmarksSettings *dir_bookmarks_sets,
                     std::function< void () > begin_check_cb,
                     std::function< void () > end_check_cb );
    ~DMCacheEntryNWC();
    DMCacheEntryNWC( const DMCacheEntryNWC &other ) = delete;
    DMCacheEntryNWC &operator=( const DMCacheEntryNWC &other ) = delete;

    void setDir( std::unique_ptr< NWC::Dir > dir );

    enum {
        RESET_FILETYPE_FOR_CHANGED_SIZE_OF_UNKNOWN = 1 << 0
    };
    
    void reload( int flags = 0 );

    const NWCEntrySelectionState *getEntry( int pos );
    std::pair< const NWCEntrySelectionState *, int > getEntry( const std::string &fullname, int pos, bool also_hidden );
    void modifyEntry( int pos,
                      std::function< void( NWCEntrySelectionState & ) > mod_function );

    size_t getSize();
    bool getUse( int pos );

    int getActiveEntryPos() const;
    void setActiveEntryPos( int pos );

    void updateView( bool force );

    long getNrOfFiles( bool selected = false ) const;
    loff_t getSizeOfFiles( bool selected = false ) const;
    long getNrOfDirs( bool selected = false ) const;
    loff_t getSizeOfDirs( bool selected = false ) const;
    long getNrOfHiddenFiles() const;
    long getNrOfHiddenDirs() const;

    const std::string &getCommonPrefix();
    std::string getNameOfDir() const;
    std::string getBasicDirname();
    bool isRealDir() const;
    std::string getVisibleName();

    void setXOffset( int xoffset );
    int getXOffset();

    void setYOffset( int yoffset );
    int getYOffset();

    void resetFiletypeCheckState();
    int updateNextEntryForFiletypeCheck();
    int getEntryForFiletypeCheck();

    int getNumberOfUncheckedEntries() const;

    struct filetype_check {
        filetype_check() : next_entry_for_filetype_check( UNKNOWN ) {}

        static const int UNKNOWN = -1;
        static const int NO_ENTRY = -2;

        int next_entry_for_filetype_check;
    };

    void resetFiletypesAndColors();
    void checkForDCD();
    bool getDontCheckContent() const;

    void resetDirSizes();

    const NWC::Dir *getNWCDir() const;

    typedef enum {
        MOD_UNSET,
        MOD_REMOVAL,
        MOD_INSERTION,
        MOD_RENAMING
    } modification_mode_t;

    int beginModification( modification_mode_t mode );

    int removeEntry( int pos );
    int insertEntry( const std::string &fullname );
    int changeBasenameOfEntry( const std::string &baseame,
                               int pos );

    int endModification();
    int updateActiveForRemoval( int pos );

    int temporarilyHideEntry( int pos );

    enum custom_directory_info_state {
        CDI_NOT_USED,
        CDI_CALCULATING,
        CDI_RESULT_AVAILABLE,
        CDI_DONE
    };

    const std::string &getCustomDirectoryInfo();
    void setCustomDirectoryInfoFuture( std::future< std::string > f );
    bool customDirectoryInfoPending();
    custom_directory_info_state customDirectoryInfoState() const;
private:
    struct active_entry {
        active_entry() : view_element( -1 ),
                         dir_entry_id( -1 ) {}

        int view_element; // the number in the m_entries vector
        int dir_entry_id; // the ID in m_dir (stored only to find entry back after resort)
    } m_active_entry;

    void setupEntries();
    void recalcStats();
    void recalcCommonPrefix();
    void applyOldSettings( std::vector< NWCEntrySelectionState > &new_entries,
                           std::vector< NWCEntrySelectionState > &old_entries,
                           active_entry &new_active_entry,
                           active_entry &old_active_entry,
                           int flags );
    void changeEntryInStats( const NWCEntrySelectionState &es,
                             bool remove );

    RefCount< NWC::Dir > m_dir;
    DirFilterSettings *m_dir_filter_sets;
    DirSortSettings *m_dir_sort_sets;
    DirBookmarksSettings *m_dir_bookmarks_sets;
    int m_filter_serial_nr, m_sort_serial_nr, m_bookmarks_serial_nr;

    std::vector< NWCEntrySelectionState > m_entries;

    struct entry_counter {
        entry_counter() : files( 0 ),
                          files_selected( 0 ),
                          dirs( 0 ),
                          dirs_selected( 0 ),
                          files_bytes( 0 ),
                          files_bytes_selected( 0 ),
                          dirs_bytes( 0 ),
                          dirs_bytes_selected( 0 ),
                          hidden_files( 0 ),
                          hidden_dirs( 0 )
        {}

        long files, files_selected;
        long dirs, dirs_selected;
        loff_t files_bytes, files_bytes_selected;
        loff_t dirs_bytes, dirs_bytes_selected;
        long hidden_files, hidden_dirs;
    } m_files_dirs;

    struct common_prefix {
        common_prefix() : calculated( false )
        {}

        std::string prefix_string;
        bool calculated;
    } m_common_path_prefix;

    int m_x_offset, m_y_offset;

    struct filetype_check m_filetype_check_state;

    int m_unchecked_entries;

    bool m_dont_check_content;

    modification_mode_t m_modification_mode;

    std::string m_custom_directory_info;
    std::future< std::string > m_custom_directory_info_future;
    custom_directory_info_state m_custom_directory_info_state = CDI_NOT_USED;

    std::function< void () > m_begin_check_cb;
    std::function< void () > m_end_check_cb;
};

#endif
