/* The original version of this program can be found at http://damb.dk */
#include <windows.h>
#include <commctrl.h>
#include <string>
#include <sstream>

enum WindowsId
{
   FirstEditId = 256,
   FirstUpDownId,
   SecondEditId,
   SecondUpDownId,
   ResultListBoxId,
   SubRadioId,
   AddRadioId,
   HexCheckId,
   ButtonId,
   GroupBoxId,
   ProgressCtrlId
};

enum TimerId
{
   ProgressTimer = 1024
};

template <typename T>
std::string ToString(T aValue)
{
   std::stringstream ss;
   ss << aValue;
   return ss.str();
}

template <typename T>
std::string ToStringHex(T aValue)
{
   std::stringstream ss;
   ss << std::hex << aValue;
   return ss.str();
}

HINSTANCE InstanceHandle;
bool TimerRunning;
int TimerIdx;

void AddListText(HWND aMainWnd, const char *aMsg)
{
   static int MaxWidth;
   HWND List = GetDlgItem(aMainWnd, ResultListBoxId);
   int idx = SendMessage(List, LB_ADDSTRING, 0, (LPARAM )aMsg);
   SendMessage(List, LB_SETCARETINDEX, idx, 0);

   HDC dc = GetDC(List);
   HFONT Font = (HFONT )SendMessage(aMainWnd, WM_GETFONT, 0, 0);
   HFONT OldFont = (HFONT )SelectObject(dc, Font);
   SIZE TextSize;
   GetTextExtentPoint32(dc, aMsg, strlen(aMsg), &TextSize);
   TextSize.cx += 10;

   if(TextSize.cx > MaxWidth)
   {
      MaxWidth = TextSize.cx;
      SendMessage(List, LB_SETHORIZONTALEXTENT, MaxWidth, 0);
   }
   SelectObject(dc, OldFont);
   ReleaseDC(List, dc);
}

void OnSize(HWND aMainWnd, int aWidth, int aHeight)
{
   HWND Control;
   Control = GetDlgItem(aMainWnd, ResultListBoxId);
   MoveWindow(Control, 5, 60, aWidth - 10, aHeight - 170, FALSE);
   Control = GetDlgItem(aMainWnd, AddRadioId);
   MoveWindow(Control, 10, aHeight - 90, 50, 14, FALSE);
   Control = GetDlgItem(aMainWnd, SubRadioId);
   MoveWindow(Control, 60, aHeight - 90, 50, 14, FALSE);
   Control = GetDlgItem(aMainWnd, HexCheckId);
   MoveWindow(Control, 120, aHeight - 90, 50, 14, FALSE);
   Control = GetDlgItem(aMainWnd, GroupBoxId);
   MoveWindow(Control, 5, aHeight - 110, 110, 40, FALSE);
   Control = GetDlgItem(aMainWnd, ButtonId);
   MoveWindow(Control, 5, aHeight - 62, 75, 25, FALSE);
   Control = GetDlgItem(aMainWnd, ProgressCtrlId);
   MoveWindow(Control, 5, aHeight - 32, aWidth - 10, 25, FALSE);
}

BOOL CALLBACK SetFontProc(HWND aHwnd, LPARAM lParam)
{
   SendMessage(aHwnd, WM_SETFONT, lParam, TRUE);
   return TRUE;
}

LRESULT CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg)
   {
   case WM_CREATE:
      CreateWindowEx(WS_EX_CLIENTEDGE,
                     "EDIT",
                     "",
                     WS_CHILD | WS_VISIBLE | ES_NUMBER | WS_TABSTOP | WS_GROUP,
                     5, 5, 120, 20,
                     hwndDlg,
                     (HMENU)(FirstEditId),
                     InstanceHandle,
                     0);

      CreateWindow(UPDOWN_CLASS,
                   "Spin1",
                   UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT | WS_CHILD | WS_VISIBLE | UDS_ARROWKEYS,
                   105, 5, 20, 20,
                   hwndDlg,
                   (HMENU )FirstUpDownId,
                   InstanceHandle,
                   0);
      SendDlgItemMessage(hwndDlg, FirstUpDownId, UDM_SETRANGE, 0, MAKELONG(100, -100));

      CreateWindowEx(WS_EX_CLIENTEDGE,
                     "EDIT",
                     "",
                     WS_CHILD | WS_VISIBLE | ES_NUMBER | WS_TABSTOP,
                     5, 35, 120, 20,
                     hwndDlg,
                     (HMENU)(SecondEditId),
                     InstanceHandle,
                     0);

      CreateWindow(UPDOWN_CLASS,
                   "Spin2",
                   UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_SETBUDDYINT | WS_CHILD | WS_VISIBLE | UDS_ARROWKEYS,
                   105, 35, 20, 20,
                   hwndDlg,
                   (HMENU )SecondUpDownId,
                   InstanceHandle,
                   0);
      SendDlgItemMessage(hwndDlg, SecondUpDownId, UDM_SETRANGE, 0, MAKELONG(100, -100));

      CreateWindowEx(WS_EX_CLIENTEDGE,
                     "LISTBOX",
                     "0",
                     WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | WS_HSCROLL,
                     5, 65, 120, 80,
                     hwndDlg,
                     (HMENU )ResultListBoxId,
                     InstanceHandle,
                     0);

      CreateWindow("BUTTON",
                   "Add",
                   WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTORADIOBUTTON,
                   10, 155, 50, 14,
                   hwndDlg,
                   (HMENU )AddRadioId,
                   InstanceHandle,
                   0);

      CreateWindow("BUTTON",
                   "Sub",
                   WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTORADIOBUTTON,
                   65, 155, 50, 14,
                   hwndDlg,
                   (HMENU )SubRadioId,
                   InstanceHandle,
                   0);

      CreateWindow("BUTTON",
                   "Hex",
                   WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX,
                   120, 155, 50, 14,
                   hwndDlg,
                   (HMENU )HexCheckId,
                   InstanceHandle,
                   0);

      CreateWindow("BUTTON",
                   "Calculate",
                   WS_CHILD | WS_VISIBLE | WS_TABSTOP,
                   5, 180, 120, 30,
                   hwndDlg,
                   (HMENU )ButtonId,
                   InstanceHandle,
                   0);

      CreateWindow("BUTTON",
                   "Action",
                   WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
                   5, 135, 120, 40,
                   hwndDlg,
                   (HMENU )GroupBoxId,
                   InstanceHandle,
                   0);
      CreateWindow(PROGRESS_CLASS,
                   "",
                   WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
                   5, 100, 100, 20,
                   hwndDlg,
                   (HMENU )ProgressCtrlId,
                   InstanceHandle,
                   0);
      SendDlgItemMessage(hwndDlg, ProgressCtrlId, PBM_SETRANGE, 0, MAKELPARAM(0, 50));
      CheckDlgButton(hwndDlg, AddRadioId, BST_CHECKED);
      EnumChildWindows(hwndDlg, SetFontProc, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
      break;
   case WM_GETMINMAXINFO:
   {
      MINMAXINFO *MinMaxInfo = (MINMAXINFO *)lParam;
      MinMaxInfo->ptMinTrackSize.x = 140;
      MinMaxInfo->ptMinTrackSize.y = 250;
      break;
   }
   case WM_SIZE:
      OnSize(hwndDlg, LOWORD(lParam), HIWORD(lParam));
      break;
   case WM_COMMAND:
      if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == ButtonId)
      {
         if(!TimerRunning)
         {
            TimerIdx = 1;
            TimerRunning = true;
            SetTimer(hwndDlg, ProgressTimer, 100, 0);
            SendDlgItemMessage(hwndDlg, ProgressCtrlId, PBM_SETPOS, TimerIdx, 0);
         }
      }
      break;
   case WM_TIMER:
      TimerIdx++;
      SendDlgItemMessage(hwndDlg, ProgressCtrlId, PBM_SETPOS, TimerIdx, 0);
      if(TimerIdx > 50)
      {
         KillTimer(hwndDlg, ProgressTimer);
         TimerRunning = false;
         int First = GetDlgItemInt(hwndDlg, FirstEditId, 0, FALSE);
         int Second = GetDlgItemInt(hwndDlg, SecondEditId, 0, FALSE);
         int Result;
         std::string ResultString;
         std::string Op;
         if(IsDlgButtonChecked(hwndDlg, AddRadioId))
         {
            Result = First + Second;
            Op = " + ";
         }
         else
         {
            ResultString = ToString(First) + " - " + ToString(Second) + " = " + ToString(Result);
            Op = " - ";
         }
         ResultString = ToString(First) + Op + ToString(Second) + " = ";
         bool DoHex = SendDlgItemMessage(hwndDlg, HexCheckId, BM_GETCHECK, 0, 0) == BST_CHECKED;
         if(DoHex)
            ResultString += std::string("0x") + ToStringHex(Result);
         else
            ResultString += ToString(Result);
         AddListText(hwndDlg, ResultString.c_str());
         break;
      }
   }
   return DefWindowProc(hwndDlg, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, INT nCmdShow)
{
   InstanceHandle = hInstance;
   InitCommonControls();
   WNDCLASS wc;
   memset(&wc, 0, sizeof(WNDCLASS));
   wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
   wc.lpfnWndProc = DialogProc;
   wc.hInstance = InstanceHandle;
   wc.hbrBackground = (HBRUSH )(COLOR_BTNFACE + 1);
   wc.lpszClassName = "WhateverClass";
   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
   if(!RegisterClass(&wc))
      return FALSE;

   HWND WindowHandle = CreateWindow("WhateverClass",
                                    "Calc", // Caption text
                                    WS_MINIMIZEBOX | WS_VISIBLE | WS_MAXIMIZEBOX |
                                    WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_THICKFRAME,
                                    100, 100, 180, 245,  // Position
                                    NULL,
                                    NULL,
                                    InstanceHandle,
                                    0);
   MSG Msg;
   while(GetMessage(&Msg, WindowHandle, 0, 0xFFFF) > 0)
   {
      if(!IsDialogMessage(WindowHandle, &Msg))
      {
         TranslateMessage(&Msg);
         DispatchMessage(&Msg);
      }
   }
   return 0;
}