/*
 * Copyright © 2020-2026 Pierrick Caillon <pierrick.caillon+zipdirfs@megami.fr>
 */
#include "ZipDirFs/Components/ZipFileChanged.h"
#include "ZipDirFs/Utilities/FileSystem.h"
#include "ZipDirFs/Zip/Factory.h"
#include <filesystem>

namespace ZipDirFs::Components
{
	namespace fs = std::filesystem;
	using namespace ZipDirFs::Zip;
	using Utilities::FileSystem;

	namespace
	{
		std::time_t getTimeReal(const fs::path& p, const std::string& i,
			std::bitset<2>& state, ZipFileChanged::FileTime& pathChanged);
	}

	ZipFileChanged::ZipFileChanged(const fs::path& path, const std::string& item) :
		path(path), item(item), lastItemChanged{0}, state{0}
	{
	}

	bool ZipFileChanged::operator()()
	{
		FileTime pathChanged;
		const FileTime itemChanged{getTimeReal(path, item, state, pathChanged)};
		bool result = pathChanged != lastPathChanged;
		lastPathChanged = pathChanged;
		if (state[1])
		{
			result = result || itemChanged != lastItemChanged;
			lastItemChanged = itemChanged;
		}
		return result;
	}

	ZipFileChanged::operator FileTime() const
	{
		return lastItemChanged;
	}

	auto ZipFileChanged::getTime(const fs::path& p, const std::string& i) -> FileTime
	{
		std::bitset<2> state{0};
		FileTime pathChanged;
		FileTime itemChanged{getTimeReal(p, i, state, pathChanged)};
		return state[1] ? itemChanged : pathChanged;
	}

	namespace
	{
		std::time_t getTimeReal(const fs::path& p, const std::string& i,
			std::bitset<2>& state, ZipFileChanged::FileTime& pathChanged)
		{
			std::shared_ptr<Archive> archive{nullptr};
			std::shared_ptr<Entry> entry{nullptr};
			pathChanged = FileSystem::last_write_time(p);
			archive = Factory::getInstance().get(p);
			if (!state[0])
			{
				state[0] = true;
				state[1] = (entry = archive->open(i)) != nullptr;
			}
			else if (state[1])
			{
				entry = archive->open(i);
			}
			return state[1] && entry != nullptr ? entry->stat().getChanged() : 0;
		}
	} // namespace
} // namespace ZipDirFs::Components
