#include "stdafx.h"
#include "Global.h"
#include <tchar.h>
#include <direct.h>
#include <SetupAPI.h>
#include <InitGuid.h>
#include <WinIoCtl.h>
#pragma comment(lib, "SetupAPI.lib")

namespace Global
{
	//////////////////////////////////////////////////////////////////////////
	// 全局变量;
	TCHAR g_szCurModuleDir[MAX_PATH] = {0};
	TCHAR g_szCurModulePath[MAX_PATH] = {0};
	TCHAR g_szFna[MAX_PATH] = {0};
	TCHAR g_szConfig[MAX_PATH] = {0};
	
	//////////////////////////////////////////////////////////////////////////
	// 全局函数;
	/************************************************************************/
	/*  函数：WriteTextLog[7/28/2009 Jeff];
	/*  描述：写文本日志;
	/*  参数：;
	/*  	[IN] ：;
	/*  返回：void;
	/*  注意：;
	/*  示例：;
	/*
	/*  修改：;
	/*  日期：;
	/*  内容：;
	/************************************************************************/
	void WriteTextLog(const TCHAR *format, ...)
	{
		// 解析出日志路径;
		TCHAR szlogpath[MAX_PATH] = { 0 };
		_stprintf_s(szlogpath, _T("%s%s.txt"), g_szCurModuleDir, g_szFna);
		// 打开或创建文件;
		FILE *fp = NULL;
		//if (_taccess(szlogpath, 0) != -1)
#ifndef UNICODE
		if (_access(szlogpath, 0) != -1)
#else
		if (_taccess(szlogpath, 0) != -1)
#endif
		{// 存在;
			if ( 0 == _tfopen_s(&fp, szlogpath, _T("a+")))
				// 移动到末尾;
				fseek(fp, 0, SEEK_END);
		}
		else
		{// 不存在;
			_tfopen_s(&fp, szlogpath, _T("w+"));
		}

		if ( fp == NULL )
			return;

		// 格式化前设置语言区域;
		TCHAR* old_locale = _tcsdup(_tsetlocale(LC_CTYPE, NULL));
		_tsetlocale(LC_CTYPE, _T("chs"));//设定中文;

		// 格式化日志内容;
		va_list		args = NULL;
		int			len = 0;
		TCHAR		*buffer = NULL;
		va_start(args, format);
		// _vscprintf doesn't count. terminating '\0'
		len = _vsctprintf(format, args) + 1;
		buffer = (TCHAR*)malloc(len * sizeof(TCHAR));
		_vstprintf_s(buffer, len, format, args);
		// 将日志内容输入到文件中;
		// 获取今年年份;
		__time64_t gmt = time(NULL);// 获取当前日历时间(1900-01-01开始的Unix时间戳);
		struct tm gmtm = {0};
		localtime_s(&gmtm, &gmt); // 时间戳转成本地时间;
		_ftprintf(fp, _T("%04d-%02d-%02d %02d:%02d:%02d %s\n"), gmtm.tm_year+1990, gmtm.tm_mon+1, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec, buffer);

		// 关闭文件，释放资源并设置回原语言区域;
		free(buffer);
		fclose(fp);
		_tsetlocale(LC_CTYPE, old_locale);
		free(old_locale);//还原区域设定;
	}

	
	// 读取配置文件-预留;
	void GetConfig()
	{
		TCHAR szValue[MAX_PATH] = {0};
		// config;
		//g_ini_config.com = GetPrivateProfileInt(_T("config"), _T("COM"), NULL, g_szConfig);
		//g_ini_config.baudrate = GetPrivateProfileInt(_T("config"), _T("Baudrate"), NULL, g_szConfig);
		//g_ini_config.chasis = GetPrivateProfileInt(_T("config"), _T("Chasis"), NULL, g_szConfig);
		//g_ini_config.mode = GetPrivateProfileInt(_T("config"), _T("ModeSelect"), NULL, g_szConfig);
		//g_ini_config.warncount = GetPrivateProfileInt(_T("config"), _T("WarnCount"), NULL, g_szConfig);

		//GetPrivateProfileString(_T("config"), _T("ChasisList"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_config.chasislist =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("config"), _T("SiacpCmdFile"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_config.siacpcmdfile =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("config"), _T("Server_url"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_config.serverurl =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//// folder;
		//GetPrivateProfileString(_T("filefolder"), _T("DIDFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.DIDFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("MACFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.MACFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("KEYFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.KEYFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("ESNFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.ESNFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("WiDiFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.WiDiFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("WidevineFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.WidevineFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("HDCPKEY22Folder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.HDCPKEY22Folder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("CIKeyFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.CIKeyFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

		//GetPrivateProfileString(_T("filefolder"), _T("WBFolder"), NULL, szValue, MAX_PATH, g_szConfig);
		//g_ini_folder.WBFolder =  szValue;
		//memset(szValue, 0, MAX_PATH);

	}
	
	BOOL GetOrientation(IN Image* pImg)
	{
		if (pImg == NULL) return FALSE;

		UINT totalBufferSize;
		UINT numProperties;
		pImg->GetPropertySize(&totalBufferSize, &numProperties);
		// Allocate the buffer that will receive the property items.
		PropertyItem* pAllItems = (PropertyItem*)malloc(totalBufferSize);
		// Fill the buffer.
		pImg->GetAllPropertyItems(totalBufferSize, numProperties, pAllItems);
		// Print the id data member of each property item.
		for (UINT j = 0; j < numProperties; ++j)
		{
			if (PropertyTagOrientation == pAllItems[j].id)
			{
				short* ptrLong = (short*)(pAllItems[j].value);
				int ret = (int)* ptrLong;
				free(pAllItems);
				return ret;
			}
		}
		free(pAllItems);

		return TRUE;
	}


	/************************************************************************/
	/*
	函数:GetEncoderClsid
	描述:获取GDI+支持的图像格式编码器种类,以及所有种类编码器信息;
	参数:
	IN:  format 要获取的图像格式;
	OUT: pClsid 返回符合条件的图像编码器信息;
	返回:成功返回编码器索引,否则返回-1;
	*/
	/************************************************************************/
	int GetEncoderClsid(IN CONST WCHAR* format, OUT CLSID* pClsid)
	{
		// GDI+支持的图像编码器数量;
		UINT  numEncoders = 0;
		// GDI+所有图像格式编码器详细信息所需要的空间大小;
		UINT  nSize = 0;

		ImageCodecInfo* pImageCodecInfo = NULL;

		// 2.获取GDI+支持的所有图像格式编码器详细信息所需要的空间大小;
		GetImageEncodersSize(&numEncoders, &nSize);
		if (nSize == 0)
			return -1;

		//3.为ImageCodecInfo数组分配足额空间;
		pImageCodecInfo = (ImageCodecInfo*)(malloc(nSize));
		if (pImageCodecInfo == NULL)
			return -1;

		//4.获取所有的图像编码器信息;
		GetImageEncoders(numEncoders, nSize, pImageCodecInfo);

		//5.查找符合的图像编码器的Clsid;
		for (UINT i = 0; i < numEncoders; ++i)
		{
			if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0)
			{
				*pClsid = pImageCodecInfo[i].Clsid;
				free(pImageCodecInfo);
				return i;  // Success
			}
		}

		//6.释放步骤3分配的内存;
		free(pImageCodecInfo);

		return -1;
	}


	BOOL LoadImgFromFile(IN Image** pImg, LPCTSTR lpPath)
	{
		if (!PathFileExists(lpPath))
			return FALSE;

		if (*pImg)
			delete* pImg;

		*pImg = NULL;

#ifdef UNICODE
		* pImg = Image::FromFile(lpPath);
#else
		BSTR strtmp = _bstr_t(lpPath);
		*pImg = Image::FromFile(strtmp, TRUE);
		SysFreeString(strtmp);
#endif

		return (*pImg ? TRUE : FALSE);
	}

	BOOL LoadImgFromBuffer(IN Image** pImg, IN BYTE* pBuffer, IN CONST INT& nBufLen)
	{
		if (pBuffer == NULL)
			return FALSE;

		if (*pImg)
			delete* pImg;

		*pImg = NULL;
		HGLOBAL hMemery = GlobalAlloc(GMEM_MOVEABLE, nBufLen);
		if (hMemery == NULL)
			return FALSE;

		BYTE* pMem = (BYTE*)GlobalLock(hMemery);
		memcpy(pMem, pBuffer, nBufLen);

		IStream* pstream = NULL;
		CreateStreamOnHGlobal(hMemery, TRUE, &pstream);
		*pImg = Image::FromStream(pstream);
		GlobalUnlock(hMemery);
		pstream->Release();

		return (*pImg ? TRUE : FALSE);
	}

	// 先以只读方式从文件中读取二进制流出来，可以做到不独占文件;
	BOOL LoadImgFromBuffer(IN Image** pImg, LPCTSTR lpPath)
	{
		if (!PathFileExists(lpPath))
			return FALSE;

		if (*pImg)
			delete* pImg;
		*pImg = NULL;

		return LoadImgFromFile(pImg, lpPath);

		CFile fp;
		CFileException e;
		BOOL bRet = FALSE;
		if (fp.Open(lpPath, CFile::modeRead, &e))
		{
			DWORD dwLength = (DWORD)fp.GetLength();
			BYTE* pData = new BYTE[dwLength];

			fp.Read(pData, dwLength);
			fp.Close();

			bRet = LoadImgFromBuffer(pImg, pData, dwLength);

			if (pData)
				delete[]pData;
		}

		return bRet;
	}

	/************************************************************************/
	/*  函数：LoadImgFromResource[9/21/2016 IT];
	/*  描述：从资源中加载;
	/*  参数：;
	/*  	[IN] ：;
	/*  	[OUT] ：;
	/*  	[IN/OUT] ：;
	/*  返回：void;
	/*  注意：;
	/*  示例：;
	/*
	/*  修改：;
	/*  日期：;
	/*  内容：;
	/************************************************************************/
	Image* LoadImgFromResource(IN HMODULE hModule, IN LPCTSTR lpName, IN LPCTSTR lpType)
	{
		HGLOBAL	hGlobal = NULL;
		HRSRC	hSource = NULL;
		LPVOID  lpBuffer = NULL;
		DWORD   dwSize = 0;
		// 1.定位我们的自定义资源，这里因为我们是从本模块定位资源，所以将句柄简单地置为NULL即可
		hSource = FindResource(hModule, lpName, lpType);
		if (hSource == NULL)
		{
			_tprintf(_T("载入资源失败:%s"), lpName);
			return NULL;
		}

		// 2.获取资源的大小;
		dwSize = (UINT)SizeofResource(NULL, hSource);

		// 3.加载资源;
		hGlobal = LoadResource(NULL, hSource);
		if (hGlobal == NULL)
		{
			_tprintf(_T("载入资源失败:%s"), lpName);
			return NULL;
		}

		// 4.锁定资源,获取buffer;
		lpBuffer = LockResource(hGlobal);
		if (lpBuffer == NULL)
		{
			_tprintf(_T("载入资源失败:%s"), lpName);
			return NULL;
		}

		// lpFileFullName需要先判断文件是否存在??不需要;
		Image* pImg = NULL;
		LoadImgFromBuffer(&pImg, (BYTE*)lpBuffer, dwSize);

		UnlockResource(hGlobal);
		FreeResource(hGlobal);

		return pImg;
	}

	BOOL SaveImgByRotate(LPCTSTR lpszFileName, BYTE* pBuffer, const INT& nBufLen, BOOL bHoriontal, BOOL bVertically)
	{
		Image *pImg = NULL;
		HGLOBAL hMemery = GlobalAlloc(GMEM_MOVEABLE, nBufLen);
		if (hMemery == NULL)
			return FALSE;

		BYTE* pMem = NULL;
		pMem = (BYTE*)GlobalLock(hMemery);
		if (pMem == NULL)
			return FALSE;
		memcpy(pMem, pBuffer, nBufLen);

		IStream* pstream = NULL;
	    HRESULT hr = CreateStreamOnHGlobal(hMemery, TRUE, &pstream);
		if (pstream == NULL)
			return FALSE;
		pImg = Image::FromStream(pstream);
		GlobalUnlock(hMemery);
		pstream->Release();

		if (bHoriontal && !bVertically)
			pImg->RotateFlip(RotateNoneFlipX);// 水平翻转;
		else if ( bHoriontal && bVertically)
			pImg->RotateFlip(Rotate180FlipNone);// 270度;
		else if (!bHoriontal && bVertically)
			pImg->RotateFlip(Rotate180FlipX);// 垂直翻转;

		CString strNewfile = lpszFileName;
		// 需要判断路径是否存在,不存在创建目录;
		int nIndex = strNewfile.ReverseFind(_T('\\'));
		if (nIndex == -1)
			return FALSE;

		if (!PathFileExists(strNewfile.Left(nIndex)))
		{
			// 如果文件夹不存在,创建;
			SHCreateDirectoryEx(NULL, strNewfile.Left(nIndex), NULL);
		}

		nIndex = strNewfile.ReverseFind(_T('.'));
		if (nIndex == -1)
			return FALSE;

		Status stat = GenericError;
		CLSID encoderClsid = { 0 };
		BSTR newfile = strNewfile.AllocSysString();

		strNewfile = strNewfile.Mid(nIndex + 1);
		if (strNewfile.CompareNoCase(_T("bmp")) == 0)
		{
			GetEncoderClsid(L"image/bmp", &encoderClsid);
			stat = pImg->Save(newfile, &encoderClsid, NULL);
		}
		else if (strNewfile.CompareNoCase(_T("png")) == 0)
		{
			GetEncoderClsid(L"image/png", &encoderClsid);
			stat = pImg->Save(newfile, &encoderClsid, NULL);
		}
		else// if ( strNewfile.CompareNoCase(_T("jpeg")) == 0 )
		{
			GetEncoderClsid(L"image/jpeg", &encoderClsid);

			EncoderParameters encoderParameters;
			encoderParameters.Count = 1;
			encoderParameters.Parameter[0].Guid = EncoderQuality;
			encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
			encoderParameters.Parameter[0].NumberOfValues = 1;
			// Save the image as a JPEG with quality level 100.
			ULONG uQuality = 100;
			encoderParameters.Parameter[0].Value = &uQuality;
			stat = pImg->Save(newfile, &encoderClsid, &encoderParameters);
		}

		if (pImg)
			delete pImg;
		pImg = NULL;

		SysFreeString(newfile);

		return stat == Ok ? TRUE : FALSE;
	}
	

	void MKDIR(LPCTSTR dir)
	{
		//////////////////////////////////////////////////////////////////////////
		// 创建目录;
		int nleft = 0;
		int nIndex = -1;
		TString strdir = dir;

		if (strdir.at(strdir.size() - 1) != _T('\\'))
			strdir.append(_T("\\"));

		// 共享路径和硬盘盘符;
		if (_tcscmp(strdir.substr(0, 2).c_str(), _T("\\\\")) == 0)
			nleft = strdir.find_first_of(_T("\\"), 2) + 1;	// 去除共享主机名;
		else if (strdir.at(2) == _T('\\'))
			nleft = 3;

		do
		{
			nIndex = strdir.substr(nleft, -1).find_first_of(_T("\\"));

			if (nIndex != TString::npos)
			{
				if (_tmkdir(strdir.substr(0, nIndex + nleft).c_str()) == -1 && (errno != EEXIST))
				{
					WriteTextLog(_T("创建目录失败：%s，错误码：%d"), strdir.substr(0, nIndex + nleft).c_str(), errno);
					break;
				}

				nleft += nIndex + 1;
			}
		} while (nIndex != -1);
	}

	// hModule 模块句柄 NULL表示当前模块;
	bool GetVersion(OUT WORD* pdwFileVersion, OUT WORD* pdwProductVerion)
	{
		TCHAR szFilePath[MAX_PATH] = { 0 };
		DWORD dwRet = GetModuleFileName(NULL, szFilePath, MAX_PATH);
		if (dwRet == 0)
			return false;

		VS_FIXEDFILEINFO* pVi = NULL;
		DWORD dwHandle = 0;
		int size = GetFileVersionInfoSize(szFilePath, &dwHandle);
		if (size > 0)
		{
			BYTE* buffer = new BYTE[size];
			memset(buffer, 0, size);

			if (GetFileVersionInfo(szFilePath, dwHandle, size, buffer))
			{
				if (VerQueryValue(buffer, _T("\\"), (LPVOID*)& pVi, (PUINT)& size))
				{
					pdwFileVersion[0] = HIWORD(pVi->dwFileVersionMS);
					pdwFileVersion[1] = LOWORD(pVi->dwFileVersionMS);
					pdwFileVersion[2] = HIWORD(pVi->dwFileVersionLS);
					pdwFileVersion[3] = LOWORD(pVi->dwFileVersionLS);

					pdwProductVerion[0] = HIWORD(pVi->dwProductVersionMS);
					pdwProductVerion[1] = LOWORD(pVi->dwProductVersionMS);
					pdwProductVerion[2] = HIWORD(pVi->dwProductVersionLS);
					pdwProductVerion[3] = LOWORD(pVi->dwProductVersionLS);

					delete[]buffer;
					return true;
				}
			}

			delete[]buffer;
		}

		return false;
	}
}