#pragma once

#include <stdexcept>
#include <string>

using namespace std;

#ifdef _WIN32
		inline wstring s2w(const char* str, size_t size = -1)
		{
			if (size == -1)
				size = strlen(str);

			if (size == 0)
				return wstring();

			size_t req_size = ::MultiByteToWideChar(CP_UTF8, 0,
				str, (int)size, NULL, 0);

			if (req_size == 0)
				throw runtime_error("Failed converting UTF-8 string to UTF-16");

			wstring wstr(req_size, 0);

			int conv_size = ::MultiByteToWideChar(CP_UTF8, 0,
				str, (int)size, wstr.data(), req_size);

			if (conv_size == 0)
				throw runtime_error("Failed converting UTF-8 string to UTF-16");

			return wstr;
		}

		inline wstring s2w(const string& str)
		{
			return s2w(str.data(), str.size());
		}

		inline string w2s(const wchar_t* wstr, size_t size = -1)
		{
			size_t req_size = WideCharToMultiByte(CP_UTF8, 0, wstr, size, nullptr, 0, nullptr, nullptr);

			if (!req_size)
				throw runtime_error("wide to multibyte conversion failed");

			string str(req_size, 0);

			int conv_size = WideCharToMultiByte(CP_UTF8, 0L, wstr, size, str.data(), req_size, nullptr, nullptr);

			if (!conv_size)
				throw runtime_error("wide to multibyte conversion failed");

			return str;
		}

		inline string w2s(const wstring& wstr)
		{
			return w2s(wstr.data(), wstr.size());
		}
#else
	inline wstring s2w(const char* str, size_t size = -1)
	{
		throw runtime_error("not implemented");
	}

	inline wstring s2w(const string& str)
	{
		return s2w(str.data(), str.size());
	}

	inline string w2s(const wchar_t* wstr, size_t size = -1)
	{
		throw runtime_error("not implemented");
	}

	inline string w2s(const wstring& wstr)
	{
		return w2s(wstr.data(), wstr.size());
	}
#endif
