// IRControl.cpp : 定义 DLL 的导出函数。
//

#include "stdafx.h"
#include "framework.h"
#include "IRControl.h"
#include <tlhelp32.h>
#include <Shlwapi.h>
#include "shellapi.h"
#pragma comment(lib, "shlwapi.lib")
#include "Global.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#ifndef SEND_SG_FORMAT
#define SEND_SG_FORMAT _T("name=\"%s\",dataset=\"%s\",signal=\"%s\"\n")
#endif

#ifndef SEND_SG_REP_FORMAT
#define SEND_SG_REP_FORMAT _T("name=\"%s\",dataset=\"%s\",signal=\"%s\",repeats=\"%d\"\n")
#endif

#ifndef SEND_SG_DUR_FORMAT
#define SEND_SG_DUR_FORMAT _T("name=\"%s\",dataset=\"%s\",signal=\"%s\",duration=\"%d\"\n")
#endif

#ifndef SEND_SG_BOTH_FORMAT
#define SEND_SG_BOTH_FORMAT _T("name=\"%s\",dataset=\"%s\",signal=\"%s\",repeats=\"%d\",duration=\"%d\"\n")
#endif

#ifndef APP_CMD_LINE
#define APP_CMD_LINE _T("%s --port=%ld")
#endif

#ifndef GET_IRC_DATA
#define GET_IRC_DATA \
if (m_strCurDevice.size() == 0) \
	getDeviceNameList(); \
if (m_strCurDevice.size() == 0) \
	return false;\
if (m_strCurDataset.size() == 0)\
	getDatasetNameList();\
if (m_strCurDataset.size() == 0)\
	return false;
#endif

DWORD CIRControl::m_dwCurAppId = 0;

CIRControl::CIRControl()
{
	
}

CIRControl::~CIRControl()
{
}

 bool CIRControl::checkEOM(std::string& data)
 {
 	if (data.size() < 5)
 		return false;
 
 	if (_tcsicmp("{\n", data.substr(0, 2).c_str()) != 0)
 		return false;
 
 	if (_tcsicmp("\n}\n", data.substr(data.size() - 3, 3).c_str()) != 0)
 		return false;
 
 	// 并返回去掉花括号的内容;
 	data = data.substr(2, data.size() - 5);
 
 	return true;
 }

bool CIRControl::StartApp(LPCTSTR lpAppDir, LPCTSTR lpSignalXml, DWORD dwPort)
{
	if (!lpAppDir || !PathFileExists(lpAppDir))
		return false;

	if ( IsAppRunning(lpAppDir) != 0)
		return true;

	// 启动应用程序;
	TCHAR szParameters[256] = {0};
	_stprintf_s(szParameters, APP_CMD_LINE, lpSignalXml, dwPort);
	//ShellExecute(NULL, "open", pszExePath, NULL, NULL, SW_SHOWNORMAL);
	SHELLEXECUTEINFO sei;
	memset(&sei, 0, sizeof(SHELLEXECUTEINFO));
	sei.cbSize = sizeof(SHELLEXECUTEINFO);
	sei.hwnd = NULL;
	// 普通打开方式：open；若想以管理员身份运行：runas
	sei.lpVerb = _T("runas");
	//sei.fMask = SEE_MASK_NOCLOSEPROCESS;//不设置，则使用默认值;
	sei.lpFile = lpAppDir;
	sei.lpParameters = szParameters;
	sei.lpDirectory = NULL;
#ifdef _DEBUG
	sei.nShow = SW_SHOWNORMAL;
#else
	sei.nShow = SW_HIDE;
#endif
	sei.hInstApp = NULL;

	if (!ShellExecuteEx(&sei))
	{
		DWORD dw = GetLastError();
		return false;
	}

	if (sei.hProcess)
		CloseHandle(sei.hProcess);

	return true;
}


DWORD CIRControl::IsAppRunning(LPCTSTR lpszAppDir)
{
	if (!lpszAppDir || !PathFileExists(lpszAppDir))
		return 0;

	std::string strAppDir = lpszAppDir;
	int nIndex = strAppDir.find('/');
	while (nIndex != std::string::npos)
	{
		strAppDir.replace(nIndex, 1, _T("\\"));
		nIndex = strAppDir.find('/');
	}
	nIndex = strAppDir.find_last_of(_T('\\'));
	if (nIndex != std::string::npos)
		strAppDir = strAppDir.substr(nIndex + 1);

	DWORD dwProcessID = 0;
	PROCESSENTRY32 pe32 = { 0 };

	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hProcessSnap == NULL)
	{
		Global::WriteTextLog(_T("获取进程快照失败:%ld"), GetLastError());
		return 0;
	}
	pe32.dwSize = sizeof(PROCESSENTRY32);

	if (Process32First(hProcessSnap, &pe32))
	{
		do
		{
			// szExeFile只是文件名，不知道是否只有win10才这样;
			if (_tcsicmp(strAppDir.c_str(), pe32.szExeFile) == 0)
			{
				m_dwCurAppId = dwProcessID = pe32.th32ProcessID;
				break;
			}
		} while (Process32Next(hProcessSnap, &pe32));
	}
	CloseHandle(hProcessSnap);

	return dwProcessID;
}

bool CIRControl::CloseApp(DWORD dwAppId)
{
	if (dwAppId == 0)
		dwAppId = m_dwCurAppId;

	if (dwAppId == 0)
		return true;

	HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, TRUE, dwAppId);
	if (hProcess == NULL)
	{
		Global::WriteTextLog(_T("打开进程失败:%ld"), GetLastError());
		return false;
	}

	DWORD dwError;
	if (!TerminateProcess(hProcess, 0))
	{
		dwError = GetLastError();
		CloseHandle(hProcess);
		hProcess = NULL;
		return false;
	}

	// 等待进程结束响应;
	if (WAIT_OBJECT_0 != WaitForSingleObject(hProcess, INFINITE))
	{
		CloseHandle(hProcess);
		return false;
	}

	CloseHandle(hProcess);
	hProcess = NULL;

	return true;
}

bool CIRControl::getDeviceNameList()
{
	return getDeviceNameList(m_vtDevices);
}

bool CIRControl::getDeviceNameList(std::vector<std::string>& vtDevice)
{
	vtDevice.clear();
	std::string data;
	if (!Send("hubquery=\"list redrats\"\n", data))
		return false;

	if (!checkEOM(data))
		return false;

	// 获取设备名;
	auto fun_dev = [](std::vector<std::string>& vtDev, std::string _dev_) {
		int npos = -1;
		npos = _dev_.find_last_of(']');
		if (npos != std::string::npos)
		{
			_dev_ = _dev_.substr(npos + 2); // +2 包含空格;
			// 去除connected;
			npos = _dev_.find(" (connected)");
			if (npos != std::string::npos)
			{
				_dev_ = _dev_.substr(0, npos);
			}
			vtDev.push_back(_dev_);
		}
	};

	std::string dev;
	int npos = -1;
	while (true)
	{
		npos = data.find_first_of('\n');
		if (npos == std::string::npos)
			break;

		// 去除方括号;
		fun_dev(vtDevice, data.substr(0, npos));
		data = data.substr(npos);
	}
	fun_dev(vtDevice, data.substr(0, npos));

	// 第一个设备给当前设备;
	if (vtDevice.size())
	{
		m_strCurDevice = *vtDevice.begin();
	}

	return true;
}

bool CIRControl::getDatasetNameList()
{
	return getDatasetNameList(m_vtDataset);
}

bool CIRControl::getDatasetNameList(std::vector<std::string>& vtDataset)
{
	vtDataset.clear();
	std::string data;
	if (!Send("hubquery=\"list datasets\"\n", data))
		return false;

	if (!checkEOM(data))
		return false;

	int npos = -1;
	while (true)
	{
		npos = data.find_first_of('\n');
		if (npos == std::string::npos)
			break;
		vtDataset.push_back(data.substr(0, npos));
		data = data.substr(npos + 1);
	}
	vtDataset.push_back(data);

	// 第一个设备给当前设备;
	if (vtDataset.size())
	{
		m_strCurDataset = *vtDataset.begin();
	}

	return true;
}

bool CIRControl::loadSignalDataSet(std::string file)
{
	std::string data;
	std::string send_data = "hubquery=\"load ir-file\",file=\"";
	send_data.append(file);
	send_data.append("\"\n");
	// 加载数据集xml文件，以前的会被删除;
	if (!Send(send_data, data))
		return false;

	if (_tcsicmp(data.c_str(), _T("OK\n")) == 0)
	{
		m_strCurDataset.clear();
		getDatasetNameList();
		return true;
	}

	return false;
}

bool CIRControl::addSignalDataSet(std::string file)
{
	std::string data;
	std::string send_data = "hubquery=\"add ir-file\",file=\"";
	send_data.append(file);
	send_data.append("\"\n");
	// 添加信息数据集，同名会被覆盖;
	if (!Send(send_data, data))
		return false;

	return !_tcsicmp(data.c_str(), _T("OK\n"));
}
// 
// bool CIRControl::getSignalsName(std::string dataset)
// {
// 	return getSignalsName(m_vtSignals, dataset);
// }

bool CIRControl::getSignalsName(std::vector<std::string>& vtSignals, std::string dataset)
{
	std::string data;
	std::string send_data = "hubquery=\"list signals in dataset\",dataset=\"";
	if (dataset.size() == 0)
	{// 加载默认;
		if (m_strCurDataset.size() == 0)
			getDatasetNameList();

		dataset = m_strCurDataset;
	}

	if (dataset.size() == 0)
		return false;

	send_data.append(dataset);
	send_data.append("\"\n");
	if (!Send(send_data, data))
		return false;

	if (!checkEOM(data))
		return false;

	int npos = -1;
	while (true)
	{
		npos = data.find_first_of('\n');
		if (npos == std::string::npos)
			break;
		vtSignals.push_back(data.substr(0, npos));
		data = data.substr(npos + 1);
	}
	vtSignals.push_back(data);

	return true;
}

std::string CIRControl::getSignalsName(std::string dataset /* = "" */)
{
	std::string data;
	std::string send_data = "hubquery=\"list signals in dataset\",dataset=\"";
	if (dataset.size() == 0)
	{// 加载默认;
		if (m_strCurDataset.size() == 0)
			getDatasetNameList();

		dataset = m_strCurDataset;
	}

	if (dataset.size() == 0)
	{
		return data;
	}

	send_data.append(dataset);
	send_data.append("\"\n");
	if (!Send(send_data, data))
	{
		return std::string();
	}

 	if (!checkEOM(data))
 	{
		return std::string();
 	}

	return data;
}

bool CIRControl::sendSignal(std::string signal, int send_times, int sleep_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	_stprintf_s(szSendSignal, SEND_SG_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signal.c_str());
	for (; send_times > 0; send_times--)
	{
		if (!Send(szSendSignal, data))
			return false;

		if (_tcsicmp(data.c_str(), _T("OK\n")))
			return false;

		Sleep(sleep_time);
	}

	return true;
}

bool CIRControl::sendSignals(const char(*signals)[10], int nCount, int sleep_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	for (int i = 0; i < nCount; i++)
	{
		//_stprintf_s(szSendSignal, SEND_SG_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signals[i]);
		_stprintf_s(szSendSignal, SEND_SG_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signals++);
		if (!Send(szSendSignal, data))
			return false;

		if (_tcsicmp(data.c_str(), _T("OK\n")))
			return false;

		Sleep(sleep_time);
	}

	return true;
}

bool CIRControl::sendSignals(std::string signals[], int nCount, int sleep_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	for (int i = 0; i < nCount; i++)
	{
		//_stprintf_s(szSendSignal, SEND_SG_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signals[i].c_str());
		_stprintf_s(szSendSignal, SEND_SG_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), (*signals++).c_str());
		if (!Send(szSendSignal, data))
			return false;

		if (_tcsicmp(data.c_str(), _T("OK\n")))
			return false;

		Sleep(sleep_time);
	}

	return true;
}

bool CIRControl::sendSignals(std::vector<std::string>& vtSignals, int sleep_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	for (auto signal : vtSignals)
	{
		_stprintf_s(szSendSignal, SEND_SG_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signal.c_str());
		if (!Send(szSendSignal, data))
			return false;

		if (_tcsicmp(data.c_str(), _T("OK\n")))
			return false;

		Sleep(sleep_time);
	}

	return true;
}

bool CIRControl::sendRepeatsSignal(std::string signal, int repeat_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	_stprintf_s(szSendSignal, SEND_SG_REP_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signal.c_str(), repeat_time);

	if (!Send(szSendSignal, data))
	{
		Global::WriteTextLog(_T("发送重复信号失败：%s"), data.c_str());
		return false;
	}

	if (!_tcsicmp(data.c_str(), _T("OK\n")))
		return true;

	Global::WriteTextLog(_T("发送重复信号失败：%s"), data.c_str());
	return false;
}

bool CIRControl::sendDurationSignal(std::string signal, int duration_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	_stprintf_s(szSendSignal, SEND_SG_DUR_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signal.c_str(), duration_time);

	if (!Send(szSendSignal, data))
		return false;

	return !_tcsicmp(data.c_str(), _T("OK\n"));
}

bool CIRControl::sendBothSignal(std::string signal, int repeat_time, int duration_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	_stprintf_s(szSendSignal, SEND_SG_BOTH_FORMAT, m_strCurDevice.c_str(), m_strCurDataset.c_str(), signal.c_str(), repeat_time, duration_time);

	if (!Send(szSendSignal, data))
		return false;

	return !_tcsicmp(data.c_str(), _T("OK\n"));
}

