#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 <limits.h>

namespace Filesystem {

bool CreateDirectories(std::string path) {
	std::string temp = "";
	size_t start;
	size_t end = 0;
	temp.append(path.substr(0, path.find_first_not_of(DELIM, end)));

	while ((start = path.find_first_not_of(DELIM, end)) != std::string::npos) {
		end = path.find(DELIM, start);
		temp.append(path.substr(start, end - start));
#ifdef WIN32
		if (!CreateDirectoryA(temp.c_str(), NULL) && GetLastError() == ERROR_PATH_NOT_FOUND)
			/* ERROR_PATH_NOT_FOUND should NOT happen here */
			return false;
#else
		struct stat st;
		if (stat(temp.c_str(), &st) == -1)
			mkdir(temp.c_str(), 0755);
#endif
		temp.append(DELIM);
	}
	return true;
}

bool Exists(std::string path) {
#if WIN32
	return GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES;
#else
	struct stat st;
	return stat(path.c_str(), &st) == 0;
#endif
}

std::string GetParentDirectory(std::string path) {
	size_t pos = 0;
	pos = path.find_last_of(DELIM);
	return path.substr(0, pos);
}

std::string GetDotPath(void) {
	std::string ret = "";
#ifdef WIN32
	char buf[PATH_MAX + 1];
	if (SHGetFolderPathAndSubDir(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, CONFIG_DIR, buf) == S_OK) {
		ret += buf;
	}
#elif defined(MACOSX)
	ret += osx::GetApplicationSupportDirectory();
	ret += DELIM CONFIG_DIR;
#else // just assume POSIX
	if (getenv("HOME") != NULL)
		ret += getenv("HOME");
#	ifdef __linux__
	else
		ret += getpwuid(getuid())->pw_dir;
#	endif // __linux__
	if (!ret.empty())
		ret += DELIM ".config" DELIM CONFIG_DIR;
#endif     // !WIN32 && !MACOSX
	return ret;
}

std::string GetConfigPath(void) {
	std::string ret = "";
	ret += GetDotPath();
	if (!ret.empty())
		ret += DELIM CONFIG_NAME;
	return ret;
}

std::string GetAnimeDBPath(void) {
	std::string ret = "";
	ret += GetDotPath();
	if (!ret.empty())
		ret += DELIM "anime" DELIM "db.json";
	return ret;
}

} // namespace Filesystem
