// LogModule.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "LogModule.h"
#include <Shlwapi.h>
#include "SynSerial.h"
#include <process.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 唯一的应用程序对象

CWinApp theApp;

using namespace std;

CIOCPModel g_IOCP; // 主要对象，完成端口模型


// 线程：用于监听串口消息;
bool g_bStopThread = false;
HANDLE g_hThread = NULL;
unsigned int g_threadID = 0;
unsigned int __stdcall ThreadWathTVPort(PVOID pM)
{
	CSynSerial tv;
	std::string buffer;
	TCHAR szLastPort[10] = {0};
	_tcscpy_s(szLastPort, Global::g_szTVPort);
	std::vector<std::string> vtNotifyReboot;
	std::vector<std::string> vtNotifyShutdown;
	DWORD dwTickCount = GetTickCount();

	while(!g_bStopThread)
	{
		// 读取配置文件;
		Global::GetResourceCfg();
		if ( !Global::g_bWatchTVPort )
		{
			Sleep(5000);
			continue;
		}

		if ( GetTickCount() - dwTickCount > 5000 )
		{// 5秒更新一次;
			dwTickCount = GetTickCount();
			vtNotifyReboot.clear();
			vtNotifyShutdown.clear();
			Global::Split(Global::g_szTVReboot, _T(";"), vtNotifyReboot);
			Global::Split(Global::g_szTVShutdown, _T(";"), vtNotifyShutdown);
		}

		// 串口是否变更;
		if ( _tcsicmp(szLastPort, Global::g_szTVPort) )
		{
			_tcscpy_s(szLastPort, Global::g_szTVPort);
			// 重启打开串口;
			tv.CloseSerialPort();
		}
		
		if ( !tv.IsOpen() )
		{
			tv.OpenSerialPort(szLastPort, 115200, 8, 0, 1, 0, 1000);
		}

		if ( tv.IsOpen() )
		{
			BYTE szBuffer[1024] = {0};
			DWORD dwBuffer = tv.ReadComm(szBuffer, 1024, 1000);
			if ( dwBuffer != 0 )
			{
				int nType = 0; // 0表示无异常类型，-1表示关机异常，1表示重启异常;
				bool bAbnormal = false;
				buffer = (char*)szBuffer;
				__time64_t gmt = time(NULL);// 获取当前日历时间(1900-01-01开始的Unix时间戳);
				// 遍历是否有符合的子串;		
				for ( std::vector<std::string>::iterator it = vtNotifyReboot.begin(); it != vtNotifyReboot.end(); it++ )
				{
					if ( _tcsstr(buffer.c_str(), it->c_str()) )
					{
						nType = 1;
						bAbnormal = true;
						break;
					}
				}

				if ( !bAbnormal )
				{
					for ( std::vector<std::string>::iterator it = vtNotifyShutdown.begin(); it != vtNotifyShutdown.end(); it++ )
					{
						if ( _tcsstr(buffer.c_str(), it->c_str()) )
						{
							nType = -1;
							bAbnormal = true;
							break;
						}
					}
				}

				// 1分钟前，是否有收到脚本通知;
				if ( Global::g_notify.notify )
				{
					__int64 nd = gmt - Global::g_notify.datetime;
#ifdef _DEBUG
					TRACE3("判断时间%ld-通知时间%ld=相差时间%ld\n\n", gmt, Global::g_notify.datetime, nd);
#endif
					if ( nd < 60)
					{
						// 监测的类型与通知类型是否一致;
						if ( (nType == 1 && Global::g_notify.report_type == _T("reboot")) ||
							 (nType == -1 && Global::g_notify.report_type == _T("shutdown")) ) 
						{
							bAbnormal = false;
							// 重置;
							Global::g_notify.notify = false;
							Global::g_notify.datetime = 0;
							Global::g_notify.report_type.clear();
						}
					}
				}
				
				if (bAbnormal)
				{
					if ( nType == -1 )
					{
						// 遥控：重启电视机;
						if ( Global::g_SendPowerKey )
							Global::g_SendPowerKey();
					}

					// 压入容器中;
					Global::TLog tlog;
					if ( nType == -1 )
						tlog.report_type = "Abnormal shutdown";
					else if ( nType == 1 )
						tlog.report_type = "Abnormal restart";
					tlog.datetime = gmt; // 发生时间;

					struct tm gmtm = {0};
					localtime_s(&gmtm, &gmt); // 时间戳转成本地时间;
					TCHAR szDataTime[64] = {0};
					_stprintf_s(szDataTime,_T("Time of exception:%04d-%02d-%02d %02d:%02d:%02d"), gmtm.tm_year + 1900, gmtm.tm_mon+1, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec);
					tlog.report_data = szDataTime;
					Global::g_vtAbnormal.push_back(tlog);

					// 最后，重置;
					Global::g_notify.notify = false;
					Global::g_notify.datetime = 0;
					Global::g_notify.report_type.clear();
				}
			}
		}

		Sleep(200);
	}

	return 0;
}


// 启动tcp服务;
BOOL StartServer(unsigned int port)
{
	// 1.加载配置文件;
	TCHAR szDrive[_MAX_DRIVE] = { 0 };
	TCHAR szDir[_MAX_DIR] = { 0 };
	TCHAR szExt[_MAX_DIR] = { 0 };
	::GetModuleFileName(NULL, Global::g_szCurModulePath, sizeof(Global::g_szCurModulePath) / sizeof(TCHAR));
	_tsplitpath_s(Global::g_szCurModulePath, szDrive, szDir, Global::g_szFna, szExt);
	_tcscpy_s(Global::g_szCurModuleDir, szDrive);
	_tcscat_s(Global::g_szCurModuleDir, szDir);

	// 初始化网络库;
	if ( !g_IOCP.LoadSocketLib() )
	{
		return FALSE;
	}

	Global::WriteTextLog(_T("初始化网络库成功"));

	// 开启tcp服务;
	if ( !g_IOCP.Start(port) )
	{
		return FALSE;
	}

	Global::g_time = time(NULL);
	Global::g_lastTime = COleDateTime::GetCurrentTime();

	Global::WriteTextLog(_T("开启TCP服务成功"));
	if ( PathFileExists(Global::g_szConfig) )
	{
		// runner_tcp_port
		TCHAR szTcpPort[10] = {0};
		_itoa_s(port, szTcpPort, 10);
		Global::WriteTextLog(_T("配置文件路径：%s"), Global::g_szConfig);
		for ( int i = 0; i < 10; i++ )
		{
			if (!WritePrivateProfileString(_T("COMM"), _T("runner_tcp_port"), szTcpPort, Global::g_szConfig))
				Global::WriteTextLog(_T("保存端口号：%d 失败; 原因：%d"), port, GetLastError());
			else
			{
				Global::WriteTextLog(_T("保存端口号：%d 成功;"), port);
				break;
			}
		}
	}

#ifdef _DEBUG
	Sleep(10000);
#endif
	Global::GetResourceCfg();
	// 启动线程;
	g_hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadWathTVPort, NULL, 0, &g_threadID );

	return TRUE;
}

// 停止tcp服务;
void StopServer()
{
	g_IOCP.Stop();

	// 等待线程结束;
	g_bStopThread = true;
	WaitForSingleObject( g_hThread, INFINITE );
	CloseHandle( g_hThread );
}

// 是否写入日志文件;
void EnableWriteLog(bool bEnable)
{
	Global::g_bEnableLog = bEnable;
	if ( !bEnable )
		Global::ClosePythonLog();
	Global::WriteTextLog(_T("当前日志路径：%s; 状态：%s"), Global::g_szLogPath, bEnable ? _T("启用日志") : _T("禁用日志") );
}

void SetCaselogPath(LPCTSTR lpCaselogPath)
{
	if ( lpCaselogPath == NULL || lpCaselogPath[0] == '\0')
	{
		Global::WriteTextLog(_T("日志路径无效"));
		return;
	}

	Global::WriteTextLog(_T("设置日志路径：%s"), lpCaselogPath);
	_stprintf_s(Global::g_szLogPath, _T("%s"), lpCaselogPath);
}

void SetConfigPath(LPCTSTR lpConfigPath)
{
	if ( lpConfigPath == NULL || lpConfigPath[0] == '\0')
		return;

	_stprintf_s(Global::g_szConfig, _T("%s"), lpConfigPath);
}

void SetSendPowerKeyCB(void *pCB)
{
	Global::g_SendPowerKey = (Global::SENDPOWERKEY)pCB;
}

LPCTSTR GetCaselogPath()
{
	return Global::g_szLogPath;
}

__int64 GetReceivePrintTime()
{
	return Global::g_time;
}

void SetReceivePrintTime(__int64 dt)
{
	Global::g_time = dt;
}

void ClosePythonLog()
{
	Global::ClosePythonLog();
}

BOOL AddAbnormaltoXML(LPCTSTR lpXMLPath)
{
	// 参数有效性判断;
	if ( !lpXMLPath || !PathFileExists(lpXMLPath) )
	{
		return FALSE;
	}

	// 解析xml;
	tinyxml2::XMLDocument doc;
	if (tinyxml2::XML_SUCCESS != doc.LoadFile(lpXMLPath) )
	{
		return FALSE;
	}

	tinyxml2::XMLElement *pXmlRoot = NULL;
	if ((pXmlRoot = doc.RootElement()) != NULL)
	{
		int i = 0;
		TCHAR szNumber[10] = {0};
		for ( std::vector<Global::TLog>::iterator it = Global::g_vtAbnormal.begin(); it != Global::g_vtAbnormal.end(); it++ )
		{
			tinyxml2::XMLElement *pItem = doc.NewElement("item");

			tinyxml2::XMLElement *pName   = doc.NewElement("name");
			tinyxml2::XMLElement *pResult = doc.NewElement("result");
			tinyxml2::XMLElement *pData	  = doc.NewElement("data");
			tinyxml2::XMLElement *pLog	  = doc.NewElement("log");
			tinyxml2::XMLElement *pRemark = doc.NewElement("remark");

			memset(szNumber, 0, 10);
			_stprintf_s(szNumber, _T("100%04d@%s"), i++, it->report_type.c_str());
			pName->SetText(szNumber);
			pResult->SetText("PASS");
			pData->SetText(it->report_data.c_str());			
			pItem->InsertEndChild(pName);
			pItem->InsertEndChild(pResult);
			pItem->InsertEndChild(pData);
			pItem->InsertEndChild(pLog);
			pItem->InsertEndChild(pRemark);

			pXmlRoot->InsertEndChild(pItem);
		}
	}
	// 保存;
	doc.SaveFile(lpXMLPath);

	Global::g_vtAbnormal.clear();
}