#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <tchar.h>

#define MAX_LOADSTRING 100
#define ID_EDIT1 101
#define ID_EDIT2 102
#define ID_BUTTON 103
#define WM_SOCKET 104
#define IDM_EXIT  105

#define ROZMIAR_BUFORA 4096

#pragma comment(lib, "ws2_32.lib")

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR *szTitle = TEXT("Czat Serwer"); 			// The title bar text
TCHAR *szWindowClass = TEXT("MyWindowClass");	// the main window class name
WSADATA wsaData;
SOCKET ListenSocket = INVALID_SOCKET;
TCHAR bufor[ROZMIAR_BUFORA];
int port = 1234;

// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);


void DodajKomunikat(HWND hEdit, TCHAR *tekst)
{
	int index = GetWindowTextLength(hEdit);
	_tcscat_s(tekst, ROZMIAR_BUFORA, TEXT("\r\n"));
	SetFocus(hEdit);
	SendMessage(hEdit, EM_SETSEL, (WPARAM)index, (LPARAM)index);
	SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)tekst);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	MSG msg;
	HACCEL hAccelTable;

	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
	if (!RegisterClassEx(&wcex))
	{
		MessageBox(NULL, TEXT("Register Window Class failed"), TEXT("Window Class Failed"), MB_ICONERROR);
		return FALSE;
	}

	HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, 530, 650, NULL, NULL, hInstance, NULL);

	if (!hWnd)	return FALSE;

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//  PURPOSE:  Processes messages for the main window.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent, iResult;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_CREATE:
		CreateWindow(TEXT("EDIT"), TEXT("Czekam na połącznie...\r\n"),
			WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL,
			10, 10, 500, 500, hWnd, (HMENU)ID_EDIT1, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("EDIT"), TEXT("Tu wpisz komunikat."),
			WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE,
			10, 520, 400, 50, hWnd, (HMENU)ID_EDIT2, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("BUTTON"), TEXT("Wyślij"),
			WS_CHILD | WS_VISIBLE | WS_TABSTOP,
			420, 520, 80, 50, hWnd, (HMENU)ID_BUTTON, GetModuleHandle(NULL), NULL);

		iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
		if (iResult != NO_ERROR) {
			MessageBox(hWnd, TEXT("WSAStartup error"), TEXT("Error"), MB_OK);
			SendMessage(hWnd, WM_DESTROY, NULL, NULL);
			break;
		}

		ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (ListenSocket == INVALID_SOCKET) {
			MessageBox(hWnd, TEXT("socket error"), TEXT("Error"), MB_OK);
			SendMessage(hWnd, WM_DESTROY, NULL, NULL);
			break;
		}

		sockaddr_in service;
		service.sin_family = AF_INET;
		service.sin_addr.s_addr = htonl(INADDR_ANY);
		service.sin_port = htons(port);

		iResult = bind(ListenSocket, (SOCKADDR *)& service, sizeof (service));
		if (iResult == SOCKET_ERROR) {
			MessageBox(hWnd, TEXT("Bind error"), TEXT("Error"), MB_OK);
			SendMessage(hWnd, WM_DESTROY, NULL, NULL);
			break;
		}

		if (listen(ListenSocket, 1) == SOCKET_ERROR)
		{
			MessageBox(hWnd, TEXT("Listen error"), TEXT("Error"), MB_OK);
			SendMessage(hWnd, WM_DESTROY, NULL, NULL);
			break;
		}

		if (WSAAsyncSelect(ListenSocket, hWnd, WM_SOCKET, FD_READ | FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
		{
			MessageBox(hWnd, TEXT("WSAAsyncSelect error"), TEXT("Error"), MB_OK);
			SendMessage(hWnd, WM_DESTROY, NULL, NULL);
		}
		ZeroMemory(bufor, ROZMIAR_BUFORA);

		_stprintf_s(bufor, TEXT("Słucham na porcie %d"), port);
		DodajKomunikat(GetDlgItem(hWnd, ID_EDIT1), bufor);

		break;
	case WM_SOCKET:

		switch (lParam)
		{
		case FD_READ:
			ZeroMemory(bufor, ROZMIAR_BUFORA);
			recv(ListenSocket, (char*)bufor, ROZMIAR_BUFORA, 0);
			DodajKomunikat(GetDlgItem(hWnd, ID_EDIT1), bufor);
			break;
		case FD_ACCEPT:
		{
						  sockaddr sa;
						  int size = sizeof(sa);
						  ListenSocket = accept(ListenSocket, &sa, &size);
						  TCHAR klient_adres[256];
						  ZeroMemory(klient_adres, sizeof(klient_adres));
						  size = sizeof(klient_adres);
						  WSAAddressToString(&sa, sizeof(sa), NULL, klient_adres, (LPDWORD)&size);
						  _stprintf_s(bufor, ROZMIAR_BUFORA, TEXT("Zaakceptowano połącznie\r\nIP: %s\r\n"), klient_adres);
						  SetWindowText(GetDlgItem(hWnd, ID_EDIT1), bufor);
						  break;
		}

		case FD_CLOSE:
			MessageBox(hWnd, TEXT("Połaczenie zerwane"), TEXT("Informacja"), MB_ICONINFORMATION | MB_OK);
			closesocket(ListenSocket);
			SendMessage(hWnd, WM_DESTROY, NULL, NULL);
			break;
		}

		break;

	case WM_COMMAND:
		wmId = LOWORD(wParam);

		switch (wmId)
		{
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		case ID_BUTTON:
			GetWindowText(GetDlgItem(hWnd, ID_EDIT2), bufor, ROZMIAR_BUFORA);
			send(ListenSocket, (char*)bufor, _tcslen(bufor)*sizeof(TCHAR), 0);
			DodajKomunikat(GetDlgItem(hWnd, ID_EDIT1), bufor);
			SetWindowText(GetDlgItem(hWnd, ID_EDIT2), TEXT(""));
			break;
		}
		break;
	case WM_DESTROY:
		shutdown(ListenSocket, SD_BOTH);
		closesocket(ListenSocket);
		WSACleanup(); PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}


