/*

SIMPLE WIN32 C API EXAMPLE HELLO WORLD PROGRAM...

AUTHOR: Matthew W. Coan
Date: 27/Jan/2020 4:13

*/

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <string.h>

#define HELLO_FONT_WIDTH 25
#define HELLO_FONT_HEIGHT 50
#define HELLO_WINDOW_WIDTH 600
#define HELLO_WINDOW_HEIGHT 300
#define MAX_STRING 100
#define HELLO_BUTTON_ID 101
#define HELLO_BUTTON_WIDTH 100
#define HELLO_BUTTON_HEIGHT 50

const char* szAppName = "Hello Window";
const char* szTitle = "Hello, world!";
const char* szMessage = "Hello, world!";
const char* szFontName = "Times New Roman";
const char* szErrorMessage = "Error: Can't create window!";

HWND hWindow = 0;
HWND hButton = 0;

ATOM RegisterHelloClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, INT nCmdShow);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

VOID OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
VOID OnResize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
VOID OnCommand(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
VOID OnHello(HWND hWnd);
VOID OnDestroyWindow();

INT WinMain(HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            LPSTR lpCmdLine,
            INT nCmdShow)
{
   MSG msg;

   RegisterHelloClass(hInstance);

   if(!InitInstance(hInstance, nCmdShow)) {
      MessageBox(NULL, szErrorMessage, szErrorMessage, MB_ICONERROR | MB_OK);
      ExitProcess(0);
   }

   ZeroMemory(&msg,sizeof(MSG));

   while(GetMessage(&msg,NULL,0,0)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }

   return msg.wParam;
}

VOID OnDestroyWindow()
{
   DestroyWindow(hButton);
   DestroyWindow(hWindow);
}

ATOM RegisterHelloClass(HINSTANCE hInstance)
{
   WNDCLASSEX wClass;

   ZeroMemory(&wClass,sizeof(WNDCLASSEX));

   wClass.cbClsExtra = 0;
   wClass.cbSize = sizeof(WNDCLASSEX);
   wClass.cbWndExtra = 0;
   wClass.hbrBackground = WHITE_BRUSH;
   wClass.hCursor = LoadCursor(NULL,IDC_ARROW);
   wClass.hIcon = NULL;
   wClass.hIconSm = NULL;
   wClass.hInstance = hInstance;
   wClass.lpfnWndProc = (WNDPROC)WndProc;
   wClass.lpszMenuName = NULL;
   wClass.style = CS_HREDRAW | CS_VREDRAW;
   wClass.lpszClassName = szAppName;
   
   return RegisterClassEx(&wClass);
}

BOOL InitInstance(HINSTANCE hInstance, INT nCmdShow)
{
   HWND hWnd;
   BOOL bRet;
   RECT rect;
   INT xPos;
   INT yPos;

   bRet = TRUE;
   
   xPos = GetSystemMetrics(SM_CXSCREEN) / 2 - HELLO_WINDOW_WIDTH / 2;

   if(xPos < 0)
      xPos = 0;

   yPos = GetSystemMetrics(SM_CYSCREEN) / 2 - HELLO_WINDOW_HEIGHT / 2;

   if(yPos < 0)
      yPos = 0;

   hWnd = CreateWindowEx(
      0,
      szAppName,
      szTitle,
      WS_OVERLAPPEDWINDOW,
      xPos,
      yPos,
      HELLO_WINDOW_WIDTH,
      HELLO_WINDOW_HEIGHT,
      NULL,
      NULL,
      hInstance,
      NULL);

   hWindow = hWnd;

   if(!hWnd) {
      bRet = FALSE;
   }
   else if(hWnd) {
      GetClientRect(hWnd, &rect);

      if(rect.right > 0) 
         xPos = rect.right / 2 - HELLO_BUTTON_WIDTH / 2;

      if(xPos < 0)
         xPos = 0;

      if(rect.bottom > 0)
         yPos = rect.bottom / 2 + 55;

      if(yPos >= rect.bottom) 
         yPos = rect.bottom-1;
      
      if(yPos < 0)
         yPos = 0;

      hButton = CreateWindowEx(
         0,
         "BUTTON",
         "Click to exit...",
         WS_TABSTOP|WS_VISIBLE|
         WS_CHILD|BS_DEFPUSHBUTTON,
         xPos, 
         yPos, 
         HELLO_BUTTON_WIDTH,
         HELLO_BUTTON_HEIGHT,
         hWnd,
         (HMENU)HELLO_BUTTON_ID,
         GetModuleHandle(NULL),
         NULL);

      if(!hButton) {
         bRet = FALSE;
      }
      else {
         ShowWindow(hWnd, nCmdShow);
         ShowWindow(hButton, nCmdShow);

         UpdateWindow(hWnd);
         UpdateWindow(hButton);
      }
   }

   return bRet;
}

VOID OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   RECT rect;
   RECT rect2;
   HDC hdc;
   SIZE sz;
   HFONT hFont;

   DefWindowProc(hWnd, message, wParam, lParam);

   GetClientRect(hWnd, &rect);

   hdc = GetDC(hWnd);
   
   FillRect(hdc, &rect, NULL);

   hFont = CreateFont(
      HELLO_FONT_HEIGHT,
      HELLO_FONT_WIDTH,
      0,
      0,
      0,
      FALSE,
      FALSE,
      FALSE,
      ANSI_CHARSET,
      OUT_DEFAULT_PRECIS,
      CLIP_DEFAULT_PRECIS,
      DEFAULT_QUALITY,
      FF_MODERN,
      szFontName);
   
   SelectObject(hdc, hFont);
   
   rect2 = rect;
   
   if(rect2.left <= (rect2.right-5))
      rect2.left += 5;
   
   if(rect2.right >= 5)
      rect2.right -= 5;
   
   if(rect2.top <= (rect2.bottom-5))
      rect2.top += 5;
   
   if(rect2.bottom >= 5)
      rect2.bottom -= 5;
	
   GetTextExtentPoint(hdc, szTitle, 13, &sz);
   
   if(rect.bottom > 0 && sz.cy > 0)
      rect.top = (rect.bottom / 2) - (sz.cy / 2);

   if(rect.right > 0 && sz.cx > 0)
      rect.left = (rect.right / 2) - (sz.cx / 2);

   if(rect.top < 0) 
      rect.top = 0;

   if(rect.left < 0) 
      rect.left = 0;
   
   SetTextColor(hdc, RGB(0,0,0));
   
   DrawText(hdc, szMessage, -1, &rect, DT_SINGLELINE);
  
   DrawEdge(hdc,&rect2,EDGE_SUNKEN,BF_RECT);

   DeleteObject(hFont);
   
   DeleteDC(hdc);
}

VOID OnResize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   RECT rect;
   INT xPos, yPos;

   GetClientRect(hWnd, &rect);
   
   if(rect.right > 0)
      xPos = rect.right / 2 - HELLO_BUTTON_WIDTH / 2;
   
   if(rect.bottom > 0)
      yPos = rect.bottom / 2 + 55;

   if(xPos >= rect.right)
      xPos = rect.right - 1;
   
   if(xPos < 0)
      xPos = 0;

   if(xPos < 0)
      xPos = 0;

   MoveWindow(
      hButton, 
      xPos,
      yPos,
      HELLO_BUTTON_WIDTH, 
      HELLO_BUTTON_HEIGHT, 
      TRUE);
   
   OnPaint(hWnd, message, wParam, lParam);
}

VOID OnHello(HWND hWnd)
{
   PostQuitMessage(0);
}

VOID OnCommand(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   INT cmd;
   cmd = LOWORD(wParam);
   switch(cmd) {
   case HELLO_BUTTON_ID:
      OnHello(hWnd);
      break;

   default:
      DefWindowProc(hWnd, message, wParam, lParam);
   }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   LRESULT lRet;
   RECT rect;

   lRet = 0;

   switch (message) {
   case WM_CREATE:
      OnPaint(hWnd, message, wParam, lParam);
      break;

   case WM_CLOSE:
      PostQuitMessage(0);
      break;

   case WM_DESTROY:
      OnDestroyWindow();
      break;

   case WM_COMMAND:
      OnCommand(hWnd, message, wParam, lParam);
      break;

   case WM_SIZE:
      OnResize(hWnd, message, wParam, lParam);
      break;

   case WM_PAINT: 
      OnPaint(hWnd, message, wParam, lParam);
      break;

   case WM_CHAR:
      MessageBox(NULL, "WM_CHAR", "WM_CHAR", MB_OK);
      break;

   default:
      lRet = DefWindowProc(hWnd, message, wParam, lParam);
   }

   return lRet;
}

