/* dircompareop.h
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2017-2023 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 DIRCOMPAREOP_H
#define DIRCOMPAREOP_H

#include "wdefines.h"
#include "functionproto.h"
#include "nwc_dir.hh"
#include <vector>
#ifdef HAVE_OPENSSL_EVP_SHA256
#  include <openssl/evp.h>
#  include <openssl/sha.h>
#elif defined(HAVE_OPENSSL_SHA256)
#  include <openssl/sha.h>
#endif

class DirCompareWin;

class DirCompareOp : public FunctionProto
{
public:
    DirCompareOp();
    ~DirCompareOp();
    DirCompareOp( const DirCompareOp &other );
    DirCompareOp &operator=( const DirCompareOp &other );
    
    DirCompareOp *duplicate() const override;
    bool isName( const char * ) override;
    const char *getName() override;

    int run( std::shared_ptr< WPUContext > wpu, ActionMessage* ) override;

    const char *getDescription() override;

    static const char *name;
private:
    enum compare_mode {
        COMPARE_FILENAME,
        COMPARE_FILENAME_FILESIZE,
        COMPARE_FILENAME_FILESIZE_MDATE,
        COMPARE_FILENAME_CONTENT,
        COMPARE_FILESIZE,
        COMPARE_CHECKSUM
    };

    enum compare_mode m_compare_mode;

    enum compare_key {
        FILENAME,
        FILENAME_IGNORE_CASE,
        FILESIZE,
        FILESIZE_CHECKSUM
    };

    enum result_mode {
        CHANGE_SELECTION_STATE,
        SHOW_AS_VIRTUAL_DIR
    };

    enum result_mode m_result_mode;

    bool m_ignore_file_name_case = false;

    loff_t m_file_size_limit = 0;

    DirCompareWin *m_progress_win;

    bool m_stop;

    static int s_vdir_number;

    class compare_element {
    public:
        compare_element( NWC::FSEntry *entry, size_t orig_pos ) :
            entry( entry ),
            orig_pos( orig_pos )
        {
#if defined(HAVE_OPENSSL_EVP_SHA256) || defined(HAVE_OPENSSL_SHA256)
            memset( chksum, 0, sizeof( chksum ) );
#endif
        }
        NWC::FSEntry *entry = NULL;
        size_t orig_pos = 0;
        std::string basename;
#if defined(HAVE_OPENSSL_EVP_SHA256) || defined(HAVE_OPENSSL_SHA256)
        unsigned char chksum[SHA256_DIGEST_LENGTH];
#endif
        bool use_checksum =  false;
    };

    int doConfigure();

    int compareDirs( std::shared_ptr< NWC::Dir > my_dir,
                     std::shared_ptr< NWC::Dir > other_dir,
                     std::vector< bool > *my_equal,
                     std::vector< bool > *other_equal,
                     std::unique_ptr< NWC::Dir > &my_res_vdir,
                     std::unique_ptr< NWC::Dir > &other_res_vdir );
    int compareEntry( NWC::FSEntry *my_entry,
                      NWC::FSEntry *other_entry,
                      std::unique_ptr< NWC::Dir > &my_res_vdir,
                      std::unique_ptr< NWC::Dir > &other_res_vdir,
                      enum compare_key cmp_key );
    int compareFile( NWC::FSEntry *my_entry,
                     NWC::FSEntry *other_entry );
    int calc_checksum( compare_element &element ) const;

    static int key_compare( const compare_element &lhs,
                            const compare_element &rhs,
                            enum compare_key key );
};

#endif
