#include "global.h"

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;
}

//压缩函数
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 MoveToNeighborRect(CRect& rcDst, CRect& rcSrc, int directionDst, int directionSrc)
{
	int wDst = rcDst.right - rcDst.left;
	int hDst = rcDst.bottom - rcDst.top;
	int wSrc = rcSrc.right - rcSrc.left;
	int hSrc = rcSrc.right - rcSrc.left;
	int xSrc = 0, ySrc = 0;
	switch (directionDst)
	{
	case 0://左上
		switch (directionSrc)
		{
		case 0://左上
			xSrc = rcDst.left;
			ySrc = rcDst.top;
			break;
		case 1://右上
		default:
			xSrc = rcDst.left - wSrc;
			ySrc = rcDst.top;
			break;
		case 2://右下
			xSrc = rcDst.left - wSrc;
			ySrc = rcDst.top - hSrc;
			break;
		case 3://左下
			xSrc = rcDst.left;
			ySrc = rcDst.top - hSrc;
			break;
		}
		break;
	case 1://右上
	default:
		switch (directionSrc)
		{
		case 0://左上
		default:
			xSrc = rcDst.right;
			ySrc = rcDst.top;
			break;
		case 1://右上
			xSrc = rcDst.right - wSrc;
			ySrc = rcDst.top;
			break;
		case 2://右下
			xSrc = rcDst.right - wSrc;
			ySrc = rcDst.top - hSrc;
			break;
		case 3://左下
			xSrc = rcDst.right;
			ySrc = rcDst.top - hSrc;
			break;
		}
		break;
	case 2://右下
		switch (directionSrc)
		{
		case 0://左上
			xSrc = rcDst.right;
			ySrc = rcDst.bottom;
			break;
		case 1://右上
			xSrc = rcDst.right - wSrc;
			ySrc = rcDst.bottom;
			break;
		case 2://右下
			xSrc = rcDst.right - wSrc;
			ySrc = rcDst.bottom - hSrc;
			break;
		case 3://左下
			xSrc = rcDst.right;
			ySrc = rcDst.bottom - hSrc;
		default:
			break;
		}
		break;
	case 3://左下
		switch (directionSrc)
		{
		case 0://左上
			xSrc = rcDst.left;
			ySrc = rcDst.bottom;
			break;
		case 1://右上
			xSrc = rcDst.left - wSrc;;
			ySrc = rcDst.bottom;
			break;
		case 2://右下
			xSrc = rcDst.left - wSrc;;
			ySrc = rcDst.bottom - hSrc;
		default:
			break;
		case 3://左下
			xSrc = rcDst.left;
			ySrc = rcDst.bottom - hSrc;
			break;
		}
		break;
	}
	rcSrc.MoveToXY(xSrc, ySrc);
}

void MoveWindow(CWnd* wnd, int x, int y)
{
	RECT rc;
	wnd->GetWindowRect(&rc);
	int w = rc.right - rc.left;
	int h = rc.bottom - rc.top;
	rc.left = x;
	rc.top = y;
	rc.right = rc.left + w;
	rc.bottom = rc.top + h;
	wnd->MoveWindow(&rc);
}

void LoadResourceTexture(MyDX11Renderer* pRenderer, UINT resID, ID3D11Texture2D** outTexture, ID3D11ShaderResourceView** outSRV)
{
	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);
	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 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;
}

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]];
}

void MyWinExec(std::wstring cmd)
{
	// 初始化结构体
	STARTUPINFOW si = { sizeof(si) };
	PROCESS_INFORMATION pi = { 0 };
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOW;
	// 创建进程
	BOOL success = CreateProcessW(
		NULL,                   // 不直接指定应用程序名（使用命令行）
		(wchar_t*)cmd.c_str(),// 命令行（必须可写）
		NULL,                   // 进程安全属性
		NULL,                   // 线程安全属性
		FALSE,                  // 不继承句柄
		0,                      // 标志
		NULL,                   // 环境块（使用父进程环境）
		NULL,                   // 当前目录（使用父进程目录）
		&si,                    // STARTUPINFO
		&pi                     // PROCESS_INFORMATION
	);
	if (success)
	{
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
}
