#include "global.h"
#include <sstream>
void UTF16ToUTF8(const wchar_t* wstr, std::vector<char>* outData, int* outLen)
{
	auto len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, 0, 0);
	if (outData->size() < len)
		outData->resize(len);
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, outData->data(), len, 0, 0);
	if (outLen)
		*outLen = len;
}

void UTF8ToUTF16(const char* str, std::vector<wchar_t>* outData, int* outLen)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
	if (outData->size() < len)
		outData->resize(len);
	MultiByteToWideChar(CP_UTF8, 0, str, -1, outData->data(), len);
	if (outLen)
		*outLen = len;
}

//ZLib
HMODULE zlibDll = nullptr;
int(*zlib_compress)(void* dest, size_t* destLen, const void* source, size_t sourceLen) = nullptr;//zlib的compress函数
int(*zlib_compress2)(void* dest, size_t* destLen, const void* source, size_t sourceLen, int level) = nullptr;
int(*zlib_uncompress)(void* dest, size_t* destLen, const void* source, size_t* sourceLen) = nullptr;//zlib的uncompress函数
size_t(*zlib_compressBound)(size_t sourceLen) = nullptr;//zlib的compressBound函数

void InitZLib()
{
	if (zlibDll)
		return;
	zlibDll = LoadLibraryW(L"zlib1.dll");
	zlib_compress = reinterpret_cast<decltype(zlib_compress)>(GetProcAddress(zlibDll, "compress"));
	zlib_compress2 = reinterpret_cast<decltype(zlib_compress2)>(GetProcAddress(zlibDll, "compress2"));
	zlib_uncompress = reinterpret_cast<decltype(zlib_uncompress)>(GetProcAddress(zlibDll, "uncompress"));
	zlib_compressBound = reinterpret_cast<decltype(zlib_compressBound)>(GetProcAddress(zlibDll, "compressBound"));
}

void ZLibCompressData(std::vector<BYTE>* outData, size_t* outLen, const void* source, size_t sourceLen)
{
	//计算压缩数据所需空间
	auto boundBuffSize = zlib_compressBound(sourceLen);
	auto allBuffSize = boundBuffSize + sizeof(size_t);
	//如果不够就开辟所需空间
	if (outData->size() < allBuffSize)
		outData->resize(allBuffSize);
	//写入原数据大小信息
	memcpy_s(outData->data(), allBuffSize, &sourceLen, sizeof(sourceLen));
	//写入压缩数据
	zlib_compress2(outData->data() + sizeof(size_t), &boundBuffSize, source, sourceLen, 9);
	//输出
	*outLen = boundBuffSize + sizeof(size_t);
}

void ZLibUncompressData(std::vector<BYTE>* outData, size_t* outLen, const void* source, size_t sourceLen)
{
	//取解压后的数据大小
	size_t BoundBuffSize = ((size_t*)source)[0];
	size_t srcLen = BoundBuffSize;
	//如果不够就开辟所需空间
	if (outData->size() < srcLen)
		outData->resize(srcLen);
	//写入解压数据
	zlib_uncompress(outData->data(), &BoundBuffSize, (const BYTE*)source + sizeof(size_t), &srcLen);
	//输出
	*outLen = srcLen;
}

void LoadResourceTexture(MyDX11Renderer* pRenderer, UINT resID, ID3D11Texture2D** outTexture, ID3D11ShaderResourceView** outSRV, int* outW, int* outH)
{
	auto hr = FindResource(NULL, MAKEINTRESOURCE(resID), L"PNG");
	auto sz = SizeofResource(NULL, hr);
	auto res = LoadResource(NULL, hr);
	void* data = LockResource(res);
	auto rw = SDL_RWFromConstMem(data, sz);
	auto s = IMG_LoadPNG_RW(rw);
	if (outW)
		*outW = s->w;
	if (outH)
		*outH = s->h;
	SDL_RWclose(rw);
	pRenderer->MyCreateTextureFromSDLSurface(outTexture, s);
	SDL_FreeSurface(s);
	pRenderer->MyCreateShaderResourceView(outSRV, *outTexture);
}

float MyFar(float myFar)
{
	float k = 16.0f;
	if (myFar <= -k)
		myFar = -k + 0.1f;
	float t = (myFar / k + 1.0f) / (2.0f * tanf(0.5f));
	return 2 * atanf(1.0f / (2.0f * t));
}

const float deg2rad = 3.141592654f / 180.0f;

int Random(int min, int max)
{
	const int range = max - min + 1;
	return min + rand() % range;
}
bool ParseInts(const wchar_t* str, std::vector<int>& outArr)
{
	std::wstringstream ss(str);
	std::wstring item;
	wchar_t delimiter = L',';

	outArr.clear();
	while (std::getline(ss, item, delimiter))
	{
		try
		{
			outArr.push_back(std::stoi(item));
		}
		catch (const std::exception)
		{
			return false;
		}
	}
	return true;
}


const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static BYTE reverse_map[] =
{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
};
void Base64Encode(std::string& out, const void* data, size_t dataSize)
{
	out.clear();
	int i = 0;
	int j = 0;
	BYTE char_array_3[3];
	BYTE char_array_4[4];
	BYTE* bytes_to_encode = (BYTE*)data;
	auto& in_len = dataSize;
	while (in_len--)
	{
		char_array_3[i++] = *(bytes_to_encode++);
		if (i == 3) {
			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for (i = 0; i < 4; i++)
				out += base64_chars[char_array_4[i]];
			i = 0;
		}
	}
	if (i)
	{
		for (j = i; j < 3; j++)
			char_array_3[j] = '\0';
		char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
		char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
		char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
		char_array_4[3] = char_array_3[2] & 0x3f;
		for (j = 0; j < i + 1; j++)
			out += base64_chars[char_array_4[j]];
		while (i++ < 3)
			out += '=';
	}
}

bool Base64Decode(std::vector<BYTE>& out, const char* base64Str)
{
	out.clear();
	size_t code_len = strlen(base64Str);
	if ((code_len & 0x03) != 0)
		return false;
	BYTE quad[4];
	for (size_t i = 0; i < code_len; i += 4)
	{
		for (size_t k = 0; k < 4; k++)
			quad[k] = reverse_map[base64Str[i + k]];
		if (!(quad[0] < 64 && quad[1] < 64))
			return false;
		out.push_back((quad[0] << 2) | (quad[1] >> 4));
		if (quad[2] >= 64)
			break;
		else if (quad[3] >= 64)
		{
			out.push_back((quad[1] << 4) | (quad[2] >> 2));
			break;
		}
		else
		{
			out.push_back((quad[1] << 4) | (quad[2] >> 2));
			out.push_back((quad[2] << 6) | quad[3]);
		}
	}
	return true;
}

float lerp(float start, float end, float t)
{
	return start + t * (end - start);
}

int GetSafePxa(int X, int Y, std::vector<LONG>& pxmData, std::vector<int>& pxaData, int pxmArr_w, int pxmArr_h)
{
	if (Y < 0 || Y > pxmArr_h - 1)
		return 0;
	if (X < 0 || X > pxmArr_w - 1)
		return 0;
	return pxaData[pxmData[Y * pxmArr_w + X]];
}