//
// Created by kikab on 04.06.2018.
//

#ifndef LOTRO_DAT_LIBRARY_DATFILESYSTEM_H
#define LOTRO_DAT_LIBRARY_DATFILESYSTEM_H

#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <utility>
#include <memory>

#include "../DatOperationResult.h"
#include "../SubFile.h"
#include "../SubDirectory.h"

extern "C++" {
namespace LOTRO_DAT {
    class DatFile;
    class BinaryData;
    class SubDirectory;


    /*!
     * \brief Модуль файловой системы
     * \author Gi1dor
     * \date 30.06.2018
     * Класс для работы с внутренними файлами в dat-контейнере. Позволяет найти и извлечь данные необходимого файла
     * или изменить информацию о нём
     * \warning Объекты этого класса не должны создаваться отдельно! Созданием и управлением ими занимается класс DatFile
     */

    class DatFileSystem {

    public:
        DatFileSystem() = delete;
        DatFileSystem(const DatFileSystem &other) = delete;
        DatFileSystem& operator=(const DatFileSystem &other) = delete;
        ~DatFileSystem() = default;

        explicit DatFileSystem(DatFile *datFilePtr);

        DatOperationResult<> Init();

        DatOperationResult<> InitAllDirectories();

        DatOperationResult<> InitAllFiles();

        DatOperationResult<BinaryData> GetFileData(const SubFile& file, long long int offset);

        DatOperationResult<std::shared_ptr<SubFile>> GetFile(long long file_id);

        DatOperationResult<bool> CheckCorrectSubfile(const SubFile& file);

        DatOperationResult<> UpdateFileInfo(const SubFile& file);

        int GetInitialisedFilesNumber() const;

        void PrintInformaion(FILE* file);

        DatOperationResult<> DeInit();

        DatOperationResult<> PerformOperationOnAllFiles(const std::function<void (std::shared_ptr<SubFile>&)>& function);

        DatOperationResult<> CommitDirectories();

    private:
        DatOperationResult<> InitSubFile(long long file_id);

        DatOperationResult<> InitSubDirectory(SubDirectory dir);

    private:
        DatFile *dat;
        std::set<long long> subfile_pending_update;

        std::map<long long, std::shared_ptr<SubFile> > dictionary_;

        std::unordered_set<long long> visited_subdirectories_offsets_;
        std::unordered_set<long long> visited_subfiles_ids_;

        std::set<SubDirectory, SubDirectory::SubDirectoryOffsetComparator> subdir_init_queue_;
        std::unordered_map<long long, SubFile> subfile_init_map_;
        std::set<SubFile, SubFile::SubFileOffsetComparator> subfile_init_queue_;
    public:
        long long patched_file_end;
    };
}
};

#endif //LOTRO_DAT_LIBRARY_DATFILESYSTEM_H
