
// TouchBoardDlg.cpp : 구현 파일
//

#include "stdafx.h"
#include "TouchBoard.h"
#include "TouchBoardDlg.h"
#include "OnCastDlg.h"
#include "afxdialogex.h"
#include "CRoundButton.h"

#pragma comment(lib,"Ws2_32.lib")
#pragma comment(lib,"Wininet.lib")
#pragma comment(lib,"Iphlpapi.lib")
#ifdef _DEBUG
#pragma comment(lib,"cximage/debug/cximage.lib")
#pragma comment(lib,"cximage/debug/Jpeg.lib")
#pragma comment(lib,"cximage/debug/png.lib")
#pragma comment(lib,"cximage/debug/mng.lib")
#pragma comment(lib,"cximage/debug/jasper.lib")
#pragma comment(lib,"cximage/debug/zlib.lib")
#pragma comment(lib,"cximage/debug/Tiff.lib")
#pragma comment(lib,"cximage/debug/libdcr.lib")
#pragma comment(lib,"cximage/debug/libpsd.lib")
#else
#pragma comment(lib,"cximage/cximage.lib")
#pragma comment(lib,"cximage/Jpeg.lib")
#pragma comment(lib,"cximage/png.lib")
#pragma comment(lib,"cximage/mng.lib")
#pragma comment(lib,"cximage/jasper.lib")
#pragma comment(lib,"cximage/zlib.lib")
#pragma comment(lib,"cximage/Tiff.lib")
#pragma comment(lib,"cximage/libdcr.lib")
#pragma comment(lib,"cximage/libpsd.lib")
#endif

#include <winsock2.h>
#include <ws2tcpip.h>
#include <fcntl.h>
#include <psapi.h>

#include <iphlpapi.h>
#include <icmpapi.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CTouchBoardDlg *g_pMainDlg = NULL;

// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 대화 상자 데이터입니다.
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 지원입니다.

// 구현입니다.
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CTouchBoardDlg 대화 상자



CTouchBoardDlg::CTouchBoardDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CTouchBoardDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTouchBoardDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_LOG, m_logEdit);
}

BEGIN_MESSAGE_MAP(CTouchBoardDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_SETUP, &CTouchBoardDlg::OnBnClickedButtonSetup)
	ON_WM_DESTROY()
	ON_REGISTERED_MESSAGE(WM_TBD_SETUP_SAVE, &CTouchBoardDlg::OnTbdSetupSave)
	ON_REGISTERED_MESSAGE(WM_TBD_GROUP_PUSH, &CTouchBoardDlg::OnTbdLevel2Push)
	ON_REGISTERED_MESSAGE(WM_TBD_UPDATE_GROUP, &CTouchBoardDlg::OnTbdUpdateLevel2)
	ON_REGISTERED_MESSAGE(WM_TBD_UPDATE_LOG, &CTouchBoardDlg::OnTbdLogUpdate)
	ON_REGISTERED_MESSAGE(WM_TBD_SUB_GROUPING, &CTouchBoardDlg::OnTbdSubGrouping)
	
	ON_WM_ERASEBKGND()
	ON_BN_CLICKED(IDC_BUTTON_CAST_ALL, &CTouchBoardDlg::OnBnClickedButtonCastAll)
	ON_BN_CLICKED(IDC_BUTTON_CAST_FIRE, &CTouchBoardDlg::OnBnClickedButtonCastFire)
	ON_BN_CLICKED(IDC_BUTTON_CAST_RESCUE, &CTouchBoardDlg::OnBnClickedButtonCastRescue)
	ON_BN_CLICKED(IDC_BUTTON_CAST_EMERGENCY, &CTouchBoardDlg::OnBnClickedButtonCastEmergency)
	ON_BN_CLICKED(IDC_BUTTON_CAST_NORMAL, &CTouchBoardDlg::OnBnClickedButtonCastNormal)
	ON_BN_CLICKED(IDC_BUTTON_RESTORE, &CTouchBoardDlg::OnBnClickedButtonRestore)
	ON_BN_CLICKED(IDC_BUTTON_WIRELESS, &CTouchBoardDlg::OnBnClickedButtonWireless)
	ON_BN_CLICKED(IDC_BUTTON_CALL, &CTouchBoardDlg::OnBnClickedButtonCall)
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDC_BUTTON_CAST_WHOLE, &CTouchBoardDlg::OnBnClickedButtonCastWhole)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BUTTON_MICVOL_MINUS, &CTouchBoardDlg::OnBnClickedButtonMicvolMinus)
	ON_BN_CLICKED(IDC_BUTTON_MICVOL_PLUS, &CTouchBoardDlg::OnBnClickedButtonMicvolPlus)
	ON_BN_CLICKED(IDC_BUTTON_SPKVOL_MINUS, &CTouchBoardDlg::OnBnClickedButtonSpkvolMinus)
	ON_BN_CLICKED(IDC_BUTTON_SPKVOL_PLUS, &CTouchBoardDlg::OnBnClickedButtonSpkvolPlus)
	ON_WM_CTLCOLOR()
END_MESSAGE_MAP()




#include <Dbghelp.h>
#include <iostream>
#include <tchar.h>
#include <strsafe.h>
#include <shlobj.h>

#pragma comment(lib, "DbgHelp")
#define MAX_BUFF_SIZE 1024

using namespace std;
DWORD WINAPI func();

BOOL CheckPing(char strAddr[])
{
	BOOL bChkInternet;
	int nMaxTime = 1;

	HRESULT hr;
	char *SendData = "Check TCP/IP";

	LPVOID ReplyBuffer;
	INT32 iBufferLen;
	DWORD dwRetVal;
	HANDLE hlcmpFile;

	char pingAddr[64];
	sprintf(pingAddr, "%s", strAddr);

	hlcmpFile = IcmpCreateFile();
	iBufferLen = sizeof(ICMP_ECHO_REPLY) + strlen(SendData);
	ReplyBuffer = (VOID*)malloc(iBufferLen);
	while (TRUE)
	{
		dwRetVal = IcmpSendEcho(hlcmpFile,
			inet_addr(pingAddr), //www.00.co.kr
			SendData,
			strlen(SendData),
			NULL,
			ReplyBuffer,
			iBufferLen,
			1000);


		if (dwRetVal != 0) {
			PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
			struct in_addr ReplyAddr;
			ReplyAddr.S_un.S_addr = pEchoReply->Address;
			TRACE("\tSent icmp message to %s\n", pingAddr);
			if (dwRetVal > 1) {
				TRACE("\tReceived %ld icmp message responses\n", dwRetVal);
				TRACE("\tInformation from the first response:\n");
			}
			else {
				TRACE("\tReceived %ld icmp message response\n", dwRetVal);
				TRACE("\tInformation from this response:\n");
			}
			TRACE("\t  Received from %s\n", inet_ntoa(ReplyAddr));
			TRACE("\t  Status = %ld\n",
				pEchoReply->Status);
			TRACE("\t  Roundtrip time = %ld milliseconds\n",
				pEchoReply->RoundTripTime);
			
			if (pEchoReply->Status != 0)
				return FALSE;

			break;
		}

		Sleep(1000);
		nMaxTime--;

		if (0 == nMaxTime)
		{
			//AfxMessageBox(_T("인터넷에 연결 안됨"), MB_OK);
			//free(ReplyBuffer);
			TRACE("PING Failed at %s\n", pingAddr);
			return FALSE;
		}
	}

	if(dwRetVal != 0)
		TRACE("PING Okay at %s\n", pingAddr);
	//free(ReplyBuffer);
	return (dwRetVal != 0);
}

void make_minidump(EXCEPTION_POINTERS* e)
{
	TCHAR tszFileName[MAX_BUFF_SIZE] = {0};
	TCHAR tszPath[MAX_BUFF_SIZE] = {0};
	SYSTEMTIME stTime = {0};
	GetSystemTime(&stTime);
	SHGetSpecialFolderPath(NULL,tszPath, CSIDL_APPDATA, FALSE);
	StringCbPrintf(tszFileName, 
			       _countof(tszFileName), 
				   _T("%s\\%s__%4d%02d%02d_%02d%02d%02d.dmp"), 
				   _T("D:\\"), _T("CrashDump"),  
				   stTime.wYear, 
				   stTime.wMonth, 
				   stTime.wDay, 
				   stTime.wHour, 
				   stTime.wMinute, 
				   stTime.wSecond);

    HANDLE hFile = CreateFile(tszFileName, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if(hFile == INVALID_HANDLE_VALUE)
        return;

    MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
    exceptionInfo.ThreadId = GetCurrentThreadId();
    exceptionInfo.ExceptionPointers = e;
    exceptionInfo.ClientPointers = FALSE;

    MiniDumpWriteDump(
        GetCurrentProcess(),
        GetCurrentProcessId(),
        hFile,
        MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory | MiniDumpWithFullMemory),
        e ? &exceptionInfo : NULL,
        NULL,
        NULL);

	if(hFile)
	{
		CloseHandle(hFile);
		hFile = NULL;
	}
    return; 
}

LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e)
{
    make_minidump(e);
    return EXCEPTION_CONTINUE_SEARCH;
}


// CTouchBoardDlg 메시지 처리기

BOOL CTouchBoardDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	SetUnhandledExceptionFilter( unhandled_handler);		// added by ritoseo - 2019-09-10
	// 시스템 메뉴에 "정보..." 메뉴 항목을 추가합니다.

	// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
	//  프레임워크가 이 작업을 자동으로 수행합니다.
	SetIcon(m_hIcon, TRUE);			// 큰 아이콘을 설정합니다.
	SetIcon(m_hIcon, FALSE);		// 작은 아이콘을 설정합니다.

	// TODO: 여기에 추가 초기화 작업을 추가합니다.
	WSADATA wsaData = {0};
	int iResult;

	g_pMainDlg = this;

	m_sock = INVALID_SOCKET;
	m_iSelectGroup = -1;
	m_sendSize = 0;
	m_recvSize = 0;
	m_bIsActive = TRUE;
	m_stationCount = 0;
	m_iGroupBtnCount = 0;

    m_pMemDC = NULL;
	m_pDCBitmap = NULL;
	m_pDidLinePen = NULL;

	m_recvSize = 0;

	// Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        TRACE(L"WSAStartup failed: %d\n", iResult);
    }

	for(int i = 0;i < TBD_MAX_STATION_COUNT;i++) {
		m_pStationList[i] = NULL;
	}
	for(int i = 0;i < TBD_MAX_GROUP_COUNT;i++) {
		m_pGroupBtn[i] = NULL;	
	}
	
	RGB2RGBQURD(RGB(255, 0, 0), RGB_QUAD_RED);
	RGB2RGBQURD(RGB(0, 255, 0), RGB_QUAD_GREEN);
	RGB2RGBQURD(RGB(0, 0, 255), RGB_QUAD_BLUE);

#if USE_ROUND_BUTTON2
	//m_topFont.CreatePointFont(210, L"나눔고딕");
	m_topFont.CreateFont(28, 11, 0, 0, 1500, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"나눔고딕");
	m_castFont.CreateFont(28, 11, 0, 0, 1500, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"나눔고딕");
	m_titleFont.CreateFont(38, 15, 0, 0, 1000, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"나눔고딕");
#else
	m_topFont.CreatePointFont(240, L"나눔고딕");
	m_castFont.CreatePointFont(180, L"나눔고딕");
#endif
	
	m_logFont.CreatePointFont(80, L"나눔고딕");
	//m_btnFont.CreatePointFont(160, L"굴림");
	m_btnFont.CreateFont(20, 7, 0, 0, 1000, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"나눔고딕");
	m_btnSmallFont.CreateFont(20, 5, 0, 0, 1000, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"나눔고딕");
	m_btnUnderFont.CreateFont(20, 8, 0, 0, 1000, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"나눔고딕");
	

	GetMonitorInformation();
	TRACE("Monitor Resolution : %d x %d\n", m_infoMonitor.nWidth, m_infoMonitor.nHeight);
	m_bIsFullHD = false;
	if (m_infoMonitor.nWidth >= 1920) {
		m_iScreenWidth = 1920;
		m_iScreenHeight = 1080;
		m_bIsFullHD = true;
	} else {
		m_iScreenWidth = TBD_STANDARD_WIDTH;
		m_iScreenHeight = TBD_STANDARD_HEIGHT;
	}

#if 0
	m_bIsFullHD = false;
	m_iScreenWidth = TBD_STANDARD_WIDTH;
	m_iScreenHeight = TBD_STANDARD_HEIGHT;
#endif

	/*
	m_iScreenWidth = m_infoMonitor.nWidth;
	m_iScreenHeight = m_infoMonitor.nHeight;
	if (m_iScreenWidth > TBD_STANDARD_WIDTH) {
		m_iScreenWidth = 1920;
		m_iScreenHeight = 1080;
		m_bIsFullHD = true;
	}
	*/

	SetWindowPos(NULL, 0, 0, m_iScreenWidth, m_iScreenHeight, 0);


#if TBD_USE_COLOR_BUTTON == 1
	INT32 idx;
	INT32 iMoveXGap = 118;
	CRect rt;
	GetDlgItem(IDC_BUTTON_CAST)->GetClientRect(&rt);
	GetDlgItem(IDC_BUTTON_CAST)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CAST)->SetDlgCtrlID(0);

	if (m_bIsFullHD) {
		rt.right += 20;
		iMoveXGap += 20;
	}

#if TBD_USE_THREELINE_GROUP == 1
	rt.bottom -= 15;
#endif

	rt.MoveToXY(20, 19);
#if USE_ROUND_BUTTON2
	tButtonStyle style;
	m_pTopButton[0] = new CRoundButton2;
	m_tTopStyle[0].GetButtonStyle(&style);
		//style.m_tColorFace.m_tEnabled = RGB(130, 255, 130);
	style.m_tColorFace.m_tEnabled = RGB(57, 119, 206);
	m_tTopStyle[0].SetButtonStyle(&style);
	m_pTopButton[0]->SetRoundButtonStyle(&m_tTopStyle[0]);
#else
	m_pTopButton[0] = new CColorButton(RGB(0,0,0), RGB(130,255,130));
#endif
	m_pTopButton[0]->Create(L"방송", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CAST);
	m_pTopButton[0]->SetFont(&m_topFont);
	m_pTopButton[0]->ShowWindow(SW_HIDE);



#if USE_ROUND_BUTTON2
	rt.MoveToX(20);
#else
	rt.MoveToX(20 + 118);
#endif
	GetDlgItem(IDC_BUTTON_WIRELESS)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_WIRELESS)->SetDlgCtrlID(0);
#if USE_ROUND_BUTTON2
	m_pTopButton[1] = new CRoundButton2;
	m_tTopStyle[1].GetButtonStyle(&style);
	style.m_tColorBack.m_tEnabled = TOPBAR_BACK_COLOR;
	style.m_tColorBack.m_tPressed = TOPBAR_BACK_COLOR;
	m_tTopStyle[1].SetButtonStyle(&style);
	m_pTopButton[1]->SetRoundButtonStyle(&m_tTopStyle[1]);
#else
	m_pTopButton[1] = new CColorButton();
#endif
	m_pTopButton[1]->Create(L"무선",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_WIRELESS);
	m_pTopButton[1]->SetFont(&m_topFont);
	m_pTopButton[1]->ShowWindow(SW_SHOW);


#if USE_ROUND_BUTTON2
	rt.MoveToX(20 + iMoveXGap);
#else
	rt.MoveToX(20 + 118 * 2);
#endif
	GetDlgItem(IDC_BUTTON_CALL)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CALL)->SetDlgCtrlID(0);
#if USE_ROUND_BUTTON2
	m_pTopButton[2] = new CRoundButton2;
	m_tTopStyle[2].GetButtonStyle(&style);
	style.m_tColorBack.m_tEnabled = TOPBAR_BACK_COLOR;
	style.m_tColorBack.m_tPressed = TOPBAR_BACK_COLOR;
	m_tTopStyle[2].SetButtonStyle(&style);
	m_pTopButton[2]->SetRoundButtonStyle(&m_tTopStyle[2]);
#else
	m_pTopButton[2] = new CColorButton();
#endif
	m_pTopButton[2]->Create(L"전화",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CALL);
	m_pTopButton[2]->SetFont(&m_topFont);
	m_pTopButton[2]->ShowWindow(SW_SHOW);


#if USE_ROUND_BUTTON2
	rt.MoveToX(20 + iMoveXGap * 9 + 30);
	if (m_bIsFullHD) {
		rt.MoveToX(20 + iMoveXGap * 12 + 70);
	}
#else
	rt.MoveToX(20 + 118 * 3);
#endif
	GetDlgItem(IDOK)->ShowWindow(SW_HIDE);
	GetDlgItem(IDOK)->SetDlgCtrlID(0);
#if USE_ROUND_BUTTON2
	m_pTopButton[3] = new CRoundButton2;
	m_tTopStyle[3].GetButtonStyle(&style);
	style.m_tColorBack.m_tEnabled = TOPBAR_BACK_COLOR;
	style.m_tColorBack.m_tPressed = TOPBAR_BACK_COLOR;
	m_tTopStyle[3].SetButtonStyle(&style);
	m_pTopButton[3]->SetRoundButtonStyle(&m_tTopStyle[3]);
#else
	m_pTopButton[3] = new CColorButton();
#endif
	m_pTopButton[3]->Create(L"종료",
                  WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|
                  BS_OWNERDRAW|BS_MULTILINE,
				  rt,this,IDOK);
	m_pTopButton[3]->SetFont(&m_topFont);
	m_pTopButton[3]->ShowWindow(SW_SHOW);

	
	INT32 pivot_y = 320;
	INT32 btn_gap_y = 82;


#if USE_ROUND_BUTTON2
	GetDlgItem(IDC_BUTTON_CAST_ALL)->GetClientRect(&rt);
	rt.MoveToXY(17, pivot_y + btn_gap_y * 6);
#else
	rt.MoveToX(20 + 118 * 9);
	rt.right += 30;
#endif
	GetDlgItem(IDC_BUTTON_SETUP)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_SETUP)->SetDlgCtrlID(0);
#if USE_ROUND_BUTTON2
	m_pTopButton[4] = new CRoundButton2;
	m_tTopStyle[4].GetButtonStyle(&style);
	//style.m_tColorFace.m_tEnabled = RGB(240, 180, 120);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tTopStyle[4].SetButtonStyle(&style);
	m_pTopButton[4]->SetRoundButtonStyle(&m_tTopStyle[4]);
#else
	m_pTopButton[4] = new CColorButton();
#endif
	m_pTopButton[4]->Create(L"환경설정",
                  WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|
                  BS_OWNERDRAW|BS_MULTILINE,
				  rt,this,IDC_BUTTON_SETUP);
	m_pTopButton[4]->SetFont(&m_topFont);
	m_pTopButton[4]->ShowWindow(SW_SHOW);


	idx = 0;
	GetDlgItem(IDC_BUTTON_CAST_ALL)->GetClientRect(&rt);
	GetDlgItem(IDC_BUTTON_CAST_ALL)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CAST_ALL)->SetDlgCtrlID(0);
	rt.MoveToXY(17, pivot_y);
#if USE_ROUND_BUTTON2
	m_pActButton[idx] = new CRoundButton2;
	m_tActStyle[idx].GetButtonStyle(&style);
	style.m_tColorFace.m_tEnabled = RGB(240, 180, 120);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tActStyle[idx].SetButtonStyle(&style);
	m_pActButton[idx]->SetRoundButtonStyle(&m_tActStyle[idx]);
	m_pActButton[idx]->SetFont(&m_castFont);
#else
	m_pActButton[idx] = new CColorButton(RGB(0,0,0), RGB(240,180,120));
#endif
	m_pActButton[idx]->Create(L"서일제방송", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CAST_ALL);
	m_pActButton[idx]->ShowWindow(SW_SHOW);

#if 0
	m_pActButton[idx]->GetClientRect(rcOK);

	rgnOK.CreateRoundRectRgn(rcOK.left, rcOK.top,
		rcOK.right, rcOK.bottom,
		35, 35);
	nRet = m_pActButton[idx]->SetWindowRgn(rgnOK, TRUE);
#endif

	idx = 1;
	GetDlgItem(IDC_BUTTON_CAST_FIRE)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CAST_FIRE)->SetDlgCtrlID(0);
	rt.MoveToXY(17, pivot_y + btn_gap_y);
#if USE_ROUND_BUTTON2
	m_pActButton[idx] = new CRoundButton2;	
	m_tActStyle[idx].GetButtonStyle(&style);
	style.m_tColorFace.m_tEnabled = RGB(219, 40, 20);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tActStyle[idx].SetButtonStyle(&style);
	m_pActButton[idx]->SetRoundButtonStyle(&m_tActStyle[idx]);
	m_pActButton[idx]->SetFont(&m_castFont);

#else
	m_pActButton[idx] = new CColorButton(RGB(0,0,0), RGB(255,130,130));
#endif
	m_pActButton[idx]->Create(L"화재방송", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CAST_FIRE);
	m_pActButton[idx]->ShowWindow(SW_SHOW);

	idx = 2;
	GetDlgItem(IDC_BUTTON_CAST_RESCUE)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CAST_RESCUE)->SetDlgCtrlID(0);
	rt.MoveToXY(17, pivot_y + btn_gap_y * 2);
#if USE_ROUND_BUTTON2
	m_pActButton[idx] = new CRoundButton2;
	m_tActStyle[idx].GetButtonStyle(&style);
	style.m_tColorFace.m_tEnabled = RGB(241, 164, 36);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tActStyle[idx].SetButtonStyle(&style);
	m_pActButton[idx]->SetRoundButtonStyle(&m_tActStyle[idx]);
	m_pActButton[idx]->SetFont(&m_castFont);
#else
	m_pActButton[idx] = new CColorButton(RGB(0,0,0), RGB(252,254,209));
#endif
	m_pActButton[idx]->Create(L"구조방송", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CAST_RESCUE);
	m_pActButton[idx]->ShowWindow(SW_SHOW);

	idx = 3;
	GetDlgItem(IDC_BUTTON_CAST_EMERGENCY)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CAST_EMERGENCY)->SetDlgCtrlID(0);
	rt.MoveToXY(17, pivot_y + btn_gap_y * 3);
#if USE_ROUND_BUTTON2
	m_pActButton[idx] = new CRoundButton2;
	m_tActStyle[idx].GetButtonStyle(&style);
	style.m_tColorFace.m_tEnabled = RGB(0, 146, 55);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tActStyle[idx].SetButtonStyle(&style);
	m_pActButton[idx]->SetRoundButtonStyle(&m_tActStyle[idx]);
	m_pActButton[idx]->SetFont(&m_castFont);
#else
	m_pActButton[idx] = new CColorButton(RGB(0,0,0), RGB(130,255,130));
#endif
	m_pActButton[idx]->Create(L"구급방송", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CAST_EMERGENCY);
	m_pActButton[idx]->ShowWindow(SW_SHOW);

	idx = 4;
	GetDlgItem(IDC_BUTTON_CAST_NORMAL)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CAST_NORMAL)->SetDlgCtrlID(0);
	rt.MoveToXY(17, pivot_y + btn_gap_y * 4);
#if USE_ROUND_BUTTON2
	m_pActButton[idx] = new CRoundButton2;
	m_tActStyle[idx].GetButtonStyle(&style);
	style.m_tColorFace.m_tEnabled = RGB(1, 109, 181);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tActStyle[idx].SetButtonStyle(&style);
	m_pActButton[idx]->SetRoundButtonStyle(&m_tActStyle[idx]);
	m_pActButton[idx]->SetFont(&m_castFont);
#else
	m_pActButton[idx] = new CColorButton(RGB(0,0,0), RGB(70,70,200));
#endif
	m_pActButton[idx]->Create(L"기타방송", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CAST_NORMAL);
	m_pActButton[idx]->ShowWindow(SW_SHOW);

	idx = 5;
	GetDlgItem(IDC_BUTTON_RESTORE)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_RESTORE)->SetDlgCtrlID(0);
	rt.MoveToXY(17, pivot_y + btn_gap_y * 5);
#if USE_ROUND_BUTTON2
	m_pActButton[idx] = new CRoundButton2;
	m_tActStyle[idx].GetButtonStyle(&style);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tActStyle[idx].SetButtonStyle(&style);
	m_pActButton[idx]->SetRoundButtonStyle(&m_tActStyle[idx]);
	m_pActButton[idx]->SetFont(&m_castFont);
#else
	m_pActButton[idx] = new CColorButton;
#endif
	m_pActButton[idx]->Create(L"복구", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_RESTORE);
	m_pActButton[idx]->ShowWindow(SW_SHOW);

	idx = 6;
	GetDlgItem(IDC_BUTTON_CAST_WHOLE)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CAST_WHOLE)->SetDlgCtrlID(0);
	rt.MoveToXY(17, pivot_y - btn_gap_y);
#if USE_ROUND_BUTTON2
	m_pActButton[idx] = new CRoundButton2;
	m_tActStyle[idx].GetButtonStyle(&style);
	style.m_tColorBack.m_tEnabled = ACT_BTN_REGION_BACK_COLOR;
	style.m_tColorBack.m_tPressed = ACT_BTN_REGION_BACK_COLOR;
	m_tActStyle[idx].SetButtonStyle(&style);
	m_pActButton[idx]->SetRoundButtonStyle(&m_tActStyle[idx]);
	m_pActButton[idx]->SetFont(&m_castFont);
#else
	m_pActButton[idx] = new CColorButton;
#endif
	m_pActButton[idx]->Create(L"전체방송", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_OWNERDRAW|BS_MULTILINE,rt,this,IDC_BUTTON_CAST_WHOLE);
	m_pActButton[idx]->ShowWindow(SW_SHOW);
#endif

	m_setupDlg.Create(IDD_SETUP_DIALOG, this);
	m_setupDlg.LoadSettings();


#if TBD_BUTTON_UI_STYLE == 2
	int offset = -10;
	MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST), 0, offset);
	MoveWindowDirection(GetDlgItem(IDC_BUTTON_CALL), 0, offset);
	MoveWindowDirection(GetDlgItem(IDC_BUTTON_WIRELESS), 0, offset);
	MoveWindowDirection(GetDlgItem(IDOK), 0, offset);
#if !USE_ROUND_BUTTON2
	MoveWindowDirection(GetDlgItem(IDC_BUTTON_SETUP), 0, offset);
#endif
	MoveWindowDirection(GetDlgItem(IDC_STATIC_TITLE), 0, offset);
	#if TBD_USE_THREELINE_GROUP == 1
	MoveWindowDirection(GetDlgItem(IDC_STATIC_TITLE), 0, offset + 3);
	#endif

	#if USE_ROUND_BUTTON2
	offset = 65;
	if (m_bIsFullHD) {
		offset += 10;
	}
	MoveWindowDirection(GetDlgItem(IDC_BUTTON_SPKVOL_MINUS), 0, offset);
	MoveWindowDirection(GetDlgItem(IDC_STATIC_SPKVOL), 0, offset);
	MoveWindowDirection(GetDlgItem(IDC_STATIC_SPKVOL_VALUE), 0, offset);
	MoveWindowDirection(GetDlgItem(IDC_BUTTON_SPKVOL_PLUS), 0, offset);
	#endif
#endif

	if (m_bIsFullHD) {
		MoveWindowDirection(GetDlgItem(IDC_STATIC_TITLE), 250, 0);
	}


	GetDlgItem(IDC_BUTTON_CAST_WHOLE)->SetFont(&m_castFont);
	GetDlgItem(IDC_BUTTON_CAST_ALL)->SetFont(&m_castFont);
	GetDlgItem(IDC_BUTTON_CAST_FIRE)->SetFont(&m_castFont);
	GetDlgItem(IDC_BUTTON_CAST_RESCUE)->SetFont(&m_castFont);
	GetDlgItem(IDC_BUTTON_CAST_EMERGENCY)->SetFont(&m_castFont);
	GetDlgItem(IDC_BUTTON_CAST_NORMAL)->SetFont(&m_castFont);
	GetDlgItem(IDC_BUTTON_RESTORE)->SetFont(&m_castFont);
	GetDlgItem(IDC_BUTTON_SETUP)->SetFont(&m_castFont);
#if USE_ROUND_BUTTON2
	GetDlgItem(IDC_STATIC_TITLE)->SetFont(&m_titleFont);
#endif

	GetDlgItem(IDC_BUTTON_PS_STATUS)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_ES_STATUS)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_BUTTON_CT_STATUS)->ShowWindow(SW_HIDE);

	GetDlgItem(IDC_BUTTON_PS_STATUS)->GetClientRect(rt);
	rt.MoveToXY(17, 70);

	m_pStatusButton[0] = new CColorButton(RGB(0, 0, 0), STATUS_BTN_GOOD_BACK_COLOR);
	m_pStatusButton[0]->Create(L"PS", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW | BS_MULTILINE, rt, this, IDC_BUTTON_PS_STATUS);
	m_pStatusButton[0]->SetFont(&m_castFont);
	m_pStatusButton[0]->ShowWindow(SW_SHOW);

	rt.MoveToXY(17 + rt.Width() + 5, 70);
	m_pStatusButton[1] = new CColorButton(RGB(0, 0, 0), STATUS_BTN_GOOD_BACK_COLOR);
	m_pStatusButton[1]->Create(L"ES", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW | BS_MULTILINE, rt, this, IDC_BUTTON_ES_STATUS);
	m_pStatusButton[1]->SetFont(&m_castFont);
	m_pStatusButton[1]->ShowWindow(SW_SHOW);

	rt.MoveToXY(17 + (rt.Width() + 5) * 2, 70);
	m_pStatusButton[2] = new CColorButton(RGB(0, 0, 0), RGB(255, 0, 0));
	m_pStatusButton[2]->Create(L"CT", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW | BS_MULTILINE, rt, this, IDC_BUTTON_CT_STATUS);
	m_pStatusButton[2]->SetFont(&m_castFont);
	m_pStatusButton[2]->ShowWindow(SW_SHOW);


	GetDlgItem(IDC_BUTTON_NAME)->SetFont(&m_castFont);
	m_setupDlg.GetDlgItem(IDC_BUTTON_MICVOL_MINUS)->SetFont(&m_topFont);
	m_setupDlg.GetDlgItem(IDC_BUTTON_MICVOL_PLUS)->SetFont(&m_castFont);
	m_setupDlg.GetDlgItem(IDC_STATIC_MICVOL)->SetFont(&m_castFont);
	m_setupDlg.GetDlgItem(IDC_STATIC_MICVOL_VALUE)->SetFont(&m_castFont);
	
	m_setupDlg.GetDlgItem(IDC_BUTTON_LINEVOL_MINUS)->SetFont(&m_topFont);
	m_setupDlg.GetDlgItem(IDC_BUTTON_LINEVOL_PLUS)->SetFont(&m_castFont);
	m_setupDlg.GetDlgItem(IDC_STATIC_LINEVOL)->SetFont(&m_castFont);
	m_setupDlg.GetDlgItem(IDC_STATIC_LINEVOL_VALUE)->SetFont(&m_castFont);

	GetDlgItem(IDC_STATIC_SPKVOL)->SetFont(&m_castFont);
	GetDlgItem(IDC_STATIC_SPKVOL_VALUE)->SetFont(&m_castFont);
	GetDlgItem(IDC_EDIT_LOG)->SetFont(&m_logFont);
#if TBD_BUTTON_UI_STYLE == 2
	GetDlgItem(IDC_EDIT_LOG)->MoveWindow(180, m_iScreenHeight - 110, m_iScreenWidth - 210, 50);
#else
	GetDlgItem(IDC_EDIT_LOG)->MoveWindow(180, TBD_STANDARD_HEIGHT - 130, TBD_STANDARD_WIDTH - 210, 70);
#endif


	UpdateSettingToVariable();

	m_ciBackground.Create(m_iScreenWidth, m_iScreenHeight, 32);
	RGBQUAD rgbquad;
	RGB2RGBQURD(RGB(240, 240, 240), rgbquad);
#if USE_ROUND_BUTTON2
	RGB2RGBQURD(GLOBAL_BACK_COLOR, rgbquad);	
#endif
	m_ciBackground.FloodFill(0, 0, rgbquad);


	HINSTANCE hInst = AfxGetInstanceHandle();
	HRSRC res = FindResource(hInst, MAKEINTRESOURCE(IDB_PNG_SYMBOL), L"PNG");
	m_ciSymbol.AlphaCreate();
	m_ciSymbol.LoadResource(res, CXIMAGE_FORMAT_PNG, hInst);
	m_ciSymbol.Resample(75, 33);
	


#if TBD_USE_SOCKET_THREAD == 1
	m_pReceiveThread = AfxBeginThread(SocketReceiveThread, this);
#else
	m_pReceiveThread = AfxBeginThread(SocketConnectionThread, this);
	SetTimer(TBD_TIMER_EVENT_SOCKET, 10, NULL);
#endif

	m_pPingThread = AfxBeginThread(PingCheckThread, this);


#if USE_DUMMY_DATA_FOR_UI
	{
		int station_idx = 0;
		m_stationCount = 0;
		m_iGroupBtnCount = 0;

		for (station_idx == 0; station_idx < 22; station_idx++) {
			if (m_pStationList[station_idx] == NULL) {
				m_pStationList[station_idx] = new CStationInfo;
				m_pStationList[station_idx]->m_pButton = NULL;
			}
			m_pStationList[station_idx]->mGroupIdx = station_idx;
			m_pStationList[station_idx]->mWardId = station_idx;
			m_pStationList[station_idx]->mStationId = station_idx;
			m_pStationList[station_idx]->mNickName = L"소방본부";
			m_pStationList[station_idx]->mNickIndex = station_idx;
			m_pStationList[station_idx]->mLevel = 2;
			m_pStationList[station_idx]->mUpWardId = station_idx;
			m_pStationList[station_idx]->mSubCount = 10;
			m_pStationList[station_idx]->mSubGroupId = station_idx;
			m_pStationList[station_idx]->mBtnShiftRow = -1;
			if (m_iGroupBtnCount < TBD_MAX_GROUP_COUNT)		// added by ritoseo - 2022-01-20
				m_iGroupBtnCount++;
			m_stationCount++;
		}

		for (station_idx == 22; station_idx < 33; station_idx++) {
			if (m_pStationList[station_idx] == NULL) {
				m_pStationList[station_idx] = new CStationInfo;
				m_pStationList[station_idx]->m_pButton = NULL;
			}
			m_pStationList[station_idx]->mGroupIdx = 1;
			m_pStationList[station_idx]->mWardId = station_idx;
			m_pStationList[station_idx]->mStationId = station_idx;
			m_pStationList[station_idx]->mNickName = L"지역대";
			m_pStationList[station_idx]->mNickIndex = station_idx - 22;
			m_pStationList[station_idx]->mLevel = 3;
			m_pStationList[station_idx]->mUpWardId = station_idx;
			m_pStationList[station_idx]->mSubCount = 1;
			m_pStationList[station_idx]->mSubGroupId = station_idx;
			m_pStationList[station_idx]->mBtnShiftRow = -1;
			m_stationCount++;
		}

		CalcButtonPositioning();
		UpdateTouchButtonList();
	}
#endif


	return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}

void CTouchBoardDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}



// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
//  아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는
//  프레임워크에서 이 작업을 자동으로 수행합니다.

void CTouchBoardDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 아이콘을 그립니다.
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CPaintDC dc(this); 

		CBitmap *pOldBitmap;
		CPen *pOldPen;

		if(m_pMemDC == NULL) {
			m_pMemDC = new CDC();
			m_pMemDC->CreateCompatibleDC(&dc);
		}

		if(m_pDCBitmap == NULL) {
			m_pDCBitmap = new CBitmap();
			m_pDCBitmap->CreateCompatibleBitmap(&dc, m_iScreenWidth, m_iScreenHeight);
		}

		if(m_pDidLinePen == NULL) {
			m_pDidLinePen = new CPen();
			m_pDidLinePen->CreatePen(PS_SOLID, 3, TOUCH_BTN_LINE_COLOR);
		}

		pOldBitmap = m_pMemDC->SelectObject(m_pDCBitmap);
		pOldPen = m_pMemDC->SelectObject(m_pDidLinePen);

		m_pMemDC->SetBkMode( TRANSPARENT );
		m_ciBackground.Draw2(m_pMemDC->GetSafeHdc());

#if USE_ROUND_BUTTON2
		m_pMemDC->FillSolidRect(0, 0, m_iScreenWidth, 65, TOPBAR_BACK_COLOR);
		m_pMemDC->FillSolidRect(0, 220, 190, 675 /*+ 60 */, ACT_BTN_REGION_BACK_COLOR);
		if (m_bIsFullHD) {
			m_pMemDC->FillSolidRect(190, 65, m_iScreenWidth - 190 - 40, 150, RGB(155, 155, 155));
			m_pMemDC->FillSolidRect(191, 66, m_iScreenWidth - 190 - 42, 148, RGB(255, 255, 255));
		} else {
			m_pMemDC->FillSolidRect(190, 65, 1045, 150, RGB(155, 155, 155));
			m_pMemDC->FillSolidRect(191, 66, 1043, 148, RGB(255, 255, 255));
		}

		//m_pMemDC->FillSolidRect(190, 220, 1045, 750, RGB(155, 155, 155));
		//m_pMemDC->FillSolidRect(191, 221, 1043, 748, RGB(255, 255, 255));


#endif

		for(INT32 i = 0;i < m_stationCount;i++)
		{
			if(m_pStationList[i] && m_pStationList[i]->mStationId > 0)
			{
#if TBD_BUTTON_UI_STYLE == 2
				if(m_pStationList[i]->mGroupIdx == m_iSelectGroup && m_pStationList[i]->mLevel < 4) {
					RECT rect = m_pStationList[i]->mGroupBox;
					INT32 off_x = m_pStationList[i]->mBtnPosX + TBD_BTN_SUB_START_X;
					INT32 off_y = m_pStationList[i]->mBtnPosY + TBD_BTN_SUB_START_Y;

					COLORREF color = TBD_BTN_GROUP_LINE_BASE_COLOR;
					if(m_pStationList[i]->m_pButton->m_bChecked) 
						color = TBD_BTN_GROUP_LINE_CHECK_COLOR;

					m_pMemDC->Draw3dRect(rect.left + off_x, rect.top + off_y, rect.right - rect.left, rect.bottom - rect.top, color, color);
					m_pMemDC->Draw3dRect(rect.left + off_x - 1, rect.top + off_y - 1, rect.right - rect.left + 2, rect.bottom - rect.top + 2, color, color);
				}
#else
				if(m_pStationList[i]->mGroupIdx == m_iSelectGroup && m_pStationList[i]->mSubCount > 0) {
					RECT rect = m_pStationList[i]->mGroupBox;
					INT32 off_x = m_pStationList[i]->mBtnPosX + TBD_BTN_SUB_START_X;
					INT32 off_y = m_pStationList[i]->mBtnPosY + TBD_BTN_SUB_START_Y;

					COLORREF color = TBD_BTN_GROUP_LINE_BASE_COLOR;
					if(m_pStationList[i]->m_pButton->m_bChecked) 
						color = TBD_BTN_GROUP_LINE_CHECK_COLOR;

					m_pMemDC->Draw3dRect(rect.left + off_x, rect.top + off_y, rect.right - rect.left, rect.bottom - rect.top, color, color);
					m_pMemDC->Draw3dRect(rect.left + off_x - 1, rect.top + off_y - 1, rect.right - rect.left + 2, rect.bottom - rect.top + 2, color, color);
				}
#endif
			}
		}

		//m_pMemDC->Draw3dRect(100, 100, 700, 600, RGB(255, 0, 0), RGB(255, 0, 0));
		if (m_bIsFullHD) {
			m_ciSymbol.Draw(m_pMemDC->GetSafeHdc(), 490 + 250, 18);
		} else {
			m_ciSymbol.Draw(m_pMemDC->GetSafeHdc(), 490, 18);
		}
		dc.BitBlt(0, 0, m_iScreenWidth, m_iScreenHeight, m_pMemDC, 0, 0, SRCCOPY);
		m_pMemDC->SelectObject(pOldPen);
		m_pMemDC->SelectObject(pOldBitmap);

		CDialogEx::OnPaint();
	}
}

// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
//  이 함수를 호출합니다.
HCURSOR CTouchBoardDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

in_addr* CTouchBoardDlg::atoaddr(char *address)
{
    struct hostent *host;
    static struct in_addr saddr;

    /* First try it as aaa.bbb.ccc.ddd. */
    saddr.s_addr = inet_addr(address);
    if (saddr.s_addr != (unsigned long)-1) {
        return &saddr;
    }

    host = gethostbyname(address);
    if (host != NULL) {
        return (struct in_addr *) *host->h_addr_list;
    }

    return NULL;
}

SOCKET CTouchBoardDlg::ConnectRequest(char *pAddress, int port)
 {
	SOCKET sock;
	int iResult;
	sockaddr_in address;
	in_addr *pAddr;

	sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	pAddr = atoaddr(pAddress);

	memset((char *) &address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(m_port);
    address.sin_addr.s_addr = pAddr->s_addr;

	char optval = 1;
	int ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int));
	ret = setsockopt(sock, IPPROTO_TCP, SO_KEEPALIVE, &optval, sizeof(int));

	unsigned long iMode = 1;
    iResult = ioctlsocket(sock, FIONBIO, &iMode);		// Socket to NON BLOCKING
    if (iResult != NO_ERROR)
    {	
        printf("ioctlsocket failed with error: %ld\n", iResult);
    }

	iResult = connect(sock, (sockaddr *)&address, sizeof(address));
	if(iResult == SOCKET_ERROR)
	{
		TIMEVAL Timeout;
		Timeout.tv_sec = 0;
		Timeout.tv_usec = 100000;

#if 0
		iMode = 0;
		iResult = ioctlsocket(sock, FIONBIO, &iMode);		// Socket to BLOCKING
		if (iResult != NO_ERROR)
		{	
			printf("ioctlsocket failed with error: %ld\n", iResult);
		}
#endif

		fd_set Write, Err;
		for(int i = 0;i < 20;i++) {
			FD_ZERO(&Write);
			FD_ZERO(&Err);
			FD_SET(sock, &Write);
			FD_SET(sock, &Err);
 
			// check if the socket is ready
			select(0,NULL,&Write,&Err,&Timeout);			
			if(FD_ISSET(sock, &Write)) 
				return sock;
			if(!m_bIsActive) {
				break;
			}
		}
		closesocket(sock);
		sock = INVALID_SOCKET;
	}

	return sock;
 }

INT32 CTouchBoardDlg::SocketSendExceptionHandle(char *sendData, int datasize)
{
	INT32 ret = 0;
	m_sockMutex.Lock();
	if(m_sendSize > 0) {
		memcpy(m_sendBuffer + m_sendSize, sendData, datasize);
		m_sendSize += datasize;
		ret = datasize;
	} else {
		INT32 size = SocketSend(sendData, datasize);
		if((size > 0 && size < datasize) || size == 0) {
			memcpy(m_sendBuffer + m_sendSize, sendData + size, datasize - size);
			m_sendSize += (datasize - size);
			ret = datasize;
		}
	}
	m_sockMutex.Unlock();
	return ret;
}

INT32 CTouchBoardDlg::SocketSend(char *sendData, int datasize)
{
    fd_set tabSocketToWait;
    struct timeval timeout;
    int status;
    int connect_timeout = 1; 
	int sock = m_sock;

    FD_ZERO(&tabSocketToWait);
    FD_SET(sock,&tabSocketToWait);
    timeout.tv_sec = connect_timeout/1000;
    timeout.tv_usec = (connect_timeout%1000) * 1000;

    status = select(sock+1,
            (fd_set *)0, 
            &tabSocketToWait,
            (fd_set *)0, 
            &timeout);

    if(status > 0) 
    {    
        status = send(sock, sendData, datasize, 0);
        if(status < 0) 
        {    
            if(errno == EAGAIN || errno == EWOULDBLOCK)
                return 0;
            else 
            {    
                perror("++++++++++++++++++++++++++++ socket Recv");
                return -1;
            }    
        }    

        return status;
    }    

    return 0;
}


void CTouchBoardDlg::UpdateSubGroupList()
{
	for(INT32 i = 0;i < m_stationCount;i++)
	{
		if(m_pStationList[i]->mLevel == 3) 
		{
			for(INT32 j = 0;j < m_stationCount;j++) {
				if(m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId && m_pStationList[j]->mLevel > m_pStationList[i]->mLevel) {
					m_pStationList[j]->mSubGroupId = m_pStationList[i]->mWardId;
					m_pStationList[i]->mSubCount++;
				}
			}
		}
	}

	for(INT32 i = 0;i < m_stationCount;i++)
	{
		if(m_pStationList[i]->mLevel == 2) 
		{
			for(INT32 j = 0;j < m_stationCount;j++) {
				if(m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId && m_pStationList[j]->mSubCount == 0 && m_pStationList[j]->mLevel > m_pStationList[i]->mLevel) {
					m_pStationList[j]->mSubGroupId = m_pStationList[i]->mWardId;
					m_pStationList[i]->mSubCount++;
				}
			}
		}
	}

	/*
	for(INT32 i = 0;i < m_stationCount;i++)
	{
		if(m_pStationList[i]->mLevel == 1) 
		{
			for(INT32 j = 0;j < m_stationCount;j++) {
				if(m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId && m_pStationList[j]->mSubCount == 0) {
					m_pStationList[j]->mSubGroupId = m_pStationList[i]->mWardId;
					m_pStationList[i]->mSubCount++;
				}
			}
		}
	}
	*/
}

void CTouchBoardDlg::CalcButtonPositioning()
{
	for(INT32 iGrp = 0;iGrp < m_iGroupBtnCount;iGrp++)
	{
		INT32 iGrpRow = 0;
		INT32 iSubGrpIdx = 0;

#if TBD_BUTTON_UI_STYLE == 1
		for(INT32 i = 0;i < m_stationCount;i++)
		{
			if(m_pStationList[i]->mGroupIdx == iGrp)
			{
				if(m_pStationList[i]->mLevel == 2) 
				{
					if(m_pStationList[i]->m_pButton == NULL) {
						m_pStationList[i]->m_pButton = new CTouchButton;
						m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
					}
					m_pStationList[i]->m_pButton->m_strName = m_pStationList[i]->mNickName + L"상황실";
					m_pStationList[i]->mBtnPosX = 0;
					m_pStationList[i]->mBtnPosY = 0;

					if(m_pStationList[i]->mSubCount > 0)
					{
						INT32 btnIdx = 0;
						for(INT32 j = 0;j < m_stationCount;j++) 
						{
							if(m_pStationList[j]->mSubGroupId == m_pStationList[i]->mWardId) {

								INT32 row, column;
								row = btnIdx / TBD_BTN_SUB_COLUMN_SIZE;
								column = btnIdx % TBD_BTN_SUB_COLUMN_SIZE;

								if(m_pStationList[j]->m_pButton == NULL) {
									m_pStationList[j]->m_pButton = new CTouchButton;
									m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
								}
								m_pStationList[j]->m_pButton->m_strName = m_pStationList[j]->mNickName;
								m_pStationList[j]->mBtnPosX = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * column;
								m_pStationList[j]->mBtnPosY = (TBD_BTN_HEIGHT + 5) * row;
								//m_pStationList[j]->m_pButton->m_bVisible = false;

								btnIdx++;
							}
						}

						m_pStationList[i]->m_pButton->m_iBtnFlag |= TOUCH_BTN_FLAG_CHECKABLE;
						m_pStationList[i]->mGroupBox.left = -TBD_BTN_SUB_MARGIN_X;
						m_pStationList[i]->mGroupBox.top = -TBD_BTN_SUB_MARGIN_Y;
						if(m_pStationList[i]->mSubCount < TBD_BTN_SUB_COLUMN_SIZE) {	
							m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (m_pStationList[i]->mSubCount - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
							m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + TBD_BTN_SUB_MARGIN_Y;
						} else {
							m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (TBD_BTN_SUB_COLUMN_SIZE - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
							m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + (TBD_BTN_HEIGHT + 5) * ((m_pStationList[i]->mSubCount - 1) / TBD_BTN_SUB_COLUMN_SIZE) + TBD_BTN_SUB_MARGIN_Y;
						}

						iGrpRow += ((btnIdx - 1) / TBD_BTN_SUB_COLUMN_SIZE) + 1;
					}

					iSubGrpIdx++;
				}


				if(m_pStationList[i]->mLevel == 3 && m_pStationList[i]->mSubCount > 0) 
				{
					if(m_pStationList[i]->m_pButton == NULL) {
						m_pStationList[i]->m_pButton = new CTouchButton;
						m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
					}
					m_pStationList[i]->m_pButton->m_strName = m_pStationList[i]->mNickName;
					m_pStationList[i]->mBtnPosX = 0;
					m_pStationList[i]->mBtnPosY = (TBD_BTN_HEIGHT + 5) * iGrpRow  + 20 * iSubGrpIdx;

					if(m_pStationList[i]->mSubCount > 0)
					{
						INT32 btnIdx = 0;
						for(INT32 j = 0;j < m_stationCount;j++) 
						{
							if(m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId) {

								INT32 row, column;
								row = btnIdx / TBD_BTN_SUB_COLUMN_SIZE;
								column = btnIdx % TBD_BTN_SUB_COLUMN_SIZE;

								if(m_pStationList[j]->m_pButton == NULL) {
									m_pStationList[j]->m_pButton = new CTouchButton;
									m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
								}
								m_pStationList[j]->m_pButton->m_strName = m_pStationList[j]->mNickName;
								m_pStationList[j]->mBtnPosX = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * column;
								m_pStationList[j]->mBtnPosY = (TBD_BTN_HEIGHT + 5) * (iGrpRow + row) + 20 * iSubGrpIdx;
								m_pStationList[j]->m_pButton->m_bVisible = false;

								btnIdx++;
							}
						}

						m_pStationList[i]->m_pButton->m_iBtnFlag |= TOUCH_BTN_FLAG_CHECKABLE;
						m_pStationList[i]->mGroupBox.left = -TBD_BTN_SUB_MARGIN_X;
						m_pStationList[i]->mGroupBox.top = -TBD_BTN_SUB_MARGIN_Y;
						if(m_pStationList[i]->mSubCount < TBD_BTN_SUB_COLUMN_SIZE) {	
							m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (m_pStationList[i]->mSubCount - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
							m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + TBD_BTN_SUB_MARGIN_Y;
						} else {
							m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (TBD_BTN_SUB_COLUMN_SIZE - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
							m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + (TBD_BTN_HEIGHT + 5) * ((m_pStationList[i]->mSubCount - 1) / TBD_BTN_SUB_COLUMN_SIZE) + TBD_BTN_SUB_MARGIN_Y;
						}

						iGrpRow += ((btnIdx - 1) / 5) + 1;
						iSubGrpIdx++;
					}
				}
			}

			//if(m_pStationList[i]->m_pButton)
			//	m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
		}
#else
		/* Sorting for NickName Index */
		for(INT32 i = 0;i < m_stationCount;i++)
		{
			if(m_pStationList[i]->mGroupIdx == iGrp && m_pStationList[i]->mNickIndex >= 0)
			{
				for(INT32 j = i + 1;j < m_stationCount;j++) {
					if(m_pStationList[j]->mGroupIdx == iGrp && m_pStationList[j]->mNickIndex >= 0 && m_pStationList[j]->mNickIndex < m_pStationList[i]->mNickIndex) {
						CStationInfo* pTemp = m_pStationList[j];
						m_pStationList[j] = m_pStationList[i];
						m_pStationList[i] = pTemp;
					}
				}
			}
		}


		INT32 iGroupRowCount = 0;
		for (INT32 i = 0; i < m_stationCount; i++)
		{
			if (m_pStationList[i]->mGroupIdx == iGrp)
			{
#if TBD_BUTTON_UI_STYLE == 2
				if (m_pStationList[i]->mLevel == 2 && m_pStationList[i]->mStationId > 0)
					//if(m_pStationList[i]->mLevel == 2) 
#else
				if (m_pStationList[i]->mLevel == 2)
#endif
				{
					iGroupRowCount++;
					iSubGrpIdx++;
				}

				if (m_pStationList[i]->mLevel == 3)
				{
					if (m_pStationList[i]->mSubCount > 0)
					{
						INT32 btnIdx = 0;
						for (INT32 j = 0; j < m_stationCount; j++)
						{
							if (m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId) {
								btnIdx++;
							}
						}
						
						iGroupRowCount += ((btnIdx - 1) / 5) + 1;
						iSubGrpIdx++;
					}
					else {
						iGroupRowCount++;
						iSubGrpIdx++;
					}
				}
			}
		}
		iSubGrpIdx = 0;


		INT32 i_sub_column_size = TBD_BTN_SUB_COLUMN_SIZE;
		if (m_bIsFullHD) {
			i_sub_column_size = 9;
		}

		for(INT32 i = 0;i < m_stationCount;i++)
		{
			if(m_pStationList[i]->mGroupIdx == iGrp)
			{
				#if TBD_BUTTON_UI_STYLE == 2
				if(m_pStationList[i]->mLevel == 2 && m_pStationList[i]->mStationId > 0) 
				//if(m_pStationList[i]->mLevel == 2) 
				#else
				if(m_pStationList[i]->mLevel == 2) 
				#endif
				{
					if(m_pStationList[i]->m_pButton == NULL) {
						m_pStationList[i]->m_pButton = new CTouchButton;
						m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
					}
					m_pStationList[i]->m_pButton->m_strName = m_pStationList[i]->mNickName + L"상황실";
					m_pStationList[i]->mBtnPosX = 0;
					m_pStationList[i]->mBtnPosY = 0;
					m_pStationList[i]->mSubCount = 0;
					m_pStationList[i]->mBtnGroupRow = iGrpRow;
					
					m_pStationList[i]->m_pButton->m_iBtnFlag |= TOUCH_BTN_FLAG_CHECKABLE;
					m_pStationList[i]->mGroupBox.left = -TBD_BTN_SUB_MARGIN_X;
					m_pStationList[i]->mGroupBox.top = -TBD_BTN_SUB_MARGIN_Y;
						//m_pStationList[i]->mGroupBox.right = TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
					m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (i_sub_column_size - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
					m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + TBD_BTN_SUB_MARGIN_Y;

					iGrpRow++;
					iSubGrpIdx++;
				}

				if(m_pStationList[i]->mLevel == 3) 
				{
					if(m_pStationList[i]->m_pButton == NULL) {
						m_pStationList[i]->m_pButton = new CTouchButton;
						m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
					}
					m_pStationList[i]->m_pButton->m_strName = m_pStationList[i]->mNickName;
					m_pStationList[i]->mBtnPosX = 0;
					m_pStationList[i]->mBtnPosY = (TBD_BTN_HEIGHT + 5) * iGrpRow  + TBD_BTN_GROUP_MARGIN_Y * iSubGrpIdx;
					m_pStationList[i]->mBtnGroupRow = iGrpRow;

					if(m_pStationList[i]->mSubCount > 0)
					{
						INT32 btnIdx = 0;
						for(INT32 j = 0;j < m_stationCount;j++) 
						{
							if(m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId) {

								INT32 row, column;
								row = btnIdx / i_sub_column_size;
								column = btnIdx % i_sub_column_size;

								if(m_pStationList[j]->m_pButton == NULL) {
									m_pStationList[j]->m_pButton = new CTouchButton;
									m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
								}
								m_pStationList[j]->m_pButton->m_strName = m_pStationList[j]->mNickName;
								m_pStationList[j]->mBtnPosX = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * column;
								m_pStationList[j]->mBtnPosY = (TBD_BTN_HEIGHT + 5) * (iGrpRow + row) + TBD_BTN_GROUP_MARGIN_Y * iSubGrpIdx;
								m_pStationList[j]->mBtnGroupRow = iGrpRow;
								m_pStationList[j]->m_pButton->m_bVisible = false;

								btnIdx++;
							}
						}

						m_pStationList[i]->m_pButton->m_iBtnFlag |= TOUCH_BTN_FLAG_CHECKABLE;
						m_pStationList[i]->mGroupBox.left = -TBD_BTN_SUB_MARGIN_X;
						m_pStationList[i]->mGroupBox.top = -TBD_BTN_SUB_MARGIN_Y;
						if(m_pStationList[i]->mSubCount < i_sub_column_size) {	
								//m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (m_pStationList[i]->mSubCount - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
							m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (i_sub_column_size - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
							m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + TBD_BTN_SUB_MARGIN_Y;
						} else {
							m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (i_sub_column_size - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
							m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + (TBD_BTN_HEIGHT + 5) * ((m_pStationList[i]->mSubCount - 1) / i_sub_column_size) + TBD_BTN_SUB_MARGIN_Y;
						}

						iGrpRow += ((btnIdx - 1) / i_sub_column_size) + 1;
						iSubGrpIdx++;
					} else {
						m_pStationList[i]->m_pButton->m_iBtnFlag |= TOUCH_BTN_FLAG_CHECKABLE;
						m_pStationList[i]->mGroupBox.left = -TBD_BTN_SUB_MARGIN_X;
						m_pStationList[i]->mGroupBox.top = -TBD_BTN_SUB_MARGIN_Y;
							//m_pStationList[i]->mGroupBox.right = TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
						m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + (TBD_BTN_WIDTH + 10) * (i_sub_column_size - 1) + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
						m_pStationList[i]->mGroupBox.bottom = TBD_BTN_HEIGHT + TBD_BTN_SUB_MARGIN_Y;

						iGrpRow++;
						iSubGrpIdx++;
					}
				}

				if (iGroupRowCount > 12) {
					if ((m_pStationList[i]->mSubCount < 1 && m_pStationList[i]->mBtnGroupRow == 0) || iGrpRow > 12) {
						//m_pStationList[i]->mGroupBox.right = TBD_BTN_SUB_START_X + TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;
						m_pStationList[i]->mGroupBox.right = TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X;

						if (iGrpRow > 12 && m_pStationList[i]->mLevel <= 3) {
							INT32 rowIndex = -1;
							for (INT32 j = 0; j < m_stationCount; j++)
							{
								if (m_pStationList[j]->mGroupIdx == iGrp && m_pStationList[j]->mBtnGroupRow < iGrpRow && m_pStationList[j]->mSubCount < 2) {
									BOOL exist = false;
									for (INT32 k = 0; k < m_stationCount; k++) {
										if (m_pStationList[k]->mBtnShiftRow == m_pStationList[j]->mBtnGroupRow) {
											exist = true;
											break;
										}
									}
									if (!exist) {
										rowIndex = m_pStationList[j]->mBtnGroupRow;
										break;
									}
								}
							}

							if (rowIndex >= 0) {
								m_pStationList[i]->mBtnShiftRow = rowIndex;
								//m_pStationList[i]->mBtnPosX += 648;
								//m_pStationList[i]->mBtnPosY = (TBD_BTN_HEIGHT + 5) * rowIndex + TBD_BTN_GROUP_MARGIN_Y * rowIndex;
								m_pStationList[i]->mBtnPosX += (TBD_BTN_WIDTH + TBD_BTN_SUB_MARGIN_X * 3) * (rowIndex + 1);
								m_pStationList[i]->mBtnPosY = 0;

								for (INT32 j = 0; j < m_stationCount; j++)
								{
									if (m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId) {
										m_pStationList[j]->mBtnPosX += 648;
										m_pStationList[j]->mBtnShiftRow = rowIndex;
										m_pStationList[j]->mBtnPosY = (TBD_BTN_HEIGHT + 5) * (rowIndex) + TBD_BTN_GROUP_MARGIN_Y * rowIndex;
									}
								}
							}
						}
					}
				}
			}

		}

#endif
	}
}

void CTouchBoardDlg::UpdateTouchButtonList()
{
	int idx = 0;
	int row, column;
	
	int column_cut_base = 9;
	int column_count = (m_iGroupBtnCount + 1) / 2;
	double btn_width = TBD_BTN_WIDTH;
	int grp_btn_height = TBD_BTN_HEIGHT;
	int grp_btn_start_y = TBD_BTN_GROUP_START_Y;
	int grp_btn_padding = 10;

	if (m_bIsFullHD) {
		column_cut_base = 14;
	}

#if TBD_USE_THREELINE_GROUP == 1
#if USE_ROUND_BUTTON2
	if(column_count <= column_cut_base) {
		//btn_width *= ((double)(10.0 - (column_count - 6) * 1.5) / 10.0);
		if (m_bIsFullHD) {
			//btn_width = (double)1538.0 / (double)column_count;
			btn_width = (double)1664.0 / (double)column_count;
			grp_btn_height *= 1.1;
			grp_btn_start_y *= 0.88;
		} else {
			//btn_width = 940 / column_count;
			btn_width = 1024.0 / column_count;
			grp_btn_height *= 1.1;
			grp_btn_start_y *= 0.88;
			if (btn_width > TBD_BTN_WIDTH)
				btn_width = TBD_BTN_WIDTH;
		}

	} else if(column_count > column_cut_base) {
		column_count = column_cut_base;
		//btn_width *= ((double)(10.0 - (column_count - 6) * 1.5) / 10.0);
		//btn_width = 940 / column_count;
		btn_width = 1024.0 / column_count;
		if (btn_width > TBD_BTN_WIDTH)
			btn_width = TBD_BTN_WIDTH;
		grp_btn_padding = 5;
		grp_btn_height *= 0.9;
		grp_btn_start_y *= 0.78;
	}
#else
	if (column_count <= 7) {
		//btn_width *= ((double)(10.0 - (column_count - 6) * 1.5) / 10.0);
		btn_width = 900 / column_count;
		if (btn_width > TBD_BTN_WIDTH)
			btn_width = TBD_BTN_WIDTH;

	}
	else if (column_count > 7) {
		column_count = 7;
		//btn_width *= ((double)(10.0 - (column_count - 6) * 1.5) / 10.0);
		btn_width = 900 / column_count;
		if (btn_width > TBD_BTN_WIDTH)
			btn_width = TBD_BTN_WIDTH;
		grp_btn_padding = 5;
		grp_btn_height *= 0.9;
		grp_btn_start_y *= 0.78;
	}
#endif


#else
	if(column_count > 6) {
		btn_width *= ((double)(10 - (column_count - 6) * 1.5) / 10.0);
	}
#endif

	row = 0;
	column = 0;
	for(INT32 i = 0;i < m_stationCount;i++)
	{
		if(m_pStationList[i]->mLevel == 2)
		{
			row = idx / column_count;
			column = idx % column_count;
			if(m_pGroupBtn[idx]) {
				m_pGroupBtn[idx]->DestroyWindow();
				delete m_pGroupBtn[idx];
				m_pGroupBtn[idx] = NULL;
			}
			m_pGroupBtn[idx] = new CTouchButton;
			m_pGroupBtn[idx]->m_pFont = &m_castFont;
			m_pGroupBtn[idx]->m_iBtnType = TOUCH_BTN_TYPE_GROUP;
			m_pGroupBtn[idx]->m_uiPressMessage = WM_TBD_GROUP_PUSH;
			m_pGroupBtn[idx]->m_strName = m_pStationList[i]->mNickName;
			m_pGroupBtn[idx]->initialize((double)TBD_BTN_GROUP_START_X + (btn_width) * (double)column, grp_btn_start_y + (grp_btn_height + grp_btn_padding) * row, btn_width - 10, grp_btn_height, 0, 0, m_pStationList[i]->mWardId, this);
			idx++;
		}

		if(m_pStationList[i]->m_pButton)
		{
			if(m_pStationList[i]->mStationId == 0)
				m_pStationList[i]->m_pButton->m_bPressable = false;

			if(m_pStationList[i]->mNickName.GetLength() < 10)
				m_pStationList[i]->m_pButton->m_pFont = &m_btnFont;
			else 
				m_pStationList[i]->m_pButton->m_pFont = &m_btnSmallFont;
			m_pStationList[i]->m_pButton->m_pFontSub = &m_btnUnderFont;
			m_pStationList[i]->m_pButton->initialize(TBD_BTN_SUB_START_X + m_pStationList[i]->mBtnPosX, TBD_BTN_SUB_START_Y + m_pStationList[i]->mBtnPosY, TBD_BTN_WIDTH, TBD_BTN_HEIGHT, 0/*TBD_BTN_ICON_WIDTH*/, 0/*TBD_BTN_ICON_HEIGHT*/, m_pStationList[i]->mWardId, this);
			m_pStationList[i]->m_pButton->ShowWindow(SW_HIDE);
		}
	}
	
	Invalidate(false);
}

void CTouchBoardDlg::MoveWindowDirection(CWnd *pWnd, INT32 xpos, INT32 ypos)
{
	CRect rt;

	pWnd->GetWindowRect(&rt);
	pWnd->GetParent()->ScreenToClient(rt);

	rt.left += xpos;
	rt.top += ypos;
	rt.right += xpos;
	rt.bottom += ypos;
	pWnd->MoveWindow(&rt);
	pWnd->Invalidate(FALSE);
}

static int findNumberFromString(char *pString)
{
    int len; 
    int i;
    int value = -1;
    if(pString == NULL)
        return -1;

    len = strlen(pString);
    for(i = 0;i < len;i++) {
        if(pString[i] >= '0' && pString[i] <= '9') {
            value = atoi(&pString[i]);
            break;
        }    
    }    

    return value;
}


INT32 CTouchBoardDlg::PacketDizest(char *pBuffer)
{
	char *pData;
	char *pToken;
	char *pTokenSub;
	char *pTokenNext;

	INT32 station_idx = -1;
	INT32 command = 0;
	INT32 subIndex = 0;
	INT32 launcherIdx = 0;

#if USE_DO_PACKET_DUMP
	static int packetCount = 0;
	char packetFile[128];
	sprintf(packetFile, "packet-%03d.txt", packetCount);
	packetCount++;
	FILE *fp;
	fp = fopen(packetFile, "wt");
	if (fp) {
		fwrite(pBuffer, 1, strlen(pBuffer), fp);
		fclose(fp);
	}
#endif

	pToken = strstr(pBuffer, "\r\n\r\n");
	if(!pToken)
		return 0;
	INT32 len = ((INT32)(pToken - pBuffer)) + 4;

	pData = new char[len + 1];
	ZeroMemory(pData, len + 1);
	memcpy(pData, pBuffer, len);

	pToken = pData;

	m_infoMutex.Lock();
	while((pTokenNext = strstr(pToken, "\r\n")))
	{
		*pTokenNext = 0;

		if(!strncmp(pToken, "MESSAGE_TYPE=", strlen("MESSAGE_TYPE=")))
		{
			pToken += strlen("MESSAGE_TYPE=");

			if(!strcmp(pToken, "INFORM-STATIONS")) {
				TRACE("Handle INFORM-STATIONS. %d bytes.\n", len);
				command = TBD_SERVER_COMMAND_STATION_INFORM;
				station_idx = 0;
				m_iGroupBtnCount = 0;
			} else if(!strcmp(pToken, "NOTIFY")) {
				TRACE("Handle NOTIFICATION. %d bytes.\n", len);
				command = TBD_SERVER_COMMAND_STATION_NOTIFY;
				m_strWardId = "";
			} else if(!strcmp(pToken, "CAST_STATUS")) {
				command = TBD_SERVER_COMMAND_CAST_STATUS;
			} else if(!strcmp(pToken, "DEVICE_STATUS")) {
				command = TBD_SERVER_COMMAND_DEVICE_STATUS;
			}
		}
		else if(!strncmp(pToken, "POSITION=", strlen("POSITION=")))
		{
			pToken += strlen("POSITION=");
		}
		else if(!strncmp(pToken, "MIC_VOLUME=", strlen("MIC_VOLUME=")))
		{
			pToken += strlen("MIC_VOLUME=");
			CString strValue;
			strValue = pToken;
			m_setupDlg.GetDlgItem(IDC_STATIC_MICVOL_VALUE)->SetWindowTextW(strValue + L"/12");
		}
		else if(!strncmp(pToken, "LINEIN_VOLUME=", strlen("LINEIN_VOLUME=")))
		{
			pToken += strlen("LINEIN_VOLUME=");
			CString strValue;
			strValue = pToken;
			m_setupDlg.GetDlgItem(IDC_STATIC_LINEVOL_VALUE)->SetWindowTextW(strValue + L"/12");
		}		
		else if(!strncmp(pToken, "SPK_VOLUME=", strlen("SPK_VOLUME=")))
		{
			pToken += strlen("SPK_VOLUME=");
			CString strValue;
			INT32 curValue, maxValue, ret;
			strValue = pToken;
			ret = sscanf(pToken, "%d/%d", &curValue, &maxValue);
			if(ret == 1) {
				strValue = curValue + L"/15";
			}
			GetDlgItem(IDC_STATIC_SPKVOL_VALUE)->SetWindowTextW(strValue);
		}

		switch(command)
		{
			case TBD_SERVER_COMMAND_STATION_INFORM:
				if(!strncmp(pToken, "WID_", strlen("WID_"))) {
					if(m_pStationList[station_idx] == NULL) {
						m_pStationList[station_idx] = new CStationInfo;
						m_pStationList[station_idx]->m_pButton = NULL;
					}
					pTokenSub = strchr(pToken, '=');
					m_pStationList[station_idx]->mGroupIdx = atoi(pToken + strlen("WID_"));
					m_pStationList[station_idx]->mWardId = atoi(pTokenSub + 1);
					m_pStationList[station_idx]->mLevel = 2;
					m_pStationList[station_idx]->mUpWardId = 0;
					m_pStationList[station_idx]->mSubCount = 0;
					m_pStationList[station_idx]->mSubGroupId = 0;
					m_pStationList[station_idx]->mBtnShiftRow = -1;
					if(m_iGroupBtnCount < TBD_MAX_GROUP_COUNT)		// added by ritoseo - 2022-01-20
						m_iGroupBtnCount++;
					TRACE(L"WARD ID : %d\n", m_pStationList[station_idx]->mWardId);
				} else if(!strncmp(pToken, "NICK_", strlen("NICK_"))) {
					int ret, index;
					char strDummy[128];
					UTF8_CONVERSION_EX;
					pTokenSub = strchr(pToken, '=');
					ret = sscanf(pTokenSub + 1, "%d.%s", &index, strDummy);
					if(ret == 2) {
						m_pStationList[station_idx]->mNickName = UTF82A_EX(strDummy);
						m_pStationList[station_idx]->mNickIndex = index;
					} else {
						m_pStationList[station_idx]->mNickIndex = -1;
						m_pStationList[station_idx]->mNickName = UTF82A_EX(pTokenSub + 1);
					}
				} else if(!strncmp(pToken, "IPADDR_", strlen("IPADDR_"))) {
					pTokenSub = strchr(pToken, '=');
					m_pStationList[station_idx]->mIpAddr = (pTokenSub + 1);
				} else if(!strncmp(pToken, "SID_", strlen("SID_"))) {
					pTokenSub = strchr(pToken, '=');
					m_pStationList[station_idx]->mStationId = atoi(pTokenSub + 1);
				} else if(!strncmp(pToken, "FIN", strlen("FIN"))) {
					station_idx++;
				} else if(!strncmp(pToken, "START", strlen("START"))) {
				} else if(!strncmp(pToken, "END", strlen("END"))) {
					m_stationCount = station_idx;
					UpdateSubGroupList();
					CalcButtonPositioning();
					AfxGetMainWnd()->PostMessage(WM_TBD_UPDATE_GROUP);
					//UpdateTouchButtonList();
					TRACE(L"Total Station Count : %d\n", m_stationCount);

					CString strOrder;
					strOrder = "BYPASS\r\n";
					strOrder += "REQUEST=CAST_STATUS\r\n";
					strOrder += "CVI_NO="; 
					strOrder += m_strCviNo; 
					strOrder += "\r\n";
					strOrder += "\r\n";

					char *pSendBuffer;
					UTF8_CONVERSION_EX;
					pSendBuffer = W2UTF8_EX(strOrder);
					SocketSendExceptionHandle(pSendBuffer, strlen(pSendBuffer));
				} else if(!strncmp(pToken, "SUB_", strlen("SUB_"))) {
					pTokenSub = strstr(pToken, "::");
					int grpIdx = atoi(pToken + strlen("SUB_"));

					pToken = pTokenSub + 2;
					if(!strncmp(pToken, "WID_", strlen("WID_"))) {
						if(m_pStationList[station_idx] == NULL) {
							m_pStationList[station_idx] = new CStationInfo;
							m_pStationList[station_idx]->m_pButton = NULL;
						}
						pTokenSub = strchr(pToken, '=');
						m_pStationList[station_idx]->mGroupIdx = grpIdx;
						m_pStationList[station_idx]->mWardId = atoi(pTokenSub + 1);
						m_pStationList[station_idx]->mSubCount = 0;
						m_pStationList[station_idx]->mBtnShiftRow = -1;
						//TRACE(L"SUB WARD ID : %d\n", m_pStationList[station_idx]->mWardId);
					} else if(!strncmp(pToken, "NICK_", strlen("NICK_"))) {
						int ret, index;
						char strDummy[128];
						UTF8_CONVERSION_EX;
						pTokenSub = strchr(pToken, '=');
						ret = sscanf(pTokenSub + 1, "%d.%s", &index, strDummy);
						if(ret == 2) {
							m_pStationList[station_idx]->mNickName = UTF82A_EX(strDummy);
							m_pStationList[station_idx]->mNickIndex = index;
						} else {
							m_pStationList[station_idx]->mNickIndex = -1;
							m_pStationList[station_idx]->mNickName = UTF82A_EX(pTokenSub + 1);
						}
					} else if(!strncmp(pToken, "IPADDR_", strlen("IPADDR_"))) {
						pTokenSub = strchr(pToken, '=');
						m_pStationList[station_idx]->mIpAddr = (pTokenSub + 1);
					} else if(!strncmp(pToken, "SID_", strlen("SID_"))) {
						pTokenSub = strchr(pToken, '=');
						m_pStationList[station_idx]->mStationId = atoi(pTokenSub + 1);
					} else if(!strncmp(pToken, "LV_", strlen("LV_"))) {
						pTokenSub = strchr(pToken, '=');
						m_pStationList[station_idx]->mLevel = atoi(pTokenSub + 1);
						if(m_pStationList[station_idx]->mLevel == 2 || m_pStationList[station_idx]->mLevel == 3)
							m_pStationList[station_idx]->mSubGroupId = m_pStationList[station_idx]->mWardId;
					} else if(!strncmp(pToken, "UWID_", strlen("UWID_"))) {
						pTokenSub = strchr(pToken, '=');
						m_pStationList[station_idx]->mUpWardId = atoi(pTokenSub + 1);
					} else if(!strncmp(pToken, "FIN", strlen("FIN"))) {
						station_idx++;
					}
				}
				break;

			case TBD_SERVER_COMMAND_STATION_NOTIFY:
				if(!strncmp(pToken, "DEVICE_NAME=", strlen("DEVICE_NAME="))) {
					UTF8_CONVERSION_EX;
					pToken += strlen("DEVICE_NAME=");
					m_strDeviceName = UTF82A_EX(pToken);
					TRACE("RECEIVE DEVICE NAME : %s\n", pToken);
					
					CString strName;
					GetDlgItem(IDC_BUTTON_NAME)->GetWindowTextW(strName);
					if(strName != m_strDeviceName) {
						GetDlgItem(IDC_BUTTON_NAME)->SetWindowTextW(m_strDeviceName);
					}

					Invalidate(false);
				} else if(!strncmp(pToken, "CVI_NO=", strlen("CVI_NO="))) {
					UTF8_CONVERSION_EX;
					pToken += strlen("CVI_NO=");
					m_strCviNo = UTF82A_EX(pToken);
				} else if(!strncmp(pToken, "WARD_ID=", strlen("WARD_ID="))) {
					UTF8_CONVERSION_EX;
					pToken += strlen("WARD_ID=");
					m_strWardId = UTF82A_EX(pToken);
				} 
				break;

			case TBD_SERVER_COMMAND_CAST_STATUS:
				if(!strncmp(pToken, "SID_", strlen("SID_"))) {
					char *pTokenSub = strchr(pToken, '=');
					pToken += strlen("SID_");
					INT32 station_id = atoi(pToken);
					INT32 status = atoi(pTokenSub + 1);
					INT32 caller_desk_id = -1;
					INT32 caller_cvi_no = -1;
					INT32 my_desk_id = -1;
					INT32 button_pushed = -1;

					if(m_strWardId.GetLength() == 0 && m_strDeviceName.GetLength() > 0) {
						UTF8_CONVERSION_EX;
						char *strDeviceName;
						strDeviceName = W2UTF8_EX(m_strDeviceName);
						my_desk_id = findNumberFromString(strDeviceName);
					}

					pTokenSub = strchr(pToken, '|');
					if(pTokenSub) {
						caller_desk_id = atoi(pTokenSub + 1);
						pTokenSub = strchr(pTokenSub, ',');
						if(pTokenSub) {
							caller_cvi_no = atoi(pTokenSub + 1);
						}

						pTokenSub = strchr(pToken, '/');
						if(pTokenSub) {
							button_pushed = atoi(pTokenSub + 1);
						}
					}

					for(INT32 i = 0;i < m_stationCount;i++)
					{
						if(m_pStationList[i]->mStationId == station_id && station_id > 0) {
							if(status > 0) {
								for(INT32 j = 0;j < 4;j++)
									m_pStationList[i]->m_pButton->m_bStatus[j] = FALSE;
								m_pStationList[i]->m_pButton->m_bStatus[status - 1] = TRUE;
								if(button_pushed == 1) {
									m_pStationList[i]->m_pButton->m_bStatus[4] = TRUE;
								}
								m_pStationList[i]->mCallerNo = caller_desk_id;
								if(m_pStationList[i]->mCallerCviNo == -1 && caller_cvi_no == _ttoi(m_strCviNo) && caller_cvi_no > 0) {    // CT로 새 방송 연결시 그룹 자동 절체
									if(m_iSelectGroup != m_pStationList[i]->mGroupIdx 
										&& m_pStationList[i]->mGroupIdx < TBD_MAX_GROUP_COUNT
										&& m_pGroupBtn[m_pStationList[i]->mGroupIdx]) {
										AfxGetMainWnd()->PostMessage(WM_TBD_GROUP_PUSH, m_pGroupBtn[m_pStationList[i]->mGroupIdx]->m_btnId);
									}
								}

								m_pStationList[i]->mCallerCviNo = caller_cvi_no;
								m_pStationList[i]->m_pButton->m_iUnderNumber = caller_desk_id;		// CT수부대 연결의 경우 수부대 번호 표시
								
								if(my_desk_id == caller_desk_id)							// CT가 수부대이고 송신자가 자신인 경우 하단번호 표시 X(이모티콘표시)
									m_pStationList[i]->m_pButton->m_iUnderNumber = -1;
								
								if(my_desk_id > 0 && caller_desk_id == -1 && caller_cvi_no) { // 수보대에서 서자체방송 상태확인
									m_pStationList[i]->m_pButton->m_iUnderNumber = 0;		// 0 : "서" 표시
								}
								
								if(my_desk_id == -1 && button_pushed == 1)							// CT자신이 소방서이고 출동터치가 올라온 경우 터치상황 표시
									m_pStationList[i]->m_pButton->m_iUnderNumber = -1;

								if(m_pStationList[i]->m_pButton->GetSafeHwnd() > 0)
									m_pStationList[i]->m_pButton->Invalidate(FALSE);
							} else {
								for(INT32 j = 0;j < 5;j++)
									m_pStationList[i]->m_pButton->m_bStatus[j] = FALSE;
								m_pStationList[i]->m_pButton->m_iUnderNumber = -1;
								m_pStationList[i]->mCallerNo = -1;
								m_pStationList[i]->mCallerCviNo = -1;
								if(m_pStationList[i]->m_pButton->GetSafeHwnd() > 0)
									m_pStationList[i]->m_pButton->Invalidate(FALSE);
							}
						}
					}
					//m_logEdit.Trace(L"STATION %d = %d, deskid : %d, cvino : %d", station_id, status, caller_desk_id, caller_cvi_no);
				}
				break;

			case TBD_SERVER_COMMAND_DEVICE_STATUS:
				if(!strncmp(pToken, "SID_", strlen("SID_"))) {
					char *pTokenSub = strchr(pToken, '=');
					pToken += strlen("SID_");
					INT32 station_id = atoi(pToken);
					INT32 status = atoi(pTokenSub + 1);

					for(INT32 i = 0;i < m_stationCount;i++)
					{
						if(m_pStationList[i]->mStationId == station_id && station_id > 0) {
							if(status > 0) {
								m_pStationList[i]->m_pButton->m_bEnabled = TRUE;
							} else {
								m_pStationList[i]->m_pButton->m_bEnabled = FALSE;
							}
							
							if(m_pStationList[i]->m_pButton->GetSafeHwnd() != 0)
								m_pStationList[i]->m_pButton->Invalidate(FALSE);
						}
					}
					//m_logEdit.Trace(L"STATION %d = %d", station_id, status);
				}
				break;

			default:
				break;
		}

		pToken = pTokenNext + 2;
	}
	m_infoMutex.Unlock();

	switch(command)
	{
		case TBD_SERVER_COMMAND_CAST_STATUS:
			break;
		case TBD_SERVER_COMMAND_STATION_NOTIFY:
			if(m_strWardId.GetLength() == 0)		// 접수대. 전체 버튼 추가
			{ 
				INT32 offset = 50;
				if(!GetDlgItem(IDC_BUTTON_CAST_WHOLE)->IsWindowVisible())
				{
					GetDlgItem(IDC_BUTTON_CAST_WHOLE)->ShowWindow(SW_SHOW);

					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_WHOLE), 0, offset - 15);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_ALL), 0, offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_FIRE), 0, offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_RESCUE), 0, offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_EMERGENCY), 0, offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_NORMAL), 0, offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_RESTORE), 0, offset);
				}
			} 
			else // 소방서 CT. 전체 버튼 숨김
			{
				INT32 offset = 50;
				if(GetDlgItem(IDC_BUTTON_CAST_WHOLE)->IsWindowVisible())
				{
					GetDlgItem(IDC_BUTTON_CAST_WHOLE)->ShowWindow(SW_HIDE);

					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_WHOLE), 0, -(offset - 15));
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_ALL), 0, -offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_FIRE), 0, -offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_RESCUE), 0, -offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_EMERGENCY), 0, -offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_CAST_NORMAL), 0, -offset);
					MoveWindowDirection(GetDlgItem(IDC_BUTTON_RESTORE), 0, -offset);
				}
			}
			break;
		default:
			break;
	}

	delete pData;

	return len;
}


UINT CTouchBoardDlg::PingCheckThread(LPVOID aParam)
{
	CTouchBoardDlg *pThis = (CTouchBoardDlg *)aParam;
	ULONGLONG ullTryTime = 0;
	ULONGLONG ullCurTime = 0;

	while (pThis->m_bIsActive)
	{
		ULONGLONG curTickTime = GetTickCount64();

		ullCurTime = GetTickCount64();
		if (pThis->m_strPSAddr.GetLength() > 0 && ullCurTime - ullTryTime > 1000)
		{
			char ipAddr[32] = { 0, };
			INT32 port;
			SOCKET sock;
			pThis->WideToMultiByte(pThis->m_strPSAddr, ipAddr);
			BOOL result = CheckPing(ipAddr);
			if (!result) {
				pThis->m_pStatusButton[0]->SetColor(RGB(0, 0, 0), RGB(255, 0, 0));
			} else {
				pThis->m_pStatusButton[0]->SetColor(RGB(0, 0, 0), STATUS_BTN_GOOD_BACK_COLOR);
			}	
		}

		if (pThis->m_strESAddr.GetLength() > 0 && ullCurTime - ullTryTime > 1000)
		{
			char ipAddr[32] = { 0, };
			INT32 port;
			SOCKET sock;
			pThis->WideToMultiByte(pThis->m_strESAddr, ipAddr);
			BOOL result = CheckPing(ipAddr);

			if (!result) {
				pThis->m_pStatusButton[1]->SetColor(RGB(0, 0, 0), RGB(255, 0, 0));
			}
			else {
				pThis->m_pStatusButton[1]->SetColor(RGB(0, 0, 0), STATUS_BTN_GOOD_BACK_COLOR);
			}
		}

		if (ullCurTime - ullTryTime > 2000) {
			ullTryTime = ullCurTime;
		}

		Sleep(10);
	}

	return 0;
}


UINT CTouchBoardDlg::SocketConnectionThread(LPVOID aParam) 
{
	CTouchBoardDlg *pThis = (CTouchBoardDlg *)aParam;
	ULONGLONG ullTryTime = 0;
	ULONGLONG ullCurTime = 0;

	while(pThis->m_bIsActive)
	{
		ULONGLONG curTickTime = GetTickCount64();

		pThis->m_sockMutex.Lock();
		ullCurTime = GetTickCount64();
		if(pThis->m_sock == INVALID_SOCKET && pThis->m_strServerAddr.GetLength() > 0 && ullCurTime - ullTryTime > 2000)
		{
			char ipAddr[32] = {0, };
			INT32 port;
			SOCKET sock;
			pThis->WideToMultiByte(pThis->m_strServerAddr, ipAddr);
			ullTryTime = ullCurTime;

			ZeroMemory(&pThis->m_recvBuffer, sizeof(pThis->m_recvBuffer));
			pThis->m_recvSize = 0;
			pThis->m_sendSize = 0;
			port = pThis->m_port;
			
			pThis->m_sockMutex.Unlock();
			sock = pThis->ConnectRequest(ipAddr, port);
			pThis->m_sockMutex.Lock();

			pThis->m_sock = sock;
			if(pThis->m_sock == INVALID_SOCKET) {
				pThis->m_logEdit.Trace(L"[%s] CT 접속 실패", pThis->m_strServerAddr);
				pThis->m_pStatusButton[2]->SetColor(RGB(0, 0, 0), RGB(255, 0, 0));
			} else {
				pThis->m_logEdit.Trace(L"[%s] CT 접속 성공", pThis->m_strServerAddr);
				pThis->m_pStatusButton[2]->SetColor(RGB(0, 0, 0), STATUS_BTN_GOOD_BACK_COLOR);
			}
		}
		pThis->m_sockMutex.Unlock();

		Sleep(10);
	}

	return 0;
}

UINT CTouchBoardDlg::SocketReceiveThread(LPVOID aParam) 
{
	CTouchBoardDlg *pThis = (CTouchBoardDlg *)aParam;
	INT size;
	ULONGLONG sendTickTime = 0;
	ULONGLONG ullTryTime = 0;
	ULONGLONG ullCurTime = 0;

	ZeroMemory(pThis->m_recvBuffer, TBD_RECV_BUFSIZE);
	pThis->m_recvSize = 0;

	while(pThis->m_bIsActive)
	{
		ULONGLONG curTickTime = GetTickCount64();

		pThis->m_sockMutex.Lock();
		if(pThis->m_sock != INVALID_SOCKET)
		{
			size = recv(pThis->m_sock, pThis->m_recvBuffer + pThis->m_recvSize, TBD_RECV_BUFSIZE - pThis->m_recvSize, 0);
			if(size > 0)
			{
				TRACE("Bytes received: %d\n", size);
				pThis->m_recvSize += size;
			}
			else if(size == 0)
			{
				TRACE("Connection Closed!\n");
				shutdown(pThis->m_sock, SD_BOTH);
				closesocket(pThis->m_sock);
				pThis->m_sock = INVALID_SOCKET;
				if(pThis->m_sock == INVALID_SOCKET) {
					/* TODO - Handle Exception
					*/
					pThis->m_logEdit.Trace(L"[%s] CT 연결이 끊어졌습니다. CODE[0]", pThis->m_strServerAddr);
				}
			}
			else 
			{
				int nError = WSAGetLastError();
				
				if(nError != WSAEWOULDBLOCK && nError != 0) 
				{
					TRACE("recv failed: %d\n", nError);
					shutdown(pThis->m_sock, SD_BOTH);
					closesocket(pThis->m_sock);
					pThis->m_sock = INVALID_SOCKET;
					pThis->m_logEdit.Trace(L"[%s] CT 연결이 끊어졌습니다. CODE[%d]", pThis->m_strServerAddr, nError);
				}
			}

			if(pThis->m_sendSize > 0)
			{
				int ret = pThis->SocketSend(pThis->m_sendBuffer, pThis->m_sendSize);
				if(ret > 0)
				{
					if(ret < pThis->m_sendSize) {
						memcpy(pThis->m_sendBuffer, pThis->m_sendBuffer + ret, pThis->m_sendSize - ret);
					}
					pThis->m_sendSize -= ret;
				} else if(ret == 0) {
					TRACE("Connection Closed!\n");
					shutdown(pThis->m_sock, SD_BOTH);
					closesocket(pThis->m_sock);
					pThis->m_sock = INVALID_SOCKET;
				} else if(ret < 0) {
					int nError = WSAGetLastError();
				
					if(nError != WSAEWOULDBLOCK && nError != 0) 
					{
						TRACE("recv failed: %d\n", nError);
						shutdown(pThis->m_sock, SD_BOTH);
						closesocket(pThis->m_sock);
						pThis->m_sock = INVALID_SOCKET;
						pThis->m_logEdit.Trace(L"[%s] CT 연결이 끊어졌습니다. CODE[%d]", pThis->m_strServerAddr, nError);
					}
				}
			}
		}

		if(curTickTime - sendTickTime > 2000) {
			char keepAlive[] = "KEEP_ALIVE\r\n\r\n";
			memcpy(pThis->m_sendBuffer + pThis->m_sendSize, keepAlive, strlen(keepAlive));
			pThis->m_sendSize += strlen(keepAlive);
			sendTickTime = curTickTime;
		}
		pThis->m_sockMutex.Unlock();

		ullCurTime = GetTickCount64();
		if(pThis->m_sock == INVALID_SOCKET && pThis->m_strServerAddr.GetLength() > 0 && ullCurTime - ullTryTime > 2000)
		{
			char ipAddr[32] = {0, };
			pThis->WideToMultiByte(pThis->m_strServerAddr, ipAddr);
			ullTryTime = ullCurTime;

			ZeroMemory(&pThis->m_recvBuffer, sizeof(pThis->m_recvBuffer));
			pThis->m_recvSize = 0;
			pThis->m_sendSize = 0;
			pThis->m_sock = pThis->ConnectRequest(ipAddr, pThis->m_port);
			if(pThis->m_sock == INVALID_SOCKET) {
				/* TODO - Handle Exception
				*/
				pThis->m_logEdit.Trace(L"[%s] CT 접속 실패", pThis->m_strServerAddr);
			} else {
				pThis->m_logEdit.Trace(L"[%s] CT 접속 성공", pThis->m_strServerAddr);
				sendTickTime = GetTickCount64();
			}
		}



		if(pThis->m_recvSize >= 4 && strstr(pThis->m_recvBuffer, "\r\n\r\n"))		// Packet is end with CR+LF+CR+LF
		{
			int ret = pThis->PacketDizest(pThis->m_recvBuffer);

			if(ret > 0 && pThis->m_recvSize > ret) {
				memcpy(pThis->m_recvBuffer, pThis->m_recvBuffer + ret, pThis->m_recvSize - ret);
			}
			if(ret > 0)
				pThis->m_recvSize -= ret;

			ZeroMemory(pThis->m_recvBuffer + pThis->m_recvSize, TBD_RECV_BUFSIZE - pThis->m_recvSize);
			//TRACE("RecvSize To: %d\n", pThis->m_recvSize);
		}

		Sleep(1);
	}

	if(pThis->m_sock != INVALID_SOCKET)
	{
		INT iResult = shutdown(pThis->m_sock, SD_BOTH);
		if (iResult == SOCKET_ERROR) {
			TRACE("listen socket shutdown failed: %d\n", WSAGetLastError());
		}
	}

	return 0;
}

void CTouchBoardDlg::WideToMultiByte(const wchar_t *src, char* dest)
 {
     int len = ::WideCharToMultiByte(CP_ACP, 0, src, -1, dest, 0, NULL, NULL);
     ::WideCharToMultiByte(CP_ACP, 0, src, -1, dest, len, NULL, NULL);
 }

 void CTouchBoardDlg::MultiByteToWide(const char* src, wchar_t *dest, int buffersize)
 {
     int len = ::MultiByteToWideChar(CP_ACP, 0, src, -1, dest, buffersize);
     ::MultiByteToWideChar(CP_ACP, 0, src, -1, dest, buffersize);
 }


 int CTouchBoardDlg::GetMonitorInformation(void)
{
	m_infoMonitor.nMonitor = ::GetSystemMetrics(SM_CMONITORS); 
	m_infoMonitor.bSameDisplayFormat = ::GetSystemMetrics(SM_SAMEDISPLAYFORMAT); 
	
	m_infoMonitor.rcVirtual.left = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
	m_infoMonitor.rcVirtual.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
	m_infoMonitor.rcVirtual.right = m_infoMonitor.rcVirtual.left + ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
	m_infoMonitor.rcVirtual.bottom = m_infoMonitor.rcVirtual.top + ::GetSystemMetrics(SM_CYVIRTUALSCREEN);

	m_infoMonitor.nWidth = ::GetSystemMetrics(SM_CXSCREEN);             // 모니터의 해상도 x
	m_infoMonitor.nHeight = ::GetSystemMetrics(SM_CYSCREEN);             // 모니터의 해상도 y
	m_infoMonitor.nWidthVirtual = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);             // 가상모니터의 해상도 x
	m_infoMonitor.nHeightVirtual = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);             // 가상모니터의 해상도 y
	
	m_infoMonitor.nMegaPixel = (m_infoMonitor.nWidth * m_infoMonitor.nHeight)/(1000*1000);
	m_infoMonitor.nMegaPixel = max(1,m_infoMonitor.nMegaPixel);
	
	return 0;
 }

 void CTouchBoardDlg::OnBnClickedButtonSetup()
 {
	 // TODO: Add your control notification handler code here
	 INT32 x, y;
	 RECT pos;
	 GetWindowRect(&pos);
	 if (m_bIsFullHD) {
		 x = pos.left + (1920 - TBD_SETUP_DLG_WIDTH) / 2;
		 y = pos.top + (1080 - TBD_SETUP_DLG_HEIGHT) / 2;
		 m_setupDlg.UpdateVariableToCtrl();
		 m_setupDlg.SetWindowPos(NULL, x, y, TBD_SETUP_DLG_WIDTH, TBD_SETUP_DLG_HEIGHT, 0);
	 }
	 else {
		 x = pos.left + (TBD_STANDARD_WIDTH - TBD_SETUP_DLG_WIDTH) / 2;
		 y = pos.top + (TBD_STANDARD_HEIGHT - TBD_SETUP_DLG_HEIGHT) / 2;
		 m_setupDlg.UpdateVariableToCtrl();
		 m_setupDlg.SetWindowPos(NULL, x, y, TBD_SETUP_DLG_WIDTH, TBD_SETUP_DLG_HEIGHT, 0);
	 }
	 m_setupDlg.ShowWindow(SW_SHOW);
 }


 void CTouchBoardDlg::OnDestroy()
 {
	CDialogEx::OnDestroy();

	 // TODO: Add your message handler code here

	if(m_sock != INVALID_SOCKET)
	{
		shutdown(m_sock, 2);
		closesocket(m_sock);
	}

	WSACleanup();

	for(int i = 0;i < m_stationCount;i++) {
		delete m_pStationList[i];
	}
}

void CTouchBoardDlg::UpdateSettingToVariable()
{
	m_sockMutex.Lock();
	m_strServerAddr.Format(L"%d.%d.%d.%d", m_setupDlg.m_ctAddr[0], m_setupDlg.m_ctAddr[1], m_setupDlg.m_ctAddr[2], m_setupDlg.m_ctAddr[3]);
	m_strESAddr.Format(L"%d.%d.%d.%d", m_setupDlg.m_esAddr[0], m_setupDlg.m_esAddr[1], m_setupDlg.m_esAddr[2], m_setupDlg.m_esAddr[3]);
	m_strPSAddr.Format(L"%d.%d.%d.%d", m_setupDlg.m_psAddr[0], m_setupDlg.m_psAddr[1], m_setupDlg.m_psAddr[2], m_setupDlg.m_psAddr[3]);
	m_port = 27879;
	m_sockMutex.Unlock();
}

afx_msg LRESULT CTouchBoardDlg::OnTbdSetupSave(WPARAM wParam, LPARAM lParam)
{
	if(wParam == 1) { /* Ip address is changed */
		if(m_sock != INVALID_SOCKET)
		{
			INT iResult = shutdown(m_sock, SD_BOTH);
			if (iResult == SOCKET_ERROR) {
				TRACE("listen socket shutdown failed: %d\n", WSAGetLastError());
			}

			closesocket(m_sock);
			m_sock = INVALID_SOCKET;
		}
	}
	UpdateSettingToVariable();
	return 0;
}

afx_msg LRESULT CTouchBoardDlg::OnTbdUpdateLevel2(WPARAM wParam, LPARAM lParam)
{
	UpdateTouchButtonList();

	/* CT의 WARDID가 존재하는 경우 속하는 소방서의 Default 그룹 선택 */
	if(m_strWardId.GetLength() > 0) {
		INT32 iWardId = _ttoi(m_strWardId);
		for(INT32 i = 0;i < m_stationCount;i++) {
			if(m_pStationList[i]->mWardId == iWardId) {
				m_iSelectGroup = m_pStationList[i]->mGroupIdx;
				break;
			}
		}
	}

	if(m_iSelectGroup == -1) {
		m_pGroupBtn[0]->PostMessage(WM_LBUTTONDOWN);
	} else {
		m_pGroupBtn[m_iSelectGroup]->PostMessage(WM_LBUTTONDOWN);
	}
	return 0;
}

afx_msg LRESULT CTouchBoardDlg::OnTbdLevel2Push(WPARAM wParam, LPARAM lParam)
{
	TRACE("PUSH : %d\n", wParam);
	INT32 grpIdx = -1;

	if(m_strWardId.GetLength() > 0) {
		INT32 iWardId = _ttoi(m_strWardId);
		INT32 iGroupIdx = -1;
		for(INT32 i = 0;i < m_stationCount;i++) {
			if(m_pStationList[i]->mWardId == iWardId) {
				iGroupIdx = m_pStationList[i]->mGroupIdx;
				break;
			}
		}

		for(INT32 i = 0;i < m_iGroupBtnCount;i++) {
			if(m_pGroupBtn[i]->m_btnId == wParam) {
				grpIdx = i;
				break;
			}
		}

		if(iGroupIdx != grpIdx)
			return 0;
	}

	for(INT32 i = 0;i < m_iGroupBtnCount;i++) {
		if(m_pGroupBtn[i]->m_btnId != wParam)
			m_pGroupBtn[i]->SetPressState(false);
		else {
			grpIdx = i;
			m_pGroupBtn[i]->SetPressState(true);
		}
	}

	m_iSelectGroup = grpIdx;
	//m_logEdit.Trace(L"HOHOHO : %d", m_iSelectGroup);

	for(INT32 i = 0;i < m_stationCount;i++) 
	{
		if(m_pStationList[i]->mGroupIdx == grpIdx)
		{
			if(m_pStationList[i]->m_pButton) 
			{
				m_pStationList[i]->m_pButton->ShowWindow(SW_SHOW);
			}
		}
		else
		{
			if(m_pStationList[i]->m_pButton) 
			{
				m_pStationList[i]->m_pButton->ShowWindow(SW_HIDE);
			}
		}
	}

	Invalidate(false);
	return 0;
}

BOOL CTouchBoardDlg::OnEraseBkgnd(CDC* pDC)
{
	// TODO: Add your message handler code here and/or call default

	//return false;

	return CDialogEx::OnEraseBkgnd(pDC);
}


void CTouchBoardDlg::OnBnClickedButtonCastAll()
{
	// TODO: Add your control notification handler code here
	RequestCastOrder(TBD_REQUEST_CAST_TYPE_ALL);
}


void CTouchBoardDlg::OnBnClickedButtonCastFire()
{
	// TODO: Add your control notification handler code here
	RequestCastOrder(TBD_REQUEST_CAST_TYPE_FIRE);
}


void CTouchBoardDlg::OnBnClickedButtonCastRescue()
{
	// TODO: Add your control notification handler code here
	RequestCastOrder(TBD_REQUEST_CAST_TYPE_RESQUE);
}


void CTouchBoardDlg::OnBnClickedButtonCastEmergency()
{
	// TODO: Add your control notification handler code here
	RequestCastOrder(TBD_REQUEST_CAST_TYPE_EMERGENCY);
}


void CTouchBoardDlg::OnBnClickedButtonCastNormal()
{
	// TODO: Add your control notification handler code here
	RequestCastOrder(TBD_REQUEST_CAST_TYPE_GENERAL);
}


void CTouchBoardDlg::OnBnClickedButtonRestore()
{
	// TODO: Add your control notification handler code here
		
	// 방송 종료 프로세스 
	TCHAR form[128];
	CString	strOrder; 
	strOrder = "BYPASS\r\n";
	strOrder += "CAST_ORDER=STOP\r\n";
	strOrder += "CVI_NO="; 
	strOrder += m_strCviNo; 
	strOrder += "\r\n";
	strOrder += "\r\n";

	char *pSendBuffer;
	UTF8_CONVERSION_EX;
	pSendBuffer = W2UTF8_EX(strOrder);
	SocketSendExceptionHandle(pSendBuffer, strlen(pSendBuffer));
	
#if 1
	for(INT32 i = 0;i < m_stationCount;i++) {
		if(m_pStationList[i]->m_pButton) {
			m_pStationList[i]->m_pButton->m_bChecked = FALSE;
			m_pStationList[i]->m_pButton->m_bPressed = FALSE;
			m_pStationList[i]->m_pButton->Invalidate(FALSE);
		}
	}

	Invalidate(FALSE);
#endif

}

void CTouchBoardDlg::RequestCastOrder(INT32 iCastType)
{
	CString strOrder;
	INT32 iSendCount = 0;
	BOOL *pbSelectList;

	pbSelectList = new BOOL[m_stationCount];
	ZeroMemory(pbSelectList, m_stationCount * sizeof(BOOL));

	if(iCastType == TBD_REQUEST_CAST_TYPE_ALL)				// 서일제방송
	{
		for(INT32 i = 0;i < m_stationCount;i++)
		{
			if(m_pStationList[i]->m_pButton && m_pStationList[i]->m_pButton->m_bEnabled && m_pStationList[i]->mGroupIdx == m_iSelectGroup) {
				pbSelectList[i] = true;
				//m_pStationList[i]->m_pButton->SetPressState(true);
			}
		}
	} 
	else if(iCastType == TBD_REQUEST_CAST_TYPE_WHOLE)		// 전체방송
	{
		for(INT32 i = 0;i < m_stationCount;i++)
		{
			if(m_pStationList[i]->mStationId > 0 && m_pStationList[i]->m_pButton && m_pStationList[i]->m_pButton->m_bEnabled) {
				pbSelectList[i] = true;
				//m_pStationList[i]->m_pButton->SetPressState(true);
			}
		}
	} 
	else 
	{
		for(INT32 i = 0;i < m_stationCount;i++)
		{
			// 그룹 체크 단말 리스트 처리
			if(m_pStationList[i]->m_pButton && m_pStationList[i]->m_pButton->m_bChecked && m_pStationList[i]->mSubCount > 0) {
				pbSelectList[i] = true;
				for(INT j = 0;j < m_stationCount;j++) {
					if(m_pStationList[j]->mUpWardId == m_pStationList[i]->mWardId) {
						pbSelectList[j] = true;
					}
				}
			}

			if(m_pStationList[i]->m_pButton && m_pStationList[i]->m_pButton->m_bPressed)
				pbSelectList[i] = true;
		}
	}

	for(INT32 i = 0;i < m_stationCount;i++) 
	{
		if(pbSelectList[i])
			iSendCount++;
	}

	if(iSendCount > 0)
	{
		CString dlgMessage;
		TCHAR form[128];
		strOrder = "BYPASS\r\n";

		if(iCastType == TBD_REQUEST_CAST_TYPE_FIRE) {
			strOrder += "COMMAND=FIRE\r\n";
			dlgMessage = L"화재방송중입니다";
		} else if(iCastType == TBD_REQUEST_CAST_TYPE_EMERGENCY) {
			strOrder += "COMMAND=EMERGENCY\r\n";
			dlgMessage = L"구급방송중입니다";
		} else if(iCastType == TBD_REQUEST_CAST_TYPE_GENERAL) {
			strOrder += "COMMAND=GENERAL\r\n";
			dlgMessage = L"기타방송중입니다";
		} else if(iCastType == TBD_REQUEST_CAST_TYPE_RESQUE) {
			strOrder += "COMMAND=RESCUSE\r\n";
			dlgMessage = L"구조방송중입니다";
		} else if(iCastType == TBD_REQUEST_CAST_TYPE_ALL) {
			//strOrder += "COMMAND=ALL\r\n";
			strOrder += "COMMAND=GENERAL\r\n";
			dlgMessage = L"서일제방송중입니다";
			iCastType = TBD_REQUEST_CAST_TYPE_GENERAL;
		} else if(iCastType == TBD_REQUEST_CAST_TYPE_WHOLE) {
			strOrder += "COMMAND=GENERAL\r\n";
			dlgMessage = L"전체방송중입니다";
			iCastType = TBD_REQUEST_CAST_TYPE_GENERAL;
		}

		wsprintf(form, L"STATION_COUNT=%d\r\n", iSendCount);
		strOrder += form;
		wsprintf(form, L"CAST_ORDER=MIC\r\n");
		strOrder += form;
		

		if(m_setupDlg.m_bSendTTS) {
			if(m_setupDlg.m_strTTSMessage.GetLength() > 0) {
				wsprintf(form, L"CAST_SOURCE=TTS\r\n");
				strOrder += form;
			}
		} 
		else if(m_setupDlg.m_bSendLineIn) {
			wsprintf(form, L"CAST_SOURCE=LINEIN\r\n");
			strOrder += form;
		}
		
		strOrder += "CVI_NO="; 
		strOrder += m_strCviNo; 
		strOrder += "\r\n";

		for(INT32 i = 0;i < m_stationCount;i++) {
			if(pbSelectList[i]) {
				wsprintf(form, L"STATION_ID=%d\r\n", m_pStationList[i]->mStationId);
				strOrder += form;
			}
		}
		strOrder += "\r\n";

		char *pSendBuffer;
		UTF8_CONVERSION_EX;
		pSendBuffer = W2UTF8_EX(strOrder);
		SocketSendExceptionHandle(pSendBuffer, strlen(pSendBuffer));

		for(INT32 i = 0;i < m_stationCount;i++) {
			if(pbSelectList[i]) {
				m_pStationList[i]->m_pButton->m_bChecked = FALSE;
				m_pStationList[i]->m_pButton->m_bPressed = FALSE;
				m_pStationList[i]->m_pButton->Invalidate(FALSE);
			}
		}
#if 0
		COnCastDlg dlg;
		dlg.m_strMessage = dlgMessage;
		dlg.DoModal();

		// 방송 종료 프로세스 
		strOrder = "BYPASS\r\n";
		strOrder += "CAST_ORDER=STOP\r\n";
		wsprintf(form, L"STATION_COUNT=%d\r\n", iSendCount);
		strOrder += form;
		strOrder += "CVI_NO="; 
		strOrder += m_strCviNo; 
		strOrder += "\r\n";
		for(INT32 i = 0;i < m_stationCount;i++) {
			if(pbSelectList[i]) {
				wsprintf(form, L"STATION_ID=%d\r\n", m_pStationList[i]->mStationId);
				strOrder += form;
			}
		}
		strOrder += "\r\n";
		pSendBuffer = W2UTF8_EX(strOrder);
		SocketSendExceptionHandle(pSendBuffer, strlen(pSendBuffer));

		for(INT32 i = 0;i < m_stationCount;i++) {
			if(pbSelectList[i]) {
				m_pStationList[i]->m_pButton->m_bChecked = FALSE;
				m_pStationList[i]->m_pButton->m_bPressed = FALSE;
				m_pStationList[i]->m_pButton->Invalidate(FALSE);
			}
		}
#endif

		Invalidate(FALSE);
	}

	delete pbSelectList;
}

ULONG CTouchBoardDlg::ProcIDFromWnd(HWND hwnd) 
{   
	ULONG idProc;   
	GetWindowThreadProcessId( hwnd, &idProc );   
	return idProc;   
}

HWND CTouchBoardDlg::GetWinHandle(ULONG pid) 
{   
	HWND tempHwnd = ::FindWindow(NULL,NULL); // 최상위 윈도우 핸들 찾기   
  
	while( tempHwnd != NULL )   
	{   
		if( ::GetParent(tempHwnd) == NULL ) 
			if( pid == ProcIDFromWnd(tempHwnd) )   
				return tempHwnd;   
		
		tempHwnd = ::GetWindow(tempHwnd, GW_HWNDNEXT);
	}   
	
	return NULL;   
} 

BOOL CTouchBoardDlg::EnumProcessAndFocus(CString processPath)
{
	DWORD aProcesses[1024], cbNeeded, cProcesses;
    unsigned int i;
	BOOL bFound = false;

    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
    {
        return false;
    }

    // Calculate how many process identifiers were returned.
    cProcesses = cbNeeded / sizeof(DWORD);

    // Print the name and process identifier for each process.
    for ( i = 0; i < cProcesses; i++ )
    {
        if( aProcesses[i] != 0 )
        {
			CString strPath;
            PrintProcessNameAndID( aProcesses[i], strPath );
			if(strPath == processPath) {
				HWND hwnd = GetWinHandle(aProcesses[i]);
				::BringWindowToTop(hwnd);
				::SetForegroundWindow(hwnd);
#if USE_ROUND_BUTTON2
#else
				::ShowWindow(hwnd, SW_SHOWMAXIMIZED);

				HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE |
                                   PROCESS_VM_READ,
                                   FALSE, aProcesses[i] );

				if(TerminateProcess(hProcess, 0))
				{
					unsigned long nCode; //프로세스 종료 상태
					GetExitCodeProcess(hProcess, &nCode);
				}
				CloseHandle( hProcess );
#endif
				bFound = true;
			}
        }
    }

	return bFound;
}

void CTouchBoardDlg::PrintProcessNameAndID(DWORD processID, CString& strPath)
{
    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

    // Get a handle to the process.
    HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | 
								   PROCESS_QUERY_LIMITED_INFORMATION |
                                   PROCESS_VM_READ,
                                   FALSE, processID );

    // Get the process name.
    if (NULL != hProcess )
    {
#if 0
		HMODULE hMod;
        DWORD cbNeeded;

        if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), 
             &cbNeeded) )
        {
            //GetModuleBaseName( hProcess, hMod, szProcessName, 
            //                   sizeof(szProcessName)/sizeof(TCHAR) );
			GetModuleFileNameEx( hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR));
			//GetProcessImageFileName(hProcess, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
        }
#else
		GetModuleFileNameEx(hProcess, NULL, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
#endif

		TRACE(TEXT("%s  (PID: %u)\n"), szProcessName, processID);
    }

    // Print the process name and identifier.
    //TRACE(TEXT("%s  (PID: %u)\n"), szProcessName, processID );
	strPath = szProcessName;
    // Release the handle to the process.
    CloseHandle( hProcess );
}

void CTouchBoardDlg::OnBnClickedButtonWireless()
{
	// TODO: Add your control notification handler code here
	if(m_setupDlg.m_strWirelessPath.GetLength() == 0)
		return;
	
	BOOL bRet = EnumProcessAndFocus(m_setupDlg.m_strWirelessPath);
	if (bRet)
		return;

	//if(bRet)
	//	return;
	
	TCHAR strPath[512];
	TCHAR strName[512];
	SHELLEXECUTEINFOW sei;
	ZeroMemory(&sei, sizeof(SHELLEXECUTEINFOW));
	sei.cbSize = sizeof(SHELLEXECUTEINFOW);

	int pos = m_setupDlg.m_strWirelessPath.ReverseFind('\\');
	if(pos >= 0) {
		wsprintf(strPath, L"%s", m_setupDlg.m_strWirelessPath.Left(pos));
		wsprintf(strName, L"%s", m_setupDlg.m_strWirelessPath.Mid(pos + 1));
		sei.lpFile = strName; 
		sei.lpDirectory = strPath;
		sei.nShow = SW_SHOWMAXIMIZED;
		sei.fMask = SEE_MASK_NOCLOSEPROCESS;
		sei.lpVerb = __T("open");
		BOOL result = ShellExecuteEx(&sei);
#if USE_ROUND_BUTTON2
#else
		if(result) {
			AfxPostQuitMessage(0);
		}
#endif
	}
}


void CTouchBoardDlg::OnBnClickedButtonCall()
{
	// TODO: Add your control notification handler code here
	if(m_setupDlg.m_strCallPath.GetLength() == 0)
		return;

	BOOL bRet = EnumProcessAndFocus(m_setupDlg.m_strCallPath);
	if(bRet)
		return;

	TCHAR strPath[512];
	TCHAR strName[512];
	SHELLEXECUTEINFOW sei;
	ZeroMemory(&sei, sizeof(SHELLEXECUTEINFOW));
	sei.cbSize = sizeof(SHELLEXECUTEINFOW);

	int pos = m_setupDlg.m_strCallPath.ReverseFind('\\');
	if(pos >= 0) {
		wsprintf(strPath, L"%s", m_setupDlg.m_strCallPath.Left(pos));
		wsprintf(strName, L"%s", m_setupDlg.m_strCallPath.Mid(pos + 1));
		sei.lpFile = strName; 
		sei.lpDirectory = strPath;
		sei.nShow = SW_SHOWMAXIMIZED;
		sei.fMask = SEE_MASK_NOCLOSEPROCESS;
		sei.lpVerb = __T("open");
		BOOL result = ShellExecuteEx(&sei);
#if USE_ROUND_BUTTON2
#else
		if(result) {
			AfxPostQuitMessage(0);
		}
#endif
	}
}


void CTouchBoardDlg::OnClose()
{
	// TODO: Add your message handler code here and/or call default
	m_bIsActive = false;

	KillTimer(TBD_TIMER_EVENT_SOCKET);
	
	if(m_sock != INVALID_SOCKET)
	{
		INT iResult = shutdown(m_sock, SD_BOTH);
		if (iResult == SOCKET_ERROR) {
			TRACE("listen socket shutdown failed: %d\n", WSAGetLastError());
		}

		closesocket(m_sock);
	}

    if(m_pReceiveThread)
		::WaitForSingleObject(m_pReceiveThread->m_hThread, INFINITE);

	CDialogEx::OnClose();
}


afx_msg LRESULT CTouchBoardDlg::OnTbdLogUpdate(WPARAM wParam, LPARAM lParam)
{
	m_logEdit.UpdateLogsToEdit();
	return 0;
}

afx_msg LRESULT CTouchBoardDlg::OnTbdSubGrouping(WPARAM wParam, LPARAM lParam)
{
	DWORD ward_id = wParam;
	BOOL bNextState = lParam;

	for(INT32 i = 0;i < m_stationCount;i++) {
		if(m_pStationList[i]->mWardId == ward_id || (m_pStationList[i]->mUpWardId == ward_id && m_pStationList[i]->mSubCount == 0)) {
			if(m_pStationList[i]->m_pButton->m_bEnabled)
				m_pStationList[i]->m_pButton->SetPressState(bNextState);
		}
	}

	return 0;
}


void CTouchBoardDlg::OnBnClickedButtonCastWhole()
{
	// TODO: Add your control notification handler code here

	RequestCastOrder(TBD_REQUEST_CAST_TYPE_WHOLE);
}


void CTouchBoardDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	
	if(nIDEvent == TBD_TIMER_EVENT_SOCKET)
	{
		INT size;
		static ULONGLONG sendTickTime = 0;
		static ULONGLONG ullTryTime = 0;
		ULONGLONG ullCurTime = 0;

		ULONGLONG curTickTime = GetTickCount64();
		m_sockMutex.Lock();
		if(m_sock != INVALID_SOCKET)
		{
			size = recv(m_sock, m_recvBuffer + m_recvSize, TBD_RECV_BUFSIZE - m_recvSize, 0);
			if(size > 0)
			{
				TRACE("Bytes received: %d\n", size);
				m_recvSize += size;
			}
			else if(size == 0)
			{
				TRACE("Connection Closed!\n");
				shutdown(m_sock, SD_BOTH);
				closesocket(m_sock);
				m_sock = INVALID_SOCKET;
				if(m_sock == INVALID_SOCKET) {
					/* TODO - Handle Exception
					*/
					m_logEdit.Trace(L"[%s] CT 연결이 끊어졌습니다. CODE[0]", m_strServerAddr);
				}
			}
			else 
			{
				int nError = WSAGetLastError();
				
				if(nError != WSAEWOULDBLOCK && nError != 0) 
				{
					TRACE("recv failed: %d\n", nError);
					shutdown(m_sock, SD_BOTH);
					closesocket(m_sock);
					m_sock = INVALID_SOCKET;
					m_logEdit.Trace(L"[%s] CT 연결이 끊어졌습니다. CODE[%d]", m_strServerAddr, nError);
				}
			}

			if(m_sendSize > 0)
			{
				int ret = SocketSend(m_sendBuffer, m_sendSize);
				if(ret > 0)
				{
					if(ret < m_sendSize) {
						memcpy(m_sendBuffer, m_sendBuffer + ret, m_sendSize - ret);
					}
					m_sendSize -= ret;
				} else if(ret == 0) {
					TRACE("Connection Closed!\n");
					shutdown(m_sock, SD_BOTH);
					closesocket(m_sock);
					m_sock = INVALID_SOCKET;
				} else if(ret < 0) {
					int nError = WSAGetLastError();
				
					if(nError != WSAEWOULDBLOCK && nError != 0) 
					{
						TRACE("recv failed: %d\n", nError);
						shutdown(m_sock, SD_BOTH);
						closesocket(m_sock);
						m_sock = INVALID_SOCKET;
						m_logEdit.Trace(L"[%s] CT 연결이 끊어졌습니다. CODE[%d]", m_strServerAddr, nError);
					}
				}
			}

			if(curTickTime - sendTickTime > 2000) {
				char keepAlive[] = "KEEP_ALIVE\r\n\r\n";
				memcpy(m_sendBuffer + m_sendSize, keepAlive, strlen(keepAlive));
				m_sendSize += strlen(keepAlive);
				sendTickTime = curTickTime;
			}
		}
		m_sockMutex.Unlock();

	#if 0
		ullCurTime = GetTickCount64();
		if(m_sock == INVALID_SOCKET && m_strServerAddr.GetLength() > 0 && ullCurTime - ullTryTime > 2000)
		{
			char ipAddr[32] = {0, };
			WideToMultiByte(m_strServerAddr, ipAddr);
			ullTryTime = ullCurTime;

			ZeroMemory(m_recvBuffer, sizeof(m_recvBuffer));
			m_recvSize = 0;
			m_sendSize = 0;
			m_sock = ConnectRequest(ipAddr, m_port);
			if(m_sock == INVALID_SOCKET) {
				/* TODO - Handle Exception
				*/
				m_logEdit.Trace(L"[%s] CT 접속 실패", m_strServerAddr);
			} else {
				m_logEdit.Trace(L"[%s] CT 접속 성공", m_strServerAddr);
				sendTickTime = GetTickCount64();
			}
		}
	#endif

#if USE_PACKET_DUMP_FILE
		{
			static int packetCount = 0;
			char packetFile[128];
			FILE *fp;
			sprintf(packetFile, "packet-%03d.txt", packetCount);
			packetCount++;
			fp = fopen(packetFile, "rt");
			if (fp) {
				fread(m_recvBuffer, 1, sizeof(m_recvBuffer), fp);
				fclose(fp);

				m_recvSize = strlen(m_recvBuffer);
			}
		}
#endif

		if(m_recvSize >= 4 && strstr(m_recvBuffer, "\r\n\r\n"))		// Packet is end with CR+LF+CR+LF
		{
			int ret = PacketDizest(m_recvBuffer);

			if(ret > 0 && m_recvSize > ret) {
				memcpy(m_recvBuffer, m_recvBuffer + ret, m_recvSize - ret);
			}
			if(ret > 0)
				m_recvSize -= ret;

			ZeroMemory(m_recvBuffer + m_recvSize, TBD_RECV_BUFSIZE - m_recvSize);
			//TRACE("RecvSize To: %d\n", pThis->m_recvSize);
		}
	}

	CDialogEx::OnTimer(nIDEvent);
}


void CTouchBoardDlg::OnBnClickedButtonMicvolMinus()
{
	// TODO: Add your control notification handler code here
	char strMessage[256];
	sprintf(strMessage, "MIC_VOLUME=MINUS\r\n\r\n");
	SocketSendExceptionHandle(strMessage, strlen(strMessage));
}


void CTouchBoardDlg::OnBnClickedButtonMicvolPlus()
{
	// TODO: Add your control notification handler code here
	char strMessage[256];
	sprintf(strMessage, "MIC_VOLUME=PLUS\r\n\r\n");
	SocketSendExceptionHandle(strMessage, strlen(strMessage));
}


void CTouchBoardDlg::OnBnClickedButtonSpkvolMinus()
{
	// TODO: Add your control notification handler code here
	char strMessage[256];
	sprintf(strMessage, "SPK_VOLUME=MINUS\r\n\r\n");
	SocketSendExceptionHandle(strMessage, strlen(strMessage));
}


void CTouchBoardDlg::OnBnClickedButtonSpkvolPlus()
{
	// TODO: Add your control notification handler code here
	char strMessage[256];
	sprintf(strMessage, "SPK_VOLUME=PLUS\r\n\r\n");
	SocketSendExceptionHandle(strMessage, strlen(strMessage));
}


HBRUSH CTouchBoardDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

	// TODO:  여기서 DC의 특성을 변경합니다.
	UINT nID = pWnd->GetDlgCtrlID();

	switch (nID)
	{
	case IDC_STATIC_TITLE:
		pDC->SetTextColor(RGB(255, 255, 255));
		pDC->SetBkColor(TOPBAR_BACK_COLOR);
		hbr = ::CreateSolidBrush(TOPBAR_BACK_COLOR);
		break;
	}


	// TODO:  기본값이 적당하지 않으면 다른 브러시를 반환합니다.
	return hbr;
}
