#pragma warning (disable : 4786)

#include <windows.h>
#include <map>
#include <cassert>

#include "controller.h"
#include "create_window.h"


LRESULT CALLBACK ProceduraOkna (HWND, UINT, UINT, LONG); // deklaracja zapowiadająca

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    LPSTR lpszCmdParam, int nCmdShow)		   
{
   const char nazwa_klasy_okien[] = "OknoZbyszka";
   
   WNDCLASSEX  wndclass = {0};
   wndclass.cbSize       	= sizeof(WNDCLASSEX);
   wndclass.style        	= CS_HREDRAW | CS_VREDRAW;  
   wndclass.lpfnWndProc  	= ProceduraOkna; 
   wndclass.hInstance    	= hInstance;                
   wndclass.hCursor      	= LoadCursor (NULL, IDC_ARROW);	
   wndclass.hIcon        	= LoadIcon   (NULL, IDI_APPLICATION); 
   wndclass.hbrBackground	= (HBRUSH) GetStockObject (WHITE_BRUSH);
   wndclass.lpszClassName	= nazwa_klasy_okien;
   wndclass.hIconSm      	= LoadIcon   (NULL, IDI_APPLICATION);
   
   RegisterClassEx (&wndclass);

   HWND hwnd = NoweOkno(hInstance, nazwa_klasy_okien);
   if (hwnd == 0)
      return -1;
   
   int ok = MessageBoxEx(hwnd, 
             "Ten program demonstruje sposób obsługi myszy i klawiatury "
                     "w Windows API\n"
                     "Chyba warto w nim pobawić się myszą\n"
                     "i wypróbować różne kombinacje klawiaturowe, szczególnie:\n"
                      "\tEsc\n\tSpace\n\t(ctrl)-Strzałka",
              "Mysz",
              MB_ICONINFORMATION, 
              0);		
   
   /* Typowa pętla komunikatów: */
   int result;
   MSG msg;
   while ((result = GetMessage (&msg, NULL, 0, 0) ) != 0)
   {
      if (result == -1) return -1;
      TranslateMessage (&msg);
      DispatchMessage (&msg);            
   }	                                   
   return msg.wParam;
}

/***   PROCEDURA OKNA   ***/

LRESULT CALLBACK ProceduraOkna (HWND hwnd, UINT message,
                                UINT wParam, LONG lParam)
{
   typedef std::map<HWND, Controller*> TablicaKontrolerow;
   static TablicaKontrolerow ctrl_tab;
   Controller* pctrl = 0;
   if ( ctrl_tab.find(hwnd) != ctrl_tab.end() )
      pctrl = ctrl_tab[hwnd];

   switch(message)
   {
      
   case WM_CREATE:
      assert (ctrl_tab[hwnd] == 0);
      if (ctrl_tab[hwnd] == 0)
      {
         ctrl_tab[hwnd] = new Controller(hwnd);
         pctrl = ctrl_tab[hwnd];
      }
      else
         return -1; // Okno nie zostanie utworzone!
      return 0;
      
   case WM_PAINT:
      {
         PAINTSTRUCT ps;
         HDC hdc = BeginPaint (hwnd, &ps);     
	         pctrl->OnPaint(hdc);
         EndPaint (hwnd, &ps);
         return 0;
      }
   case WM_MOUSEMOVE:
      return pctrl->OnMouseMove((short)LOWORD(lParam), (short)HIWORD(lParam), hwnd);

   case WM_LBUTTONDOWN:
      return pctrl->OnButtonDown(0);
   
   case WM_LBUTTONUP:
      return pctrl->OnButtonUp(0);

   case WM_MBUTTONDOWN:
      return pctrl->OnButtonDown(1);
   
   case WM_MBUTTONUP:
      return pctrl->OnButtonUp(1);

   case WM_RBUTTONDOWN:
      return pctrl->OnButtonDown(2);
   
   case WM_RBUTTONUP:
      return pctrl->OnButtonUp(2);

   case WM_CHAR:
      return pctrl->OnChar(wParam); 

   case WM_KEYDOWN:
      pctrl->OnKeyDown((int)wParam);
      break;

   case WM_CLOSE:
      {
         int id = MessageBox(hwnd, 
            "Czy naprawdę chcesz zamknąć to okno?",
            "Uwaga!", MB_ICONEXCLAMATION | MB_YESNO);
         if (id == IDYES)
            DestroyWindow(hwnd);
         return 0;
      }
   case WM_DESTROY:
      {
         delete pctrl;
         ctrl_tab.erase(hwnd);
         
         if (ctrl_tab.empty())
            PostQuitMessage (0);
         return 0;
      }
   }
   return DefWindowProc (hwnd, message, wParam, lParam);
}
