/********************************************************************
* CONFIDENTIAL - All source code is the propriety and confidential  *
* information of David Sorber.                                      *
*                                                                   *
* Copyright 2024 David Sorber                                       *
* Unpublished -- all rights reserved under the copyright laws       *
* of the United States.                                             *
********************************************************************/

#ifndef __COPYTOOL_COPYMANAGER_H_
#define __COPYTOOL_COPYMANAGER_H_

#include <atomic>
#include <cstdint>
#include <filesystem>
#include <map>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

#include "CopyManagerOptions.h"
#include "ProtectedQueue.h"

namespace sfs = std::filesystem;


namespace DBS
{

class CopyManager
{
public:

    // Maximum "count" size per sendfile() documentation
    static inline size_t MAX_COPY_SIZE{0x7ffff000};

    static inline const sfs::directory_entry ENTRY_TERMINATOR{};

    CopyManager() = delete;

    CopyManager(CopyManagerOptions& options);

    ~CopyManager();

    /**
     * Execute the copy operation described by the CopyManagerOptions instance.
     * @return
     */
    void run();

    inline void terminate()
    {
        // TODO: something else???
        m_terminate = true;
    }

    /**
     * Wait for the main thread to complete. Should be called after run().
     * @return
     */
    int waitForComplete();

    inline bool isRunning() const
    {
        return m_running;
    }

    inline bool iterationError() const
    {
        return m_iterationError;
    }

    inline uint64_t getTotalEntries()
    {
        return m_totalEntries;
    }

    inline uint64_t getInvalidEntries()
    {
        return m_invalidEntries;
    }

    inline uint64_t getProcessedEntries()
    {
        return m_processedEntries;
    }

    //--- Setters -------------------------------------------------------------
    inline void incTotalEntries()
    {
        ++m_totalEntries;
    }

    inline void incInvalidEntries()
    {
        ++m_invalidEntries;
    }

    inline void incProcessedEntries()
    {
        ++m_processedEntries;
    }

private:

    /**
     * Body of the main thread spawned when run() is called.
     */
    void mainThreadBody();

    /**
     * Body of thread that does the actual copying and creating of directories.
     */
    void copyThreadBody();

    /**
     * Body of thread that counts directory entries in the source path.
     */
    void counterThreadBody();


    CopyManagerOptions& r_options;

    ProtectedQueue<sfs::directory_entry> m_entryQueue;
    std::atomic_bool m_terminate;
    std::atomic_bool m_running;
    std::atomic_bool m_iterationError;

    std::thread* p_mainThread;
    std::vector<std::thread*> m_copyThreads;
    std::thread* p_counterThread;

    std::mutex m_mutex;
    std::atomic_uint64_t m_totalEntries;
    std::atomic_uint64_t m_invalidEntries;
    std::atomic_uint64_t m_processedEntries;

};

} // namespace DBS


#endif //__COPYTOOL_COPYMANAGER_H_
