#ifndef _COMMON_GUIWINDOW_HPP_
#define _COMMON_GUIWINDOW_HPP_
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif
#ifndef _COMMON_VECTORHANDLER_HPP_
#include <common/vhandler.hpp>
#endif
#ifndef _COMMON_BLOCK_HPP_
#include <common/block.hpp>
#endif
#ifndef _COMMON_SMARTPOINTER_HPP_
#include <common/pointer.hpp>
#endif
#ifndef _COMMON_ACCELERATOR_HPP_
#include <common/accelerator.hpp>
#endif

class String;
class Rect;
class PureMenu;
class Control;
class Font;
class Point;
class GDIPoint;

#ifndef _MSC_VER
#ifdef enable
#undef enable
#endif
#endif
class GUIWindow : public VectorHandler
{
friend class Control;
public:
  GUIWindow(void);
	virtual ~GUIWindow();
	WORD operator==(const GUIWindow &someGUIWindow)const;
	operator HWND(void)const;
	bool loadAccelerators(const String &strAcceleratorTable);
	bool loadAccelerators(UINT resID);
  WORD enable(WORD isEnabled)const;
  void setFocus(void)const;
	void setFocus(GUIWindow &someGUIWindow)const;
	BOOL setCaption(const String &captionString)const;
  int show(int nCmdShow=SW_SHOW)const;
	void update(void)const;
  void clear(void)const;
	void invalidate(WORD eraseBackground=TRUE)const;
	void invalidate(const Rect &invalidRect,BOOL eraseBackground=TRUE)const;
	BOOL validate(const Rect &validRect);
	void clientRect(Rect &clientRect)const;
	void windowRect(Rect &windowRect)const;
	int windowText(String &strText)const;
	WORD clientToScreen(Rect &clientRect)const;
  WORD screenToClient(Rect &clientRect)const;
  BOOL screenToClient(GDIPoint &somePoint)const;
  BOOL clientToScreen(GDIPoint &somePoint)const;
	void size(const Point &dimensionPoint);
  WORD moveWindow(const Rect &winRect,WORD repaint=TRUE)const;
	WORD moveWindow(int left,int top,int right,int bottom,WORD repaint=TRUE)const;
	WORD top(void)const;
	void move(const Point &topLeftPoint,bool repaint=TRUE);
	void move(const GDIPoint &topleftPoint,bool repaint=true);
	WORD setTimer(WORD timerIdentifier,UINT timeOut);
	HINSTANCE processInstance(void)const;
	HWND findWindow(const String &strWindowName)const;
	HWND createWindow(const String &className,const String &windowName,DWORD dwStyle,const Rect &initRect,HWND hParentWnd,HMENU hMenu,HINSTANCE hInstance=0,void FAR *lpInstanceData=0);
  HWND createWindow(DWORD dwExStyle,const String &className,const String &windowName,DWORD dwStyle,const Rect &initRect,HWND hParentWnd,HMENU hMenu,HINSTANCE hInstance=0,void FAR *lpInstanceData=0);
  LRESULT postMessage(HWND hPostWindow,UINT message,WPARAM wParam,LPARAM lParam)const;
	LRESULT sendMessage(HWND hPostWindow,UINT message,WPARAM wParam,LPARAM lParam)const;
	LRESULT sendMessage(UINT message,WPARAM wParam,LPARAM lParam)const;
	void setFont(const Font &someFont,BOOL redraw=TRUE)const;
	WORD killTimer(WORD timerIdentifier);
	WORD width(void)const;
	BOOL width(WORD width);
	WORD height(void)const;
	bool hasChildren(void)const;
	HWND getChild(void)const;
	BOOL height(WORD height);
  BOOL setWindowPos(int width,int height)const;
	BOOL setWindowPos(const GDIPoint &startPoint,int width,int height)const;
	void destroy(void);
	void close(void);
  void postQuitMessage(int exitCode=0)const;
	WORD isVisible(void)const;
  WORD isIconic(void)const;
	HWND parent(void)const;
  HWND setCapture(void)const;
	bool hasCapture(void)const;
  BOOL setRedraw(BOOL redrawFlag)const;
	BOOL setMenu(const PureMenu &somePureMenu)const;
	BOOL setIcon(const String &strResIcon);
	BOOL drawMenuBar(void)const;
  BOOL releaseCapture(void)const;
	BOOL bringWindowToTop(void)const;
	BOOL isWindowVisible(void)const;
	String getClassName(void)const;
	WORD isValid(void)const;
	bool flash(BOOL invert)const;
	bool insertModelessDialog(GUIWindow &modelessDialog);
	void removeModelessDialog(GUIWindow &modelessDialog);
  HMENU getMenu(void)const;
  virtual int messageLoop(void)const;
  virtual void yieldTask(void)const;
	HWND getHandle(void)const;
protected:
	enum Disposition{Destroy=0x01,Assume=0x02,AssumeAndDestroy=0x03};
	GUIWindow(HWND hWnd);
	GUIWindow(const GUIWindow &someGUIWindow);
  GUIWindow &operator=(const GUIWindow &someGUIWindow);
	GUIWindow &operator=(HWND hWnd);
	void setHandle(HWND hWnd);
  LONG handlePaintMessage(HWND hWnd,WORD message,WPARAM wParam,LPARAM lParam);
	virtual int windowProcedure(HWND hWnd,WORD message,WPARAM wParam,LPARAM lParam);
#if defined(_MSC_VER)
	__declspec(dllexport) static LONG FAR PASCAL WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
	__declspec(dllexport) static BOOL FAR PASCAL DlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
	__declspec(dllexport) static UINT FAR PASCAL OFHookProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
	__declspec(dllexport) static LONG FAR PASCAL FrameProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
	__declspec(dllexport) static LONG FAR PASCAL MDIProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
#else
	static LONG FAR PASCAL _export WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
	static int FAR PASCAL _export DlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
  static UINT FAR PASCAL OFHookProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
	static LONG FAR PASCAL _export FrameProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
	static LONG FAR PASCAL _export MDIProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
#endif
private:
  typedef SmartPointer<GUIWindow> WindowPointer;
  typedef Block<WindowPointer> WindowPointerList;
	Disposition disposition(void)const;
	void disposition(Disposition disposition);

	Disposition mDisposition;
	WindowPointerList mModelessDialogs;
	Accelerator mAccelerator;
	HWND mhWnd;
};

inline
GUIWindow::GUIWindow(void)
: mhWnd(0), mDisposition(Destroy)
{
}

inline
GUIWindow::GUIWindow(HWND hWnd)
: mhWnd(0), mDisposition(Assume)
{  // private implementation
  *this=hWnd;
}

inline
GUIWindow::GUIWindow(const GUIWindow &someGUIWindow)
: mhWnd(0), mDisposition(Assume)
{ // private implementation
  *this=someGUIWindow;
}

inline
GUIWindow::operator HWND(void)const
{
  return (isValid()?mhWnd:0);
}

inline
HMENU GUIWindow::getMenu(void)const
{
  return (isValid()?::GetMenu(mhWnd):0);
}
 
inline
void GUIWindow::setHandle(HWND hWnd)
{
  mhWnd=hWnd;
}

inline
WORD GUIWindow::operator==(const GUIWindow &someGUIWindow)const
{
	return (HWND)*this==(HWND)someGUIWindow;
}

inline
BOOL GUIWindow::width(WORD width)
{
  return setWindowPos(width,height());
}

inline
BOOL GUIWindow::height(WORD height)
{
  return setWindowPos(width(),height);
}

inline
BOOL GUIWindow::setWindowPos(int width,int height)const
{
  if(!isValid())return FALSE;
	return ::SetWindowPos(*this,HWND_BOTTOM,0,0,width,height,SWP_NOMOVE|SWP_NOZORDER);
}

inline
WORD GUIWindow::enable(WORD isEnabled)const
{
  if(!isValid())return FALSE;
	return ::EnableWindow(mhWnd,isEnabled);
}

inline
void GUIWindow::setFocus(void)const
{
  if(isValid())::SetFocus(mhWnd);
}

inline
void GUIWindow::setFocus(GUIWindow &someGUIWindow)const
{
  if(!isValid()||!someGUIWindow.isValid())return;
	::SetFocus(someGUIWindow);
}

inline
WORD GUIWindow::top(void)const
{
  if(!isValid())return FALSE;
	return ::BringWindowToTop(mhWnd);
}

inline
int GUIWindow::show(int nCmdShow)const
{
	if(isValid())return ::ShowWindow(mhWnd,nCmdShow);
  return FALSE; 
}

inline
void GUIWindow::update(void)const
{
	if(isValid())::UpdateWindow(mhWnd);
}

inline
void GUIWindow::clear(void)const
{
	if(!isValid())return;
	::InvalidateRect(mhWnd,0,TRUE);
	::UpdateWindow(mhWnd);
}

inline
void GUIWindow::invalidate(WORD eraseBackGround)const
{
	if(!isValid())return;
  ::InvalidateRect(mhWnd,0,eraseBackGround);
}

inline
void GUIWindow::invalidate(const Rect &invalidRect,BOOL eraseBackground)const
{
  if(!isValid())return;
//	::InvalidateRect(mhWnd,&(RECT&)invalidRect,eraseBackground);
  ::InvalidateRect(mhWnd,&((Rect&)invalidRect).getRect(),eraseBackground);
}

inline
void GUIWindow::close(void)
{
  if(!isValid())return;
	sendMessage(*this,WM_CLOSE,0,0L);
}

inline
WORD GUIWindow::setTimer(WORD timerIdentifier,UINT timeOut)
{
	if(!isValidHandler(VectorHandler::TimerHandler,timerIdentifier))return FALSE;
	::SetTimer((HWND)*this,timerIdentifier,timeOut,0);
  return TRUE;
}

inline
GUIWindow::Disposition GUIWindow::disposition(void)const
{
	return mDisposition;
}

inline
void GUIWindow::disposition(Disposition disposition)
{
  mDisposition=disposition;
}

inline
WORD GUIWindow::isVisible(void)const
{
  if(!isValid())return FALSE;
  return ::IsWindowVisible(mhWnd);
}

inline
WORD GUIWindow::isIconic(void)const
{
  if(!isValid())return FALSE;
	return ::IsIconic(mhWnd);
}

inline
HWND GUIWindow::parent(void)const
{
  if(!isValid())return (HWND)0;
	return ::GetParent(mhWnd);
}

inline
BOOL GUIWindow::releaseCapture(void)const
{
  return ::ReleaseCapture();
}

inline
HWND GUIWindow::setCapture(void)const
{
  if(!isValid())return FALSE;
	return ::SetCapture(mhWnd);
}

inline
bool GUIWindow::hasCapture(void)const
{
  if(!isValid())return false;
	return mhWnd==::GetCapture();
}

inline
BOOL GUIWindow::setRedraw(BOOL redrawFlag)const
{
  if(!isValid())return FALSE;
	sendMessage(WM_SETREDRAW,redrawFlag,0L);
	return TRUE;
}

inline 
BOOL GUIWindow::bringWindowToTop(void)const
{
  if(!isValid())return FALSE;
	return ::BringWindowToTop(mhWnd);
}

inline
BOOL GUIWindow::isWindowVisible(void)const
{
  if(!isValid())return FALSE;
	return ::IsWindowVisible(mhWnd);
}

inline
bool GUIWindow::hasChildren(void)const
{
  if(!isValid())return false;
	return (::GetWindow(mhWnd,GW_CHILD)?true:false);
}

inline
HWND GUIWindow::getChild(void)const
{
  if(!isValid())return (HWND)0;
	return ::GetWindow(mhWnd,GW_CHILD);
}

inline
bool GUIWindow::flash(BOOL invert)const
{
  if(!isValid())return false;
	return ::FlashWindow(mhWnd,invert);
}

inline
bool GUIWindow::loadAccelerators(const String &strAcceleratorTable)
{
  return mAccelerator.loadAccelerators(strAcceleratorTable);
}

inline
bool GUIWindow::loadAccelerators(UINT resID)
{
  return mAccelerator.loadAccelerators(resID);
}

inline
HWND GUIWindow::getHandle(void)const
{
  return mhWnd;
}

inline
WORD GUIWindow::isValid(void)const
{
	return (mhWnd&&::IsWindow(mhWnd));
}
#endif
