#ifdef WIN32
#	include <shlobj.h>
#elif defined(MACOSX)
#	include "sys/osx/filesystem.h"
#elif defined(__linux__)
#	include <pwd.h>
#	include <sys/types.h>
#endif

#ifdef WIN32
#	define DELIM "\\"
#else
#	define DELIM "/"
#	include <errno.h>
#	include <unistd.h>
#	include <sys/stat.h>
#endif

#include "core/filesystem.h"
#include "core/config.h"
#include "core/strings.h"
#include <filesystem>
#include <limits.h>

namespace Filesystem {

/* this runs fs::create_directories() on the
   PARENT directory. */
void CreateDirectories(const std::filesystem::path& path) {
	if (path.empty())
		return;

	const auto& parent = path.parent_path();
	if (!std::filesystem::exists(parent))
		std::filesystem::create_directories(parent);
}

std::filesystem::path GetDotPath() {
#ifdef WIN32
	std::filesystem::path path;
	wchar_t* buf;

	if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, NULL, &buf) == S_OK)
		path = buf;
	else
		return std::filesystem::path();

	CoTaskMemFree(buf);

	return path / CONFIG_DIR;
#elif defined(MACOSX)
	return std::filesystem::path(osx::GetApplicationSupportDirectory()) / CONFIG_DIR;
#else // just assume POSIX
	std::filesystem::path path;
	const char* home = getenv("HOME");

#	ifdef __linux__
	if (!home)
		home = getpwuid(getuid())->pw_dir;
#	endif // __linux__

	/* only do this if the home directory was really found */
	if (home)
		return std::filesystem::path(home) / ".config" / CONFIG_DIR;
	else
		return std::filesystem::path();
#endif     // !WIN32 && !MACOSX
}

std::filesystem::path GetConfigPath() {
	return GetDotPath() / CONFIG_NAME;
}

std::filesystem::path GetPlayersPath() {
	return GetDotPath() / "recognition" / "players.json";
}

std::filesystem::path GetExtensionsPath() {
	return GetDotPath() / "recognition" / "extensions.json";
}

std::filesystem::path GetAnimeDBPath() {
	return GetDotPath() / "anime" / "db.json";
}

} // namespace Filesystem
