/*
 * Copyright © 2020-2026 Pierrick Caillon <pierrick.caillon+zipdirfs@megami.fr>
 */
#ifndef ZIPDIRFS_COMPONENTS_NATIVEFACTORY_H
#define ZIPDIRFS_COMPONENTS_NATIVEFACTORY_H

#include "StateReporter.h"
#include "ZipDirFs/Containers/Helpers/Factory.h"
#include "ZipDirFs/Utilities/FileSystem.h"
#include "ZipDirFs/Zip/Exception.h"
#include "ZipDirFs/Zip/Factory.h"
#include <filesystem>

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

	/**
	 * @brief A @link ZipDirFs::Containers::Helpers::Factory Factory @endlink for creating entries
	 * under a real directory
	 * @authors Pierrick Caillon <pierrick.caillon+zipdirfs@megami.fr>
	 * @tparam Directory Implementation class for real directory.
	 * @tparam Symlink Implementation class for symlink to real file.
	 * @tparam Zip Implementation class for zip directory representing the archive root.
	 */
	template <class Directory, class Symlink, class Zip>
	class NativeFactory : public Containers::Helpers::Factory
	{
	public:
		NativeFactory(const fs::path& path) : path(path) {}
		mapped_type create(const key_type& name) override
		{
			auto fullPath = path / name;
			fs::file_status status = FileSystem::status(fullPath);
			if (fs::is_directory(status))
			{
				return reportWrap(new Directory(fullPath));
			}
			if (fs::is_regular_file(status))
			{
				mapped_type zip = nullptr;
				try
				{
					auto const archive{ZipFactory::getInstance().get(fullPath)};
					auto item{archive->commonBase()};
					zip = !item.empty() ? static_cast<mapped_type>(new Zip(fullPath, item)) :
											static_cast<mapped_type>(new Zip(fullPath));
				}
				catch (Exception&)
				{
				}
				return reportWrap(zip != nullptr ? zip : static_cast<mapped_type>(new Symlink(fullPath)));
			}
			if (fs::is_symlink(status))
			{
				return reportWrap(new Symlink(fullPath));
			}
			return nullptr;
		}
		void destroy(const mapped_type& item) override { delete item; }

	protected:
		const fs::path& path;
	};

} // namespace ZipDirFs::Components

#endif // ZIPDIRFS_COMPONENTS_NATIVEFACTORY_H
