#include "StdAfx.h"
#include "RedRatProcess.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 CRedRatProcess::m_dwCurAppId = 0;

// ��ȡ�豸��;
void 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_);
	}
};


CRedRatProcess::CRedRatProcess(void)
{
}

CRedRatProcess::~CRedRatProcess(void)
{
}

bool CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::CloseApp(DWORD dwAppId)
{
	m_dwCurAppId = GetProcessId();
	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;
}

DWORD CRedRatProcess::GetProcessId(std::string strApp)
{
	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(strApp.c_str(), pe32.szExeFile) == 0)
			{
				m_dwCurAppId = dwProcessID = pe32.th32ProcessID;
				break;
			}
		} while (Process32Next(hProcessSnap, &pe32));
	}
	CloseHandle(hProcessSnap);

	return dwProcessID;
}

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

bool CRedRatProcess::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;

	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+1);
	}
	fun_dev(vtDevice, data);

	// ��һ���豸����ǰ�豸;
	if (vtDevice.size())
	{
		m_strCurDevice = *vtDevice.begin();
	}

	return true;
}

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

bool CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::getSignalsName(std::string dataset)
// {
// 	return getSignalsName(m_vtSignals, dataset);
// }

bool CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::sendSignals(std::vector<std::string>& vtSignals, int sleep_time)
{
	GET_IRC_DATA;

	std::string data;
	TCHAR szSendSignal[256] = { 0 };
	for (std::vector<std::string>::iterator signal = vtSignals.begin(); signal != vtSignals.end(); signal++)
	{
		_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 CRedRatProcess::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 CRedRatProcess::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 CRedRatProcess::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"));
}