#pragma once

#include <tl/vector.h>
#include "tl/string.h"
#include "tl/path_system.h"
#include "tl/rel_path.h"
#include "tl/abs_path.h"

namespace fs
{

// custom windows path system
template<typename parse_separators, typename format_separator>
struct WindowsSystemCustom : public tl::detail::path_system::base_path_system<parse_separators, format_separator>
{
	template<typename T>
	static T format_abs(tl::span<const tl::string> members);
	static void parse_abs(tl::vector<tl::string>& o_elements, const char* path, size_t size);
	static bool validate_abs_path(tl::span<const tl::string> members);
	static bool match(const char* path, size_t size);
};
TL_DECLARE_STRING_VECTOR(WindowsParseSeparators, "\\", "/");
TL_DECLARE_STRING_LITERAL(WindowsFormatSeparator, "\\");
using WindowsSystem = WindowsSystemCustom<WindowsParseSeparators, WindowsFormatSeparator>;

// posix path system
TL_DECLARE_STRING_LITERAL(PosixRootTag, "/");
TL_DECLARE_STRING_VECTOR(PosixParseSeparators, "/");
TL_DECLARE_STRING_LITERAL(PosixFormatSeparator, "/");
using PosixSystem = tl::simple_path_system<PosixRootTag, PosixParseSeparators, PosixFormatSeparator>;

// mac path system
TL_DECLARE_STRING_LITERAL(UncRootTag, "\\\\");
TL_DECLARE_STRING_VECTOR(UncParseSeparators, "\\", "/");
TL_DECLARE_STRING_LITERAL(UncFormatSeparator, "\\");
using UncSystem = tl::simple_path_system<UncRootTag, UncParseSeparators, UncFormatSeparator>;

using AbsPath = tl::abs_path<tl::path_systems<WindowsSystem, PosixSystem, UncSystem>>;
using AbsPathView = AbsPath::path_view_type;
using RelPath = AbsPath::rel_path_type;
using RelPathView = RelPath::path_view_type;

}

#include "fs/AbsPath.inl"

template <>
struct std::formatter<fs::RelPath>
{
	constexpr auto parse(format_parse_context& ctx) noexcept { return ctx.begin(); }
	auto format(const fs::RelPath& p, std::format_context& ctx) const
	{
		return format_to(ctx.out(), "{}", p.str<fs::PosixSystem>());
	}
};
