/* The original version of this program can be found at http://damb.dk */
#define _WIN32_IE  0x0500
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <vector>

HINSTANCE InstanceHandle;
HWND      MainWindow;
HWND      StatusBarWindow;
HWND      ToolBarWindow;

enum MenuCommand
{
   FileOpenCmd = 1000,
   FileSaveCmd,
   FileCloseCmd,
   FileOpen1Cmd,
   FileOpen2Cmd,
   FileOpen3Cmd,
   AboutCmd
};

enum WindowId
{
   StatusBarId = 128,
   ToolBarId
};

class LineClass
{
public:
   LineClass(POINT aStart) :
      Start(aStart),
      End(aStart),
      First(true)
   {}

   void SetEnd(HDC &aDc, POINT aEnd)
   {
      Draw(aDc, true);
      End = aEnd;
      Draw(aDc, true);
   }
   void Draw(HDC &dc, bool aMoving = false);
private:
   bool First;
   POINT Start;
   POINT End;
};

void LineClass::Draw(HDC &aDc, bool aMoving)
{
   if(First)
   {
      First = false;
      return;
   }

   if(aMoving)
   {
      SetROP2(aDc, R2_NOTXORPEN);
   }
   else
   {
      SetROP2(aDc, R2_COPYPEN);
   }
   HPEN Pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
   HPEN OldPen = (HPEN )SelectObject(aDc, Pen);
   MoveToEx(aDc, Start.x, Start.y, 0);
   LineTo(aDc, End.x, End.y);
   SelectObject(aDc, OldPen);
   DeleteObject(Pen);
}

std::vector<LineClass >Lines;
bool IsDrawing;

void OnLButtonDown(HWND aHwnd, int aX, int aY)
{
   POINT P;
   P.x = aX;
   P.y = aY;
   LineClass Line(P);
   Lines.push_back(Line);
   IsDrawing = true;
}

void OnMouseMove(HWND aHwnd, int aX, int aY)
{
   if(IsDrawing)
   {
      POINT P;
      P.x = aX;
      P.y = aY;
      HDC dc = GetDC(aHwnd);
      LineClass &Last = Lines.back();
      Last.SetEnd(dc, P);
   }
}

void OnLButtonUp(HWND aHwnd, int aX, int aY)
{
   if(IsDrawing)
   {
      POINT P;
      P.x = aX;
      P.y = aY;
      LineClass &Last = Lines.back();
      HDC dc = GetDC(aHwnd);
      Last.SetEnd(dc, P);
      Last.Draw(dc);
      ReleaseDC(aHwnd, dc);
      IsDrawing = false;
   }
}

void OnPaint(HWND aHwnd)
{
   PAINTSTRUCT PaintStruct;
   BeginPaint(aHwnd, &PaintStruct);
   size_t i;
   for(i = 0; i < Lines.size(); i++)
      Lines[i].Draw(PaintStruct.hdc);
   EndPaint(aHwnd, &PaintStruct);
}

void SetStatusBarWidths(HWND ParentWindow)
{
   int BoxRight[3];
   RECT ParentRect;
   GetClientRect(ParentWindow, &ParentRect);
   int Width = ParentRect.right - ParentRect.left;
   BoxRight[0] = 100;
   BoxRight[1] = Width - 100;
   BoxRight[2] = -1;
   SendMessage(StatusBarWindow, SB_SETPARTS, 3, (LPARAM )BoxRight);
}

void SetStatusBarText(const char *Text, WORD PartNumber)
{
   SendMessage(StatusBarWindow, SB_SETTEXT, PartNumber, (LPARAM )Text);
}

bool CreateToolBar(HWND ParentWindow)
{
   const int NumButton = 5;

   ToolBarWindow = CreateWindowEx(0,
                                  TOOLBARCLASSNAME,
                                  0,
                                  WS_CHILD|WS_BORDER,
                                  0, 0, 0, 0,
                                  ParentWindow,
                                  (HMENU )ToolBarId,
                                  InstanceHandle,
                                  0);
   SendMessage(ToolBarWindow,
               TB_BUTTONSTRUCTSIZE,
               (WPARAM )sizeof(TBBUTTON),
               0);

   TBADDBITMAP TBaddBitmap;
   TBaddBitmap.hInst = HINST_COMMCTRL;
   TBaddBitmap.nID   = IDB_STD_SMALL_COLOR;
   SendMessage(ToolBarWindow,
               TB_ADDBITMAP,
               (WPARAM )NumButton,
               (LPARAM )&TBaddBitmap);

   TBBUTTON ButtonInfo[NumButton];
   memset(ButtonInfo, 0, sizeof(ButtonInfo));
   int idx;
   idx = SendMessage(ToolBarWindow,
                     TB_ADDSTRING,
                     0,
                     (LPARAM )"");
   ButtonInfo[0].iString = idx;
   ButtonInfo[0].iBitmap = STD_FILEOPEN;
   ButtonInfo[0].idCommand = 0;
   ButtonInfo[0].fsState = TBSTATE_ENABLED;
   ButtonInfo[0].fsStyle = BTNS_SEP;

   idx = SendMessage(ToolBarWindow,
                     TB_ADDSTRING,
                     0,
                     (LPARAM )"Open");
   ButtonInfo[1].iString = idx;
   ButtonInfo[1].iBitmap = STD_FILEOPEN;
   ButtonInfo[1].idCommand = FileOpenCmd;
   ButtonInfo[1].fsState = TBSTATE_ENABLED;
   ButtonInfo[1].fsStyle = BTNS_DROPDOWN;

   idx = SendMessage(ToolBarWindow,
                     TB_ADDSTRING,
                     0,
                     (LPARAM )"");
   ButtonInfo[2].iString = idx;
   ButtonInfo[2].iBitmap = STD_FILEOPEN;
   ButtonInfo[2].idCommand = 0;
   ButtonInfo[2].fsState = TBSTATE_ENABLED;
   ButtonInfo[2].fsStyle = BTNS_SEP;

   idx = SendMessage(ToolBarWindow,
                     TB_ADDSTRING,
                     0,
                     (LPARAM )"Save");
   ButtonInfo[3].iString = idx;
   ButtonInfo[3].iBitmap = STD_FILESAVE;
   ButtonInfo[3].idCommand = FileSaveCmd;
   ButtonInfo[3].fsState = TBSTATE_ENABLED;
   ButtonInfo[3].fsStyle = TBSTYLE_BUTTON;

   idx = SendMessage(ToolBarWindow,
                     TB_ADDSTRING,
                     0,
                     (LPARAM )"About");
   ButtonInfo[4].iString = idx;
   ButtonInfo[4].iBitmap = STD_HELP;
   ButtonInfo[4].idCommand = AboutCmd;
   ButtonInfo[4].fsState = TBSTATE_ENABLED;
   ButtonInfo[4].fsStyle = TBSTYLE_BUTTON;

   SendMessage(ToolBarWindow,
               TB_ADDBUTTONS,
               NumButton,
               (LPARAM)&ButtonInfo);
   SendMessage(ToolBarWindow, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
   ShowWindow(ToolBarWindow, SW_SHOW);
   return true;
}

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg)
   {
      case WM_DESTROY:
         PostQuitMessage(0);
         break;
      case WM_NOTIFY:
         if(wParam == ToolBarId)
         {
            NMHDR *Header = (NMHDR *)lParam;
            if(Header->code == TBN_DROPDOWN)
            {
               HMENU Menu = CreatePopupMenu();
               AppendMenu(Menu, MF_STRING, FileOpen1Cmd, "Open1");
               AppendMenu(Menu, MF_STRING, FileOpen2Cmd, "Open2");
               AppendMenu(Menu, MF_STRING, FileOpen3Cmd, "Open3");
               RECT Rect;
               SendMessage(ToolBarWindow, TB_GETRECT, FileOpenCmd, (LPARAM )&Rect);
               POINT P;
               P.x = Rect.right;
               P.y = Rect.top;
               ClientToScreen(hwnd, &P);
               TrackPopupMenu(Menu, TPM_LEFTALIGN, P.x, P.y, 0, hwnd, 0);
            }
         }
         break;
      case WM_SIZE:
         SendMessage(StatusBarWindow, msg, wParam, lParam);
         SendMessage(ToolBarWindow, msg, wParam, lParam);
         SetStatusBarWidths(hwnd);
         break;
      case WM_COMMAND:
         switch(LOWORD(wParam))
         {
         case FileOpenCmd:
             MessageBox(hwnd, "Open", "Test", MB_OK);
             break;
         case FileOpen1Cmd:
             MessageBox(hwnd, "Open1", "Test", MB_OK);
             break;
         case FileOpen2Cmd:
             MessageBox(hwnd, "Open2", "Test", MB_OK);
             break;
         case FileOpen3Cmd:
             MessageBox(hwnd, "Open3", "Test", MB_OK);
             break;
         case FileSaveCmd:
             MessageBox(hwnd, "Save", "Test", MB_OK);
             break;
         case FileCloseCmd:
             MessageBox(hwnd, "Close", "Test", MB_OK);
             break;
         case AboutCmd:
             MessageBox(hwnd, "About", "Test", MB_OK);
             break;
         }
         break;

      case WM_LBUTTONDOWN:
         OnLButtonDown(hwnd, LOWORD(lParam), HIWORD(lParam));
         break;
      case WM_MOUSEMOVE:
         OnMouseMove(hwnd, LOWORD(lParam), HIWORD(lParam));
         break;
      case WM_LBUTTONUP:
         OnLButtonUp(hwnd, LOWORD(lParam), HIWORD(lParam));
         break;
      case WM_PAINT:
         OnPaint(hwnd);
         break;
      default:
         return DefWindowProc(hwnd,msg,wParam,lParam);
   }
   return 0;
}

HWND CreateMainWindow()
{
   WNDCLASS wc;
   memset(&wc, 0, sizeof(WNDCLASS));
   wc.style = CS_HREDRAW | CS_VREDRAW  | CS_DBLCLKS ;
   wc.lpfnWndProc = (WNDPROC )MainWndProc;
   wc.hInstance = InstanceHandle;
   wc.hbrBackground = (HBRUSH )(COLOR_WINDOW + 1);
   wc.lpszClassName = "SimpleWinWndClass";
   wc.lpszMenuName = 0;
   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
   if(!RegisterClass(&wc))
      return 0;

   HMENU FileMenu = CreateMenu();
   AppendMenu(FileMenu, MF_STRING, FileOpenCmd, "Open");
   AppendMenu(FileMenu, MF_STRING, FileSaveCmd, "Save");
   AppendMenu(FileMenu, MF_SEPARATOR, 0 , 0);
   AppendMenu(FileMenu, MF_STRING, FileCloseCmd, "Close");

   HMENU HelpMenu = CreateMenu();
   AppendMenu(HelpMenu, MF_STRING, AboutCmd, "About");

   HMENU MainMenu = CreateMenu();
   AppendMenu(MainMenu, MF_POPUP, (UINT )FileMenu, "File");
   AppendMenu(MainMenu, MF_POPUP, (UINT )HelpMenu, "Help");

   return CreateWindow("SimpleWinWndClass",
                       "Simple-Window",
                       WS_MINIMIZEBOX | WS_VISIBLE |
                       WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_MAXIMIZEBOX |
                       WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_THICKFRAME,
                       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
                       0,
                       MainMenu,
                       InstanceHandle,
                       0);
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   INT nCmdShow)
{
   InstanceHandle = hInstance;
   if((MainWindow = CreateMainWindow()) == (HWND )0)
   {
      MessageBox(0, "Failed to create MainWindow!", "Warning", MB_OK);
      return 0;
   }
   StatusBarWindow = CreateStatusWindow(WS_CHILD|WS_VISIBLE|WS_BORDER|SBARS_SIZEGRIP,
                                        "Ready",
                                        MainWindow,
                                        StatusBarId);

   SetStatusBarWidths(MainWindow);
   CreateToolBar(MainWindow);
   ShowWindow(MainWindow, SW_SHOW);
   SetStatusBarText("First",  0);
   SetStatusBarText("Middle", 1);
   SetStatusBarText("Right",  2);
   MSG Msg;
   while(GetMessage(&Msg, 0, 0, 0))
   {
      TranslateMessage(&Msg);
      DispatchMessage(&Msg);
   }
   return Msg.wParam;
}