/***************************************************************************
                             Wnd.cpp
                             -------------------
    Begin                : Sun Oct 7,2001
    Objective            : Winwdow wrapper class
    Author               : Drew Hall
    Email                : dhall@Zero-Soft.com
 ***************************************************************************/

#include "stdafx.h"

WndMap CWnd::m_WndMap;


CWnd::CWnd() : m_hWnd(NULL), m_hMenu(NULL)
{
   m_hInst = GetModuleHandle(NULL);  
}

CWnd::~CWnd()
{
   if(m_hWnd)
      m_WndMap.erase(m_hWnd);
}

// Ridiculous cast needed b/c CreateDilog wants a boolean return while CreateWindow wants a long....
bool CWnd::DoModal(int nTemplate, HWND hWndParent)
{
   assert(nTemplate != NULL);
   m_hWnd = ::CreateDialogParam(m_hInst, MAKEINTRESOURCE(nTemplate), hWndParent, 
                               (int(__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))BounceProc, 
                                reinterpret_cast<long>(this));
   if(m_hWnd == NULL)
      return false;
   
   return true;
}

bool CWnd::CreateDlg(LPCDLGTEMPLATE lpTemplate, HWND hWndParent)
{
   assert(lpTemplate != NULL);
   m_hWnd = ::CreateDialogIndirectParam(m_hInst, lpTemplate, hWndParent, 
                                       (int(__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))BounceProc, 
                                        reinterpret_cast<long>(this));
   if(m_hWnd == NULL)
      return false;

   return true;
}

bool CWnd::RegisterAtom(const TCHAR* szClassName, HMENU hMenu)
{
   wc.cbSize        = sizeof(WNDCLASSEX);
   wc.style         = NULL;
   wc.lpfnWndProc   = BounceProc;
   wc.cbClsExtra    = 0;
   wc.cbWndExtra    = 0;
   wc.hInstance     = m_hInst;
   wc.hIcon         = NULL;
   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
   wc.lpszMenuName  = NULL;
   wc.lpszClassName = szClassName;
   wc.hIconSm       = NULL;

   m_hMenu = hMenu;

   if(!RegisterClassEx(&wc))
   {
      MessageBox(TEXT("Window Registration Failed!"), TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
      return false;
   }

   return true;
}

bool CWnd::Create(const TCHAR* szClassName, const TCHAR* szWindowTitle, HMENU hMenu, int x, int y, int nCmdShow)
{
   if(!RegisterAtom(szClassName, hMenu))
      return false;
   
   m_hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, szClassName, szWindowTitle, WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT, CW_USEDEFAULT, x, y, NULL, hMenu, m_hInst, this);
  
   if(m_hWnd == NULL)
   {
      MessageBox(TEXT("Window Creation Failed!"), TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
      return 0;
   }

   ShowWindow(m_hWnd, nCmdShow);
   UpdateWindow(m_hWnd);

   MessagePump();
   
   return true;
}

int CWnd::OnCreate(LPCREATESTRUCT lpcs)
{
   return false;
}

bool CWnd::OnInitDialog(HWND hWndFocus)
{
   return true;
}


bool CWnd::OnCommand(int nID, HWND hWndCtrl, UINT nCodeNotify)
{
   return true;
}

bool CWnd::OnSize(UINT nState, int cx, int cy)
{
   return true;
}


bool CWnd::OnPaint()
{
   return false;
}


bool CWnd::OnKey(UINT vk, bool fDown, int nRepeat, UINT nFlags)
{
   return true;
}

bool CWnd::OnTimer(int nID)
{
   return true;
}

bool CWnd::OnClose()
{
   DestroyWindow(m_hWnd);
   return true;
}

bool CWnd::OnDestroy()
{
   PostQuitMessage(0);
   return true;
}

int CWnd::MessagePump()
{
   MSG Msg;
 
   while(GetMessage(&Msg, NULL, 0, 0))
   {
      TranslateMessage(&Msg);
      DispatchMessage(&Msg);
   }
   
   return Msg.wParam;
}

LRESULT CWnd::WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
   switch(nMsg)
   {
      case WM_NCCREATE:
         m_hWnd = hWnd;
         if(!AddCWnd(hWnd, this))
         {
            MessageBox(TEXT("Could not add pointer to map"), TEXT("Error"), MB_OK);
            return false;
         }
         return DefWindowProc(hWnd, nMsg, wParam, lParam);
      
      case WM_INITDIALOG:
         m_hWnd = hWnd;
         if(!AddCWnd(hWnd, this))
         {
            MessageBox(TEXT("Could not add pointer to map"), TEXT("Error"), MB_OK);
            return false;
         }
         return OnInitDialog(reinterpret_cast<HWND>(wParam));

      case WM_CREATE:
         return OnCreate(reinterpret_cast<LPCREATESTRUCT>(lParam));

      case WM_COMMAND:
         return OnCommand(static_cast<int>(LOWORD(wParam)), reinterpret_cast<HWND>(lParam), 
                          static_cast<int>(HIWORD(wParam)));

      case WM_SIZE:
         return OnSize(static_cast<UINT>(wParam), static_cast<int>(LOWORD(lParam)), 
                       static_cast<int>(HIWORD(lParam)));

      case WM_PAINT:
         OnPaint();
         return DefWindowProc(hWnd, nMsg, wParam, lParam);

      case WM_KEYDOWN:
         return OnKey(static_cast<UINT>(wParam),true, static_cast<int>(LOWORD(lParam)), 
                      static_cast<UINT>(HIWORD(lParam)));
      
      case WM_KEYUP:
         return OnKey(static_cast<UINT>(wParam), false, static_cast<int>(LOWORD(lParam)),
                      static_cast<UINT>(HIWORD(lParam)));

      case WM_TIMER:
         return OnTimer(static_cast<UINT>(wParam));
        
      case WM_CLOSE:
         return OnClose();

      case WM_DESTROY:
         return OnDestroy();

      default:
         return DefWindowProc(hWnd, nMsg, wParam, lParam);
   }
   
   return false;
}

HWND CWnd::GetHwnd()
{
   return m_hWnd;
}

HMENU CWnd::GetMenu()
{
   return m_hMenu;
}

HINSTANCE CWnd::GetInstance()
{
   return m_hInst;
}

int CWnd::GetClientRect(RECT* rect)
{
   return ::GetClientRect(m_hWnd, rect);
}

int CWnd::GetWindowRect(RECT* rect)
{
   return ::GetWindowRect(m_hWnd, rect);
}

long CWnd::GetWindowLong(int nIndex)
{
   return ::GetWindowLong(m_hWnd, nIndex);
}

long CWnd::SetWindowLong(int nIndex, long dwData)
{
   return ::SetWindowLong(m_hWnd, nIndex, dwData);
}

int CWnd::MoveWindow(LPRECT lpRect, bool bRepaint)
{
   return MoveWindow(lpRect->left, lpRect->top, (lpRect->right - lpRect->left), 
                     (lpRect->bottom - lpRect->top), bRepaint);
}

int CWnd::MoveWindow(int x, int y, int nWidth, int yHeight, bool bRepaint)
{
   return ::MoveWindow(m_hWnd, x, y, nWidth, yHeight, bRepaint);
}

int CWnd::SetWindowText(const TCHAR* szTitle)
{
   return ::SetWindowText(m_hWnd, szTitle);
}

int CWnd::GetWindowText(TCHAR* szTitle, int nLen)
{
   return ::GetWindowText(m_hWnd, szTitle, nLen);
}

int CWnd::SetWindowPos(HWND hWndAfter, int x, int y, int nWidth, int yHeight, UINT nFlags)
{
   return ::SetWindowPos(m_hWnd, hWndAfter, x, y, nWidth, yHeight, nFlags);
}

int CWnd::CenterWindow(HWND hWndParent, bool bRepaint)
{
   RECT rc1, rc2, *lprc;
   int nWidth, nHeight, cxCenter, cyCenter;

   if(!hWndParent)
      hWndParent = GetDesktopWindow();

   ::GetWindowRect(hWndParent, &rc2);
   lprc = (RECT*)&rc2;

   cxCenter = lprc->left+((lprc->right - lprc->left)/2);
   cyCenter = lprc->top+((lprc->bottom - lprc->top)/2);

   GetWindowRect(&rc1);
   nWidth = rc1.right - rc1.left;
   nHeight = rc1.bottom - rc1.top;

   return MoveWindow(cxCenter-(nWidth/2), cyCenter-(nHeight/2), nWidth, nHeight, bRepaint);
}



LRESULT CALLBACK BounceProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
   CWnd *pWnd = CWnd::LookupCWnd(hWnd);
   if(nMsg == WM_NCCREATE)
      return ((CWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams)->WndProc(hWnd, nMsg, wParam, lParam);
   else if(nMsg == WM_INITDIALOG)
      return ((CWnd*)(lParam))->WndProc(hWnd, nMsg, wParam, lParam);
   else if(pWnd != NULL)
      return pWnd->WndProc(hWnd, nMsg, wParam, lParam);
   else
      return DefWindowProc(hWnd, nMsg, wParam, lParam);

   return true;
}

bool CWnd::AddCWnd(HWND hwnd, CWnd* cWnd)
{
   m_WndMap.insert(WndMap::value_type(hwnd, cWnd));

   return true;
}

CWnd* CWnd::LookupCWnd(HWND hwnd)
{
   WndMap::iterator itor;
   itor = m_WndMap.find(hwnd);
   if(itor == m_WndMap.end())
      return NULL;

   return (CWnd*)((*itor).second);;
}

int CWnd::MessageBox(const TCHAR* szText, const TCHAR* szTitle, UINT nType)
{
   return ::MessageBox(m_hWnd, szText, szTitle, nType);
}
