#define _WINSOCK_DEPRECATED_NO_WARNINGS 
#include <winsock2.h>
#include <windows.h>
#include <tchar.h>
#include <CommCtrl.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 ID_IPADDRESS   106
#define ID_BUTTON_POLACZ 107
#define ID_EDIT_PORT 108

#define ROZMIAR_BUFORA 4096

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "comctl32.lib")

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR *szTitle = TEXT("Czat Klient"); 			// 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;
DWORD ip_addr = 0;
BOOL czy_polaczony = false;

// 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);


// Funkcja dodajaca tekst do kontolki EDIT
void DodajKomunikat(HWND hEdit, const TCHAR *tekst)
{
	TCHAR tmp[ROZMIAR_BUFORA];
	int index = GetWindowTextLength(hEdit);
	_tcsncpy_s(tmp, tekst, ROZMIAR_BUFORA);
	_tcscat_s(tmp, ROZMIAR_BUFORA, TEXT("\r\n"));
	SetFocus(hEdit);
	SendMessage(hEdit, EM_SETSEL, (WPARAM)index, (LPARAM)index);
	SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)tmp);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	MSG msg;
	HACCEL hAccelTable;

	InitCommonControls();

	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, 620, 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;
}


void UstawOkna(HWND hWnd, BOOL czy_polaczony)
{
	EnableWindow(GetDlgItem(hWnd, ID_EDIT1), czy_polaczony);
	EnableWindow(GetDlgItem(hWnd, ID_EDIT2), czy_polaczony);
	EnableWindow(GetDlgItem(hWnd, ID_BUTTON), czy_polaczony);
	EnableWindow(GetDlgItem(hWnd, ID_IPADDRESS), !czy_polaczony);
	EnableWindow(GetDlgItem(hWnd, ID_EDIT_PORT), !czy_polaczony);
	if (czy_polaczony) SetWindowText(GetDlgItem(hWnd, ID_BUTTON_POLACZ), TEXT("Rozłącz"));
	else SetWindowText(GetDlgItem(hWnd, ID_BUTTON_POLACZ), TEXT("Połącz"));
}


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("STATIC"), TEXT("IP"), WS_CHILD | WS_VISIBLE, 10, 10, 20, 25,
			hWnd, 0, GetModuleHandle(NULL), NULL);
		CreateWindow(WC_IPADDRESS, TEXT(""), WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 30, 10, 200, 25,
			hWnd, (HMENU)ID_IPADDRESS, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("STATIC"), TEXT("port"), WS_CHILD | WS_VISIBLE, 240, 10, 30, 25,
			hWnd, 0, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("EDIT"), TEXT(""),
			WS_CHILD | WS_BORDER | WS_VISIBLE,
			270, 10, 100, 25, hWnd, (HMENU)ID_EDIT_PORT, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("BUTTON"), TEXT("Połącz"),
			WS_CHILD | WS_VISIBLE,
			380, 10, 100, 25, hWnd, (HMENU)ID_BUTTON_POLACZ, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("EDIT"), TEXT("Czekam na połącznie...\r\n"),
			WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL | WS_DISABLED,
			10, 50, 500, 450, hWnd, (HMENU)ID_EDIT1, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("EDIT"), TEXT("Tu wpisz komunikat."),
			WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE | WS_DISABLED,
			10, 520, 400, 50, hWnd, (HMENU)ID_EDIT2, GetModuleHandle(NULL), NULL);
		CreateWindow(TEXT("BUTTON"), TEXT("Wyślij"),
			WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_DISABLED,
			420, 520, 80, 50, hWnd, (HMENU)ID_BUTTON, GetModuleHandle(NULL), NULL);

		SendMessage(GetDlgItem(hWnd, ID_IPADDRESS), IPM_SETADDRESS, 0, MAKEIPADDRESS(127, 0, 0, 1));

		_stprintf_s(bufor, ROZMIAR_BUFORA, TEXT("%d"), port);
		SetWindowText(GetDlgItem(hWnd, ID_EDIT_PORT), bufor);

		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;
		}

		ZeroMemory(bufor, ROZMIAR_BUFORA);

		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_CLOSE:
			MessageBox(hWnd, TEXT("Połaczenie zerwane"), TEXT("Informacja"), MB_ICONINFORMATION | MB_OK);
			czy_polaczony = false;
			UstawOkna(hWnd, czy_polaczony);
			closesocket(ListenSocket);
			ListenSocket = INVALID_SOCKET;
			break;
		case FD_CONNECT:
			czy_polaczony = true;
			_stprintf_s(bufor, ROZMIAR_BUFORA, TEXT("OK. Połączono."));
			DodajKomunikat(GetDlgItem(hWnd, ID_EDIT1), bufor);
			czy_polaczony = true;
			UstawOkna(hWnd, czy_polaczony);
			break;
		}

		break;

	case WM_COMMAND:
		wmId = LOWORD(wParam);

		switch (wmId)
		{
		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;
		case ID_BUTTON_POLACZ:
			if (!czy_polaczony)
			{
				if (ListenSocket == INVALID_SOCKET)
				{

					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;
					}

					if (WSAAsyncSelect(ListenSocket, hWnd, WM_SOCKET, FD_READ | FD_CLOSE | FD_CONNECT) == SOCKET_ERROR)
					{
						MessageBox(hWnd, TEXT("WSAAsyncSelect error"), TEXT("Error"), MB_OK);
						SendMessage(hWnd, WM_DESTROY, NULL, NULL);
					}
				}

				TCHAR portstr[10];
				SendMessage(GetDlgItem(hWnd, ID_IPADDRESS), IPM_GETADDRESS, 0, (LPARAM)&ip_addr);
				GetWindowText(GetDlgItem(hWnd, ID_EDIT_PORT), portstr, 10);
				port = _ttoi(portstr);

				_stprintf_s(bufor, ROZMIAR_BUFORA, TEXT("Próba połączenia z IP: %d.%d.%d.%d, port: %d"),
					FIRST_IPADDRESS(ip_addr), SECOND_IPADDRESS(ip_addr), THIRD_IPADDRESS(ip_addr),
					FOURTH_IPADDRESS(ip_addr), port);
				DodajKomunikat(GetDlgItem(hWnd, ID_EDIT1), bufor);

				sockaddr_in service;
				memset(&service, 0, sizeof(service));
				service.sin_family = AF_INET;
				service.sin_addr.s_addr = htonl(ip_addr);
				service.sin_port = htons(port);

				connect(ListenSocket, (sockaddr *)& service, sizeof (service));

			}
			else
			{
				// Rzołącznie 
				shutdown(ListenSocket, SD_BOTH);
				closesocket(ListenSocket);
				ListenSocket = INVALID_SOCKET;
				czy_polaczony = false;
				UstawOkna(hWnd, czy_polaczony);
			}
			break;
		}
		break;
	case WM_DESTROY:
		shutdown(ListenSocket, SD_BOTH);
		closesocket(ListenSocket);
		WSACleanup(); PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
