#ifndef UTILS_H
#define UTILS_H
#include <string>
#include <string_view>
#include <vector>
#include <optional>
#include <functional>
#include <map>
#include <regex>
#include <ctime>
#include <boost/regex.hpp>
namespace utils
{

std::vector<std::string> splitByChar(const std::string &str, char delim);
std::vector<std::string> splitByString(const std::string &str, const std::string &delim);
std::vector<std::string> splitByRegex(const std::string &str, const std::string &regex);
std::string urldecode(std::string_view str);
std::string strreplace(const std::string &str, const std::string &search, const std::string &replace);

std::string html_xss(std::string_view str);
std::string getenv(const std::string &key);

template <class T, class U> bool hasKey(const std::map<T, U> &map, T key)
{
	auto k = map.find(key);
	return k != map.end();
}

template <class T, class U> U getKeyOrEmpty(const std::map<T, U> &map, T key)
{
	auto k = map.find(key);
	if(k != map.end())
	{
		return k->second;
	}
	return U();
}

template <class T, class U> U getKeyOrEmpty(std::multimap<T, U> map, T key)
{
	auto k = map.find(key);
	if(k != map.end())
	{
		return k->second;
	}
	return U();
}

template <class T, class U> std::vector<U> getAll(std::multimap<T, U> map, T key)
{
	std::vector<U> result;
	auto range = map.equal_range(key);
	for(auto it = range.first; it != range.second; it++)
	{
		result.push_back(it->second);
	}
	return result;
}

std::string regex_callback_replacer(boost::regex regex, const std::string &input,
									std::function<std::string(boost::smatch &)> callback);

std::string readCompleteFile(std::string_view filepath);

inline std::string nz(const char *s)
{
	if(s == nullptr)
	{
		return std::string{};
	}
	return std::string{s};
}

// TODO: optional
inline unsigned int toUInt(const std::string &str)
{
	if(str == "")
	{
		return 0;
	}
	auto result = std::stoul(str);
	if(result > std::numeric_limits<unsigned int>::max())
	{
		throw std::out_of_range(str + " is too large for unsigned int ");
	}
	return result;
}

std::string toISODate(time_t t);

template <class T> inline std::string toString(const T &v)
{
	return std::string(v.begin(), v.end());
}

} // namespace utils
#endif