#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>

#ifndef _MSC_VER

namespace std
{
	template<typename T, typename ...Args>
	std::unique_ptr<T> make_unique( Args&& ...args )
	{
	    return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
	}
}

inline int fopen_s(FILE** a_file, const char* a_fileName, const char* a_mode)
{
	*a_file = fopen(a_fileName, a_mode);
	return (*a_file != nullptr);
}

#endif


inline static std::vector<std::string> split(const std::string &s, char delim)
{
	std::vector<std::string> elems;
	std::stringstream ss(s);
	std::string item;
	while (std::getline(ss, item, delim)) {
		elems.push_back(item);
	}
	return elems;
}


inline static std::string trim(std::string str)
{
	str.erase(0, str.find_first_not_of(" \t\r\n"));
	str.erase(str.find_last_not_of(" \t\r\n") + 1);
	return str;
}


inline static std::string str2lower(const std::string& str)
{
	std::string ret = str;
	std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
	return ret;
}


// TODO: perhaps rename this function, it converts the string "#010203" to the int 0x010203
inline static unsigned int str2col(std::string str)
{
	if (str[0] == '#')
		str = &str[1];
	return std::stoul(str, nullptr, 16);
}


float static inline str2float(const std::string& str)
{
	return (float)atof(str.c_str());
}


// TODO: this doesn't work for any T, should work for int, perhaps need to add an std::enable_if
template<typename T>
inline static std::string int2hex(const T& value)
{
    std::ostringstream oss;
    oss << std::hex << value;
    return oss.str();
}


