#include "FrameWnd.h"
#include "WVFrame.h"

HINSTANCE	g_hInstance;
TCHAR		g_szFrameClassName[]	= TEXT("WirelessViewFrameWndClass");
HWND		g_hWndMDIClient			= NULL;
LONG_PTR	g_OldMDIClWndProc		= 0;
HANDLE		g_hProcHeap				= NULL;

SETTINGS	g_sSettings				= {0};
WNDSTRUCT	g_wndFrame				= {0};

DWORD		g_dwMainThrdId;
LPCTWMD		g_lpCtwmd				= NULL;

LPIOCPINFO  g_lpIoci				= NULL;
LPFGSTRUCT	g_lpFrameGrabber		= NULL;
ENDPOINT	g_epMain				= {0};
struct		
{
	HBITMAP		hLogo;
	LONG		liW;
	LONG		liH;
	LONG		liXpos;
	LONG		liYpos;
}	g_LogoBmp;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX	wc, wc1, wc2;	
	MSG			Msg;	
	HACCEL		hAcceleratorsTable;
	HWND		hWndFrame;
	WSADATA		wsadat;	
	
	
	g_hInstance = hInstance;
	g_hProcHeap	= GetProcessHeap();
	g_dwMainThrdId = GetCurrentThreadId();

#ifdef _DEBUG
	InitMemDbg();
#endif

	wc.cbSize		 = sizeof(WNDCLASSEX);
	wc.style		 = 0;
	wc.lpfnWndProc	 = WndProc;
	wc.cbClsExtra	 = 0;
	wc.cbWndExtra	 = 0;
	wc.hInstance	 = g_hInstance;
	wc.hIcon		 = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FRAME_ICON));
	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = g_szFrameClassName;
	wc.hIconSm		 = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_FRAME_ICON));

	wc1.hInstance = g_hInstance;
	DefineChildWndClass(&wc1);

	wc2.hInstance = g_hInstance;
	DefineVideoWndClass(&wc2);

	if(!RegisterClassEx(&wc) || !RegisterClassEx(&wc1) || !RegisterClassEx(&wc2))
	{
		MessageBox(NULL, TEXT("Window Registration Failed."), TEXT("Error"),
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	if(WSAStartup(MAKEWORD(2,2), &wsadat) != 0)
	{
		MessageBox(NULL, TEXT("WSAStartup Failed."), TEXT("Error"),
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}
	
	g_wndFrame.hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINMENU));

	g_wndFrame.hWnd = CreateWindowEx(0, g_szFrameClassName,
		TEXT("WirelessView"),
		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, g_wndFrame.hMenu, g_hInstance, NULL);
	
	hAcceleratorsTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_MAIN_ACCELERATOR));
	hWndFrame = g_wndFrame.hWnd;

	if(g_wndFrame.hWnd == NULL || hAcceleratorsTable == NULL)
	{
		MessageBox(NULL, TEXT("Window Creation Failed."), TEXT("Error"),
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	ShowWindow(g_wndFrame.hWnd, nCmdShow);
	UpdateWindow(g_wndFrame.hWnd);
	
	g_lpCtwmd = CreateCTWMD();
	if(g_lpCtwmd == NULL)
	{
		MessageBox(NULL, TEXT("Program Startup Failed."), TEXT("Error"),
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	
	while(GetMessage(&Msg, NULL, 0, 0) > 0)
	{
		if (!TranslateMDISysAccel(g_hWndMDIClient, &Msg) && 
			!TranslateAccelerator(hWndFrame, hAcceleratorsTable, &Msg) &&
			!CallMsgFilter(&Msg, 0))
		{
			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}
	}	
	DestroyCTWMD(g_lpCtwmd);
	WSACleanup();
#ifdef _DEBUG
	WriteMemDbgMessage();
#endif
	ExitProcess(Msg.wParam);
	return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{	
	
		case WM_CREATE:
		{
			CLIENTCREATESTRUCT	ccs;
			BITMAP				bmp;
			HMENU				hMenu = GetMenu(hwnd);			
			
			
			InitCommonControls();
			
			g_epMain.dwAddr = MAKEIPADDRESS(127, 0, 0, 1);
			g_epMain.uPort	= 1033;

			/*SetMenuItemBitmaps(g_wndFrame.hMenu, ID_MENU_SERVER, MF_BYCOMMAND, 
				LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_RUN)),
				LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_STOP)));*/
			
			InitializeApplication();

			ccs.hWindowMenu  = GetSubMenu(hMenu, 2);
			ccs.idFirstChild = ID_MDI_FIRSTCHILD;

			g_hWndMDIClient = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("mdiclient"), NULL,
				WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
				CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
				hwnd, NULL, g_hInstance, (LPVOID)&ccs);

			g_OldMDIClWndProc = SetWindowLongPtr(g_hWndMDIClient, GWLP_WNDPROC, (LONG_PTR)MDIClNewWndProc);
			g_LogoBmp.hLogo = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_LOGOBMP), 
				IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);			
			GetObject(g_LogoBmp.hLogo, sizeof(BITMAP), &bmp);

			g_LogoBmp.liW = bmp.bmWidth;
			g_LogoBmp.liH = bmp.bmHeight;

			if(g_hWndMDIClient == NULL)
				MessageBox(hwnd, TEXT("Could not create MDI client."), TEXT("Error"), MB_OK | MB_ICONERROR);
			
		}
		break;		
		case WM_CLOSE:
			DestroyWindow(hwnd);
		break;
		case WM_DESTROY:			
			UnloadApplication();
			PostQuitMessage(0);
		break;
		case WM_COMMAND:			
				switch(LOWORD(wParam))
				{
				case ID_MENU_CONNECT:
					{						
											
						if(ConnectDlg(&g_epMain, hwnd))
						{
							if(g_lpIoci == NULL)
								g_lpIoci = CreateIocpServer();
							if(g_lpIoci != NULL)
							{								
								LPCONNECTION	lpCon;
								SOCKET			s;

								s = ConnectTo(&g_epMain);
								if(s != INVALID_SOCKET)
								{
									lpCon = AddConnection(g_lpIoci, s, ClientSideProc, sizeof(CLIENTDATA), g_epMain.dwAddr, g_epMain.uPort);									
									if(lpCon != NULL)
									{
										SendCreateMessage(lpCon);
										CreateMDIChild(g_hWndMDIClient, lpCon);
									}
									else
									{
										closesocket(s);
										MessageBox(hwnd, TEXT("Spojenie sa nepodarilo asociovať s IOCP."), TEXT("WirelessView"), MB_OK | MB_ICONWARNING);
									}
								}
								else
									MessageBox(hwnd, TEXT("Pripojenie na server nebolo úspešné."), TEXT("WirelessView"), MB_OK | MB_ICONWARNING);
							}
							else
								MessageBox(hwnd, TEXT("Nepodarilo sa IOCP spustiť server."), TEXT("WirelessView"), MB_OK | MB_ICONERROR);
						}
					}
					break;
				case ID_MENU_DISCONNECT:
					PostMessage((HWND)SendMessage(g_hWndMDIClient, WM_MDIGETACTIVE, 0, 0), WM_CLOSE, 0, 0);
					break;

				case ID_MENU_DISCONNECT_ALL:
					{
						HWND hWndChild;						
						while(hWndChild = (HWND)SendMessage(g_hWndMDIClient, WM_MDIGETACTIVE, 0, 0))
						{
							SendMessage(hWndChild, WM_CLOSE, 0, 0);
						}
					}
					break;

				case ID_MENU_SERVER:
					{							
						if(MF_CHECKED & GetMenuState(g_wndFrame.hMenu, ID_MENU_SERVER, MF_BYCOMMAND))
						{	
							if(g_lpIoci != NULL)
							{
								DestroyServer((LPSERVER)g_lpIoci->lpData);
								g_lpIoci->lpData = NULL;
							}

							CheckMenuItem(g_wndFrame.hMenu, ID_MENU_SERVER, MF_BYCOMMAND | MF_UNCHECKED);
						}
						else
						{							
							if(g_lpIoci == NULL)
								g_lpIoci = CreateIocpServer();

							if(g_lpIoci != NULL)
							{
								g_lpIoci->lpData = CreateServer(g_lpIoci, g_lpFrameGrabber);

								if(g_lpIoci->lpData != NULL)
									CheckMenuItem(g_wndFrame.hMenu, ID_MENU_SERVER, MF_BYCOMMAND | MF_CHECKED);
								else
									MessageBox(hwnd, TEXT("Nepodarilo sa spustiť server."), TEXT("WirelessView"), MB_OK | MB_ICONERROR);
							}
							else
								MessageBox(hwnd, TEXT("Nepodarilo sa IOCP spustiť server."), TEXT("WirelessView"), MB_OK | MB_ICONERROR);

						}
					}
					break;
				case ID_MENU_EXIT:
					PostMessage(hwnd, WM_CLOSE, 0, 0);
					break;

				case ID_MENU_OPTIONS:
					if(g_lpIoci != NULL)
					{
						if(g_lpIoci->lpData != NULL)
						{
							if(MessageBox(hwnd, TEXT("Server je práve spustený. Ak chcete zmeniť nastavenia musí sa server najskôr ukončiť.\nMá sa server ukončiť?"), TEXT("WirelessView"), MB_YESNO | MB_ICONQUESTION) == IDYES)
							{
								CheckMenuItem(g_wndFrame.hMenu, ID_MENU_SERVER, MF_BYCOMMAND | MF_UNCHECKED);
								DestroyServer((LPSERVER)g_lpIoci->lpData);
								g_lpIoci->lpData = NULL;
								SettingsDlg(hwnd);
							}
						}
						else
							SettingsDlg(hwnd);
					}
					else
						SettingsDlg(hwnd);							

					
					break;

				case ID_MENU_ABOUT:
					DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ABOUT_DIALOG), g_wndFrame.hWnd, AboutDialogProc); 
					break;

				case ID_WND_CASCADE:
					SendMessage(g_hWndMDIClient, WM_MDICASCADE, 0, 0);
					break;
				case ID_WND_TITLE:
					SendMessage(g_hWndMDIClient, WM_MDITILE, 0, 0);
					break;
				
				default:				
					if(LOWORD(wParam) >= ID_MDI_FIRSTCHILD)
					{
						return DefFrameProc(hwnd, g_hWndMDIClient, WM_COMMAND, wParam, lParam);
					}
					else 
					{
						HWND hChild = (HWND)SendMessage(g_hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
						if(hChild)						
							SendMessage(hChild, WM_COMMAND, wParam, lParam);						
					}				
				}			
		break;
		default:
			return DefFrameProc(hwnd, g_hWndMDIClient, uMsg, wParam, lParam);
	}
	return 0;
}

LRESULT CALLBACK MDIClNewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC			hdc, hdcBmp;
						
			hdc = BeginPaint(hwnd, &ps);
			hdcBmp = CreateCompatibleDC(hdc);			
			SelectObject(hdcBmp, g_LogoBmp.hLogo);
			
			TransparentBlt(hdc, g_LogoBmp.liXpos, g_LogoBmp.liYpos, 
				g_LogoBmp.liW, g_LogoBmp.liH, 
				hdcBmp, 0, 0, g_LogoBmp.liW, g_LogoBmp.liH, 0x00ffffff);
			/*SelectObject(hdc, GetStockObject(NULL_BRUSH));
			Rectangle(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);*/
			DeleteDC(hdcBmp);
			EndPaint(hwnd, &ps);
		}		
		break;
	case WM_SIZE:
		{
		RECT	rc;
		rc.left		= g_LogoBmp.liXpos;
		rc.top		= g_LogoBmp.liYpos;
		rc.right	= g_LogoBmp.liXpos + g_LogoBmp.liW;
		rc.bottom	= g_LogoBmp.liYpos + g_LogoBmp.liH;
		InvalidateRect(hwnd, &rc, TRUE);

		GetWindowRect(g_hWndMDIClient, &rc);

		g_LogoBmp.liXpos = ((rc.right - rc.left)/2) - ((g_LogoBmp.liW) / 2);
		g_LogoBmp.liYpos = ((rc.bottom - rc.top)/2) - ((g_LogoBmp.liH) / 2);

		rc.left		= g_LogoBmp.liXpos;
		rc.top		= g_LogoBmp.liYpos;
		rc.right	= g_LogoBmp.liXpos + g_LogoBmp.liW;
		rc.bottom	= g_LogoBmp.liYpos + g_LogoBmp.liH;
		InvalidateRect(hwnd, &rc, TRUE);
		
		
		return CallWindowProc((WNDPROC)g_OldMDIClWndProc, hwnd, uMsg, wParam, lParam);
		}
		break;

	case WM_VSCROLL:
		if(LOWORD(wParam) == SB_ENDSCROLL)
			InvalidateRect(hwnd, NULL, TRUE);
		return CallWindowProc((WNDPROC)g_OldMDIClWndProc, hwnd, uMsg, wParam, lParam);
		break;
	case WM_HSCROLL:
		if(LOWORD(wParam) == SB_ENDSCROLL)
			InvalidateRect(hwnd, NULL, TRUE);
		return CallWindowProc((WNDPROC)g_OldMDIClWndProc, hwnd, uMsg, wParam, lParam);
		break;

	default:
		return CallWindowProc((WNDPROC)g_OldMDIClWndProc, hwnd, uMsg, wParam, lParam);
	}
	return 0;
}

VOID InitializeApplication()
{
	HKEY	hRegKey, hKeyCurrUser;	
	DWORD	dwDisposition;
	INT		iDevCnt;
	
	g_lpFrameGrabber = CreateFG();
	
	iDevCnt = SendFGMessage(g_lpFrameGrabber, FG_LISTDEV, 0, 0);

	// Nacitat Nastavenia
	if(RegOpenCurrentUser(KEY_CREATE_SUB_KEY, &hKeyCurrUser) != ERROR_SUCCESS)
	{
		MessageBox(NULL, TEXT("Application Initialization Failed!"), TEXT("Error!"), MB_OK | MB_ICONEXCLAMATION);
		return;
	}

	if(RegCreateKeyEx(hKeyCurrUser, TEXT("Software\\WirelessView"), 0,
		NULL, 0, KEY_WRITE | KEY_READ | KEY_WOW64_32KEY,
		NULL, &hRegKey, &dwDisposition) != ERROR_SUCCESS)
	{
		MessageBox(NULL, TEXT("Application Initialization Failed!"), TEXT("Error!"), MB_OK | MB_ICONEXCLAMATION);
		RegCloseKey(hKeyCurrUser);
		return;
	}
	
	g_sSettings.hRegKey = hRegKey;
	if(dwDisposition == REG_CREATED_NEW_KEY)
	{
		g_sSettings.iVIDeviceID	= 0;
		RegSetValueEx(hRegKey, TEXT("iVIDeviceID"), 0,
			REG_DWORD, (LPBYTE)&(g_sSettings.iVIDeviceID), sizeof(INT));
		
		g_sSettings.iPort = 1033;
		RegSetValueEx(hRegKey, TEXT("iServerPort"), 0,
			REG_DWORD, (LPBYTE)&(g_sSettings.iPort), sizeof(INT));

		g_sSettings.iVideoW = 320;
		RegSetValueEx(hRegKey, TEXT("iVideoW"), 0,
			REG_DWORD, (LPBYTE)&(g_sSettings.iVideoW), sizeof(INT));

		g_sSettings.iVideoH = 240;
		RegSetValueEx(hRegKey, TEXT("iVideoH"), 0,
			REG_DWORD, (LPBYTE)&(g_sSettings.iVideoH), sizeof(INT));
		
	}
	else
	{

		DWORD	dwSize = sizeof(INT);		

		RegQueryValueEx(hRegKey, TEXT("iVIDeviceID"), 0,
			NULL, (LPBYTE)&(g_sSettings.iVIDeviceID), &dwSize);			
				
		if((g_sSettings.iVIDeviceID >=  iDevCnt) || (g_sSettings.iVIDeviceID < 0))
		{
			g_sSettings.iVIDeviceID = 0;
			RegSetValueEx(hRegKey, TEXT("iVIDeviceID"), 0,
				REG_DWORD, (LPBYTE)&(g_sSettings.iVIDeviceID), sizeof(INT));
		}

		RegQueryValueEx(hRegKey, TEXT("iServerPort"), 0,
			NULL, (LPBYTE)&(g_sSettings.iPort), &dwSize);	
		if(g_sSettings.iPort > 0xffff || g_sSettings.iPort < 0)
		{
			g_sSettings.iPort = 1033;
			RegSetValueEx(hRegKey, TEXT("iServerPort"), 0,
				REG_DWORD, (LPBYTE)&(g_sSettings.iPort), sizeof(INT));
		}

		RegQueryValueEx(hRegKey, TEXT("iVideoW"), 0,
			NULL, (LPBYTE)&(g_sSettings.iVideoW), &dwSize);	
		if(g_sSettings.iVideoW < 0)
		{
			g_sSettings.iPort = 640;
			RegSetValueEx(hRegKey, TEXT("iVideoW"), 0,
				REG_DWORD, (LPBYTE)&(g_sSettings.iVideoW), sizeof(INT));
		}

		RegQueryValueEx(hRegKey, TEXT("iVideoH"), 0,
			NULL, (LPBYTE)&(g_sSettings.iVideoH), &dwSize);	
		if(g_sSettings.iVideoH < 0)
		{
			g_sSettings.iPort = 480;
			RegSetValueEx(hRegKey, TEXT("iVideoH"), 0,
				REG_DWORD, (LPBYTE)&(g_sSettings.iVideoH), sizeof(INT));
		}
	}

	RegCloseKey(hKeyCurrUser);
}

VOID UnloadApplication()
{	
	if(g_lpIoci != NULL)
	{
		if(g_lpIoci->lpData != NULL)
			DestroyServer((LPSERVER)g_lpIoci->lpData);
		DestroyIocpServer(g_lpIoci);
	}

	DeleteFG(g_lpFrameGrabber);
	// Uložiť nastavenia
	RegSetValueEx(g_sSettings.hRegKey, TEXT("iVIDeviceID"), 0,
		REG_DWORD, (LPBYTE)&(g_sSettings.iVIDeviceID), sizeof(INT));
	RegSetValueEx(g_sSettings.hRegKey, TEXT("iServerPort"), 0,
		REG_DWORD, (LPBYTE)&(g_sSettings.iPort), sizeof(INT));
	RegSetValueEx(g_sSettings.hRegKey, TEXT("iVideoW"), 0,
		REG_DWORD, (LPBYTE)&(g_sSettings.iVideoW), sizeof(INT));
	RegSetValueEx(g_sSettings.hRegKey, TEXT("iVideoH"), 0,
		REG_DWORD, (LPBYTE)&(g_sSettings.iVideoH), sizeof(INT));

	DeleteObject(g_LogoBmp.hLogo);
	RegCloseKey(g_sSettings.hRegKey);
	//VIClose(g_hVi);
}
