#include "stdafx.h"
#include "SATClient.h"
//#include <ws2def.h>
#include "DlgProBar.h"

const int SOCK_TCP = SOCK_STREAM - 1;
const int SOCK_UDP = SOCK_DGRAM - 1;
const int AF_IPV4 = 0;
const int AF_IPV6 = 1;
#define PAK_LEN sizeof(SATPROTO::DataHeader)
#define HEADER_LEN sizeof(SATPROTO::DataHeader)
// 进度条;
CDlgProBar* g_pDlgProBar = NULL;

void CSATClient::OnThreadBegin(CSocketHandle* pSH)
{
	ASSERT(pSH == m_SocketClient);
	(pSH);
	CString strAddr;
	SockAddrIn sockAddr;
	m_SocketClient->GetSockName(sockAddr);
	GetAddress(sockAddr, strAddr);
	InitializeCriticalSection(&pSH->m_hClient2SrvSection);
}

void CSATClient::OnThreadExit(CSocketHandle* pSH)
{
	ASSERT(pSH == m_SocketClient);
	DeleteCriticalSection(&pSH->m_hClient2SrvSection);
	m_SocketClient.Close();
	m_bSocket = FALSE;
	TRACE(_T("======线程退出.\r\n"));
	(pSH);
}

void CSATClient::OnDataReceived(CSocketHandle* pSH, const BYTE* pbData, DWORD dwCount, const SockAddrIn& addr)
{
	ASSERT(pSH == m_SocketClient);
	(pSH);

	if (!m_SocketClient->IsOpen()) return;

	OnReceive(pbData, dwCount);
}

void CSATClient::OnConnectionDropped(CSocketHandle* pSH)
{
	ASSERT(pSH == m_SocketClient);
	(pSH);
	TRACE(_T("======连接服务器断开.\r\n"));
	m_SocketClient.Close();
	m_bSocket = FALSE;
}

void CSATClient::OnConnectionError(CSocketHandle* pSH, DWORD dwError)
{
	ASSERT(pSH == m_SocketClient);
	(pSH);
	_com_error err(dwError);
	m_SocketClient.Close();
	m_bSocket = FALSE;
}

CSATClient::CSATClient(void)
{
	m_nMode = AF_IPV4;
	m_nSockType = SOCK_TCP;
	m_SocketClient.SetInterface(this);
	m_bSocket = FALSE;
}

CSATClient::~CSATClient(void)
{
	m_SocketClient.Close();
}

bool CSATClient::OnSend(const byte* pData, int nLen, BOOL bShowGif)
{
	if (!m_bSocket) {
		if (!Start())
			return false;
	}

	DWORD dwLen = m_SocketClient.Write((const LPBYTE)pData, nLen);
	if (dwLen == nLen)
	{
		if (bShowGif) {
			CDlgProBar dlg;
			g_pDlgProBar = &dlg;
			dlg.DoModal();
		}
		
		OutputDebugString(_T("发送数据成功！\n"));
		return true;
	}
	else
	{
		g_pDlgProBar = NULL;
		OutputDebugString(_T("发送数据失败！\n"));
	}

	return false;
}

bool CSATClient::OnReceive(const byte* pData, int nLen)
{
	// 小于包头;
	SATPROTO::DataHeader* phead = NULL;
	if (lastData.size() == 0)
	{
		// 不足包头;
		if (PAK_LEN > nLen)
		{
			OutputDebugString("A：不足包头;\n");
			lastData.append((char*)pData, nLen);
		}
		else
		{
			// 包头充足;
			phead = (SATPROTO::DataHeader*)pData;

			// 完整的包;
			if (phead->len == nLen)
			{
				OutputDebugString("A：完整的包;\n");
				TaskProcess((SATPROTO::Package*)pData);
			}
			// 小包;
			else if (phead->len > nLen)
			{
				OutputDebugString("A：小包;\n");
				lastData.append((char*)pData, nLen);
			}
			// 超包;
			else if (phead->len < nLen)
			{
				OutputDebugString("A：超包;\n");
				lastData.append((char*)pData + phead->len, nLen - phead->len);
				TaskProcess((SATPROTO::Package*)pData);
			}
		}
	}
	else
	{
		int lastlen = nLen;
		if (lastData.size() >= PAK_LEN)
		{
			phead = (SATPROTO::DataHeader*)lastData.data();
			if (phead->len <= lastData.size() + nLen)
			{
				if (phead->len <= lastData.size())
				{
					OutputDebugString("C：超包;\n");
					// 完整包;
					TaskProcess((SATPROTO::Package*)lastData.substr(0, phead->len).data());

					lastData = lastData.substr(phead->len);
					lastData.append((char*)pData, nLen);
				}
				else
				{
					OutputDebugString("D：超包;\n");
					lastlen = lastData.size() + nLen - phead->len;
					lastData.append((char*)pData, nLen - lastlen);
					// 完整包;
					TaskProcess((SATPROTO::Package*)lastData.data());
					// 剩余包;
					lastData.clear();
					if (lastlen)
						lastData.append((char*)pData + nLen - lastlen, lastlen);
				}
			}
			else
			{
				OutputDebugString("C：仍不足一个包;\n");
				lastData.append((char*)pData, nLen);
			}
		}
		else
		{
			// 包头剩余长度;
			int diflen = PAK_LEN - lastData.size();
			// 仍不足一个包头;
			if (diflen > nLen)
			{
				OutputDebugString("B：仍不足一个包头;\n");
				lastData.append((char*)pData, nLen);
			}
			else
			{
				// 拼成完整包头;
				lastData.append((char*)pData, diflen);
				phead = (SATPROTO::DataHeader*)lastData.data();

				// 完整包;
				if (phead->len == PAK_LEN + nLen - diflen)
				{
					OutputDebugString("B：完整包;\n");
					lastData.append((char*)pData + diflen, nLen - diflen);
					TaskProcess((SATPROTO::Package*)lastData.data());
					lastData.clear();
				}
				// 小包;
				else if (phead->len > PAK_LEN + nLen - diflen)
				{
					OutputDebugString("B：小包;\n");
					lastData.append((char*)pData + diflen, nLen - diflen);
				}
				// 超包;
				else if (phead->len < PAK_LEN + nLen - diflen)
				{
					OutputDebugString("B：超包;\n");
					// 组完成包;
					lastData.append((char*)pData + diflen, phead->len - PAK_LEN);
					TaskProcess((SATPROTO::Package*)lastData.data());
					lastData.clear();
					int last = nLen - diflen - phead->len + PAK_LEN;
					if (last)
					{
						lastData.append((char*)pData + nLen - last, last);
					}
				}
			}
		}
	}

	return false;
}

bool CSATClient::OnClose()
{
	return false;
}

bool CSATClient::OnConnect()
{
	return false;
}

void CSATClient::TaskProcess(SATPROTO::Package* pak)
{
	SATPROTO::DataHeader* pHeader = &pak->header;
	if (pHeader->protocol == 0xAA) {
#ifdef _DEBUG
		// 延长加载框显示时间;
		Sleep(500);
#endif
		if (g_pDlgProBar) {
			while (!::IsWindow(g_pDlgProBar->m_hWnd));
			g_pDlgProBar->PostMessage(WM_STOPTHREAD);
			g_pDlgProBar = NULL;
		}

		switch (pHeader->cmd)
		{
			case SATPROTO::CMD_LOGIN:
			case SATPROTO::CMD_LOGOUT:
			{
				SATPROTO::LoginResp* resp = (SATPROTO::LoginResp*)pak->buf;
				if (pHeader->cmd == SATPROTO::CMD_LOGIN)
				{
					SATData::logout_resp.bStatus = false;
					SATData::login_resp.bStatus = resp->bStatus;
					_stprintf_s(SATData::login_resp.szMessage, _T("%s"), resp->szMessage);
				}
				else
				{
					SATData::login_resp.bStatus = false;
					SATData::logout_resp.bStatus = resp->bStatus;
					_stprintf_s(SATData::logout_resp.szMessage, _T("%s"), resp->szMessage);
				}
			}
				break;
			case SATPROTO::CMD_ADD_DEVICE:
			case SATPROTO::CMD_DEL_DEVICE:
			{
				// 无须处理返回值;
			}
				break;
			case SATPROTO::CMD_QUERY_DEVICES:
			{
				SATPROTO::DeviceResp* resp = (SATPROTO::DeviceResp*)pak->buf;
				//SATData::device_resp.nSize = resp->nSize;
				//memcpy(SATData::device_resp.szDevs, resp->szDevs, 30*MAX_PATH);
				SATData::devices.clear();
				for (size_t i = 0; i < resp->nSize; i++)
				{
					SATPROTO::Device dev;
					dev.nType = resp->ssDevs[i].nType;
					dev.nStatus = resp->ssDevs[i].nStatus;
					memcpy(dev.szName, resp->ssDevs[i].szName, MAX_PATH);
					SATData::devices.push_back(dev);
				}
			}
				break;
			default:
				break;
		}
	}
}

BOOL CSATClient::Start()
{
	int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6;
	if (!m_SocketClient.StartClient(NULL, Global::g_Config.strServiceIP.c_str(), Global::g_Config.strServicePort.c_str(), nFamily, (m_nSockType + 1)))
	{
#ifdef _DEBUG
		OutputDebugString("连接服务器失败\n");
#endif
		m_bSocket = FALSE;
		return FALSE;
	}

	// 成功连接服务器;
	m_bSocket = TRUE;
	CSocketHandle* pSH = (CSocketHandle*)m_SocketClient;

	// 设置等待数据为0;
	pSH->m_nPendingSize = 0;
	memset(pSH->m_PendingBuffer, 0, SOCKET_BUFFSIZE);

	// 设置多播;
	SetupMCAST();
	return TRUE;

}

void CSATClient::Stop()
{
	m_SocketClient.Terminate();
}

bool CSATClient::SetupMCAST()
{
	const TCHAR szIPv4MCAST[] = TEXT("239.121.1.2");
	const TCHAR szIPv6MCAST[] = TEXT("FF02:0:0:0:0:0:0:1"); // All Nodes local address
	bool result = false;
	if (m_nSockType == SOCK_UDP)
	{
		if (m_nMode == AF_IPV4) {
			result = m_SocketClient->AddMembership(szIPv4MCAST, NULL);
		}
		else {
			result = m_SocketClient->AddMembership(szIPv6MCAST, NULL);
			HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
			hr = hr;
		}
	}
	return result;
}

void CSATClient::GetAddress(const SockAddrIn& addrIn, CString& rString) const
{
	TCHAR szIPAddr[MAX_PATH] = { 0 };
	CSocketHandle::FormatIP(szIPAddr, MAX_PATH, addrIn);
	rString.Format(_T("%s : %d"), szIPAddr, static_cast<int>(static_cast<UINT>(ntohs(addrIn.GetPort()))));
}

bool CSATClient::TCPLogin(std::string strUserName, std::string strPassword, std::string strActuator, BOOL bLogin, BOOL bShowGif )
{
	SATData::login_resp = {0};
	int len = HEADER_LEN + sizeof(SATPROTO::UserInfo);
	byte* pbuff = new byte[len];
	memset(pbuff, 0, len);
	SATPROTO::Package* pData = (SATPROTO::Package*)pbuff;

	pData->header.protocol = 0xAA;
	pData->header.len = len;
	pData->header.cmd = bLogin ? SATPROTO::CMD_LOGIN : SATPROTO::CMD_LOGOUT;

	SATPROTO::UserInfo* pUserInfo = (SATPROTO::UserInfo*)pData->buf;
	memcpy(pUserInfo->szUserName, strUserName.c_str(), strUserName.size());
	memcpy(pUserInfo->szPassword, strPassword.c_str(), strPassword.size());
	memcpy(pUserInfo->szActuatorName, strActuator.c_str(), strActuator.size());

	bool bret = OnSend(pbuff, len, bShowGif);
	delete[]pbuff;

	return bret;
}

bool CSATClient::TCPLogout(std::string strUserName, std::string strPassword, std::string strActuator, BOOL bShowGif)
{
	return TCPLogin(strUserName, strPassword, strActuator, FALSE, bShowGif);
}

bool CSATClient::TCPAddDevice(std::string strDevice, bool bDel, BOOL bShowGif)
{
	int len = HEADER_LEN + MAX_PATH;
	byte* pbuff = new byte[len];
	memset(pbuff, 0, len);
	SATPROTO::Package* pData = (SATPROTO::Package*)pbuff;

	pData->header.protocol = 0xAA;
	pData->header.len = len;
	pData->header.cmd = bDel ? SATPROTO::CMD_DEL_DEVICE : SATPROTO::CMD_ADD_DEVICE;

	// 赋值;
	memcpy(pData->buf, strDevice.c_str(), strDevice.size());

	bool bret = OnSend(pbuff, len, bShowGif);
	delete[]pbuff;

	return false;
}

bool CSATClient::TCPDelDevice(std::string strDevice, BOOL bShowGif)
{
	return TCPAddDevice(strDevice, false, bShowGif);
}

bool CSATClient::TCPQueryDevices(BOOL bShowGif)
{
	int len = HEADER_LEN;
	byte* pbuff = new byte[len];
	memset(pbuff, 0, len);
	SATPROTO::Package* pData = (SATPROTO::Package*)pbuff;

	pData->header.protocol = 0xAA;
	pData->header.len = len;
	pData->header.cmd = SATPROTO::CMD_QUERY_DEVICES;

	bool bret = OnSend(pbuff, len, bShowGif);
	delete[]pbuff;

	return false;
}
