void CMyClientEventHandler::OnConnectionLost(const CClientPtr& client)
{
    AUTO_LOG_FUNCTION;
    CWinApp* app = AfxGetApp();
    if (app) {
        CWnd* wnd = app->GetMainWnd();
        if (wnd) {
            if (client->m_conn_id != 0xFFFFFFFF) {
                wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_offline, 0);
            }
            wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_disconn, 0);
        }
    }
}
void CMyClientEventHandler::OnConnectionEstablished(const CClientPtr& client)
{
    AUTO_LOG_FUNCTION;
    //std::lock_guard<std::mutex> lock(_mutex);
    CWinApp* app = AfxGetApp();
    if (app) {
        CWnd* wnd = app->GetMainWnd();
        if (wnd) {
            wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_conn, 0);
        }
    }
}
CMyClientEventHandler::DEAL_CMD_RET CMyClientEventHandler::DealCmd(const CClientPtr& client)
{
    AUTO_LOG_FUNCTION;

    DWORD conn_id = GetConnIdFromCharArray(client->m_packet2._cmd).ToInt();
    JLOG(L"conn_id %d", conn_id);
    switch (client->m_packet2._big_type)
    {
    case 0x01: // from Transmit server
    {
        switch (client->m_packet2._lit_type) {
        case 0x00:	// link test responce
        {
            JLOG(_T("Transmite server link test responce\n"));
            CWinApp* app = AfxGetApp();
            if (app) {
                CWnd* wnd = app->GetMainWnd();
                if (wnd) {
                    wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_rcv_lnk_tst, 0);
                }
            }
        }
        break;
        case 0x01:	// conn_id
            client->m_conn_id = conn_id;
            JLOG(_T("Transmite server responce my conn_id %d\n"), conn_id);
            {
                CWinApp* app = AfxGetApp();
                if (app) {
                    CWnd* wnd = app->GetMainWnd();
                    if (wnd) {
                        wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_online, 0);
                    }
                }
                auto acct = client->acct_;
                if (!acct.empty() && acct.length() <= 18) {
                    char buff[1024] = { 0 };
                    size_t len = client->m_packet1.Make(buff, sizeof(buff), AID_HB, 0, nullptr,
                                                        0, 0, 0, 0);
                    char_array cmd;
                    AppendConnIdToCharArray(cmd, ConnID(client->m_conn_id));
                    //AppendConnIdToCharArray(cmd, ConnID());

                    char acct_machine[9] = { 0 };
                    NumStr2HexCharArray_N(client->machine_acct_.c_str(), acct_machine, 9);

                    char acct_csr[9] = { 0 };
                    NumStr2HexCharArray_N(acct.c_str(), acct_csr, 9);

                    char pwd[4] = { 0 };
                    memset(pwd, 0xFF, 4);

                    len += client->m_packet2.Make(buff + len, sizeof(buff) - len, 0x04, 0x03, cmd,
                                                  acct_machine,
                                                  pwd,
                                                  acct_csr,
                                                  0);

                    client->PrepairToSend(-1, buff, len);
                    CWinApp* app = AfxGetApp();
                    if (app) {
                        CWnd* wnd = app->GetMainWnd();
                        if (wnd) {
                            wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_snd_machine_04_03, 0);
                        }
                    }
                }
            }
            return DCR_ONLINE;
            break;
        default:
            break;
        }
    } // end case 01
    break;

    case 0x05:
        if (client->m_packet2._lit_type == 0x01) {
            CWinApp* app = AfxGetApp();
            if (app) {
                CWnd* wnd = app->GetMainWnd();
                if (wnd) {
                    wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_rcv_machine_05_01, 0);
                }
            }
        }
        break;

    default:
        break;
    }
    return DCR_NULL;
}
DWORD WINAPI CClientManager::ThreadWorker(LPVOID lp)
{
	AUTO_LOG_FUNCTION;
	CClientManager* manager = reinterpret_cast<CClientManager*>(lp);
	timeval tv = { 0, 10 };
	DWORD dwCount = 0;
	for (;;) {
		dwCount++;
		if (WAIT_OBJECT_0 == WaitForSingleObject(manager->m_hEventShutdown, 1))
			break;

		if (manager->m_bShuttingDown) {
			break;
		}

		for (auto client_iter : manager->m_client_map) {

			if (WAIT_OBJECT_0 == WaitForSingleObject(manager->m_hEventShutdown, 0))
				break;

			if (manager->m_bShuttingDown) {
				break;
			}

			auto client = client_iter.second;
			if (!client->IsConnectionEstablished()) {
				continue;
			}		

			int nRet = 0;
			fd_set fdRead, fdWrite;

			FD_ZERO(&fdRead);
			FD_ZERO(&fdWrite);
			FD_SET(client->m_socket, &fdRead);
			FD_SET(client->m_socket, &fdWrite);
			nRet = select(client->m_socket + 1, &fdRead, &fdWrite, nullptr, &tv);
			if (WAIT_OBJECT_0 == WaitForSingleObject(manager->m_hEventShutdown, 0))
				continue;

			BOOL bRead = FD_ISSET(client->m_socket, &fdRead);
			BOOL bWrite = FD_ISSET(client->m_socket, &fdWrite);

			if (bRead) {
				char* temp = client->m_buff.buff + client->m_buff.wpos;
				DWORD dwLenToRead = BUFF_SIZE - client->m_buff.wpos;
				nRet = recv(client->m_socket, temp, dwLenToRead, 0);

				if (nRet <= 0) {
					JLOG(_T("ThreadRecv::recv ret <= 0, ret %d"), nRet);
					manager->m_handler->OnConnectionLost(client);
					client->Disconnect();
					continue;
				} else if (manager->m_handler) {
					client->m_buff.wpos += nRet;
					DWORD ret = RESULT_OK;
					ret = manager->m_handler->OnRecv(client);

					while (1) {
						unsigned int bytes_not_commited = client->m_buff.wpos - client->m_buff.rpos;
						if (bytes_not_commited == 0) {
							if (client->m_buff.wpos == BUFF_SIZE) {
								client->m_buff.Clear();
							}
							break;
						}
						if (client->m_buff.wpos == BUFF_SIZE) {
							memmove_s(client->m_buff.buff, BUFF_SIZE,
									  client->m_buff.buff + client->m_buff.rpos,
									  bytes_not_commited);
							memset(client->m_buff.buff + bytes_not_commited,
								   0, BUFF_SIZE - bytes_not_commited);
							client->m_buff.wpos -= client->m_buff.rpos;
							client->m_buff.rpos = 0;
							ret = manager->m_handler->OnRecv(client);
						} else {
							ret = manager->m_handler->OnRecv(client);
						}
						if (ret == RESULT_NOT_ENOUGH) {
							break;
						}
					}
					client->last_recv_time_ = COleDateTime::GetTickCount();
				}
			}

			if (bWrite) {
				// send link test
				if (manager->m_handler 
					&& client->m_bConnectionEstablished 
					&& ((COleDateTime::GetTickCount() - client->last_send_link_test_time_).GetTotalSeconds() * 1000 >= LINK_TEST_GAP)) {
					char buff[4096] = { 0 };
					DWORD dwLen = client->GenerateLinkTestPackage(buff, sizeof(buff));
					if (dwLen > 0 && dwLen <= sizeof(buff)) {
						int nLen = client->Send(buff, dwLen);
						if (nLen <= 0) {
							JLOG(_T("ThreadLinkTest::Send ret <= 0, ret %d"), nLen);
							client->Disconnect();
							manager->m_handler->OnConnectionLost(client);
							continue;
						}
						CWinApp* app = AfxGetApp();
						if (app) {
							CWnd* wnd = app->GetMainWnd();
							if (wnd) {
								wnd->PostMessageW(WM_NETWORKSTARTUPOK, mp_snd_lnk_tst, client->get_acct_id());
							}
						}
						JLOG(_T("Send link test to transmite server, len %d\n"), nLen);
						client->last_send_link_test_time_ = COleDateTime::GetTickCount();
					}
				}

				// send data
				if (!client->buffer_.empty() && client->buffer_lock_.try_lock()) {
					std::lock_guard<std::mutex> lock(client->buffer_lock_, std::adopt_lock);
					auto buffer = client->buffer_.front();
					client->Send(&buffer[0], buffer.size());
					client->buffer_.pop_front();
				}
			}

			// check timeup
			/*if (dwCount % 1000 == 0) {
				dwCount = 0;
				if ((COleDateTime::GetTickCount() - client->last_recv_time_).GetTotalSeconds() * 1000 > LINK_TEST_GAP * 3) {
					manager->m_handler->OnConnectionLost(client);
					client->Disconnect();
				}
			}*/
		
		}
		
	}
	return 0;
}