#include "xuserwnd.h"
#include "xrect.h"
#include "xexcept.h"
#include "xcntrevn.h"
#include "stdlib.h"
#include "xreslib.h"
#include "xbubble.h"
#include "xtimer.h"
#include "xbitmap.h"
#include "xgraphdv.h"
#include "xres.h"
#include "xprocess.h"
#include "xmoushdl.h"
#include "xfont.h"
#include "xmousevn.h"
#include "XText.h"


MRESULT EXPENTRY userProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
	XWindow *win = (XUserWindow *) WinQueryWindowPtr(hwnd, 0);

	if (msg == WM_CREATE)
	{
		WinSetWindowPtr(hwnd, 0, (void *) mp1);
		mp1 = 0;
		return WinDefWindowProc(hwnd, msg, mp1, mp2);
	}

	if (win)
	{
		BOOL handled = FALSE;
		MRESULT mr = HandleDefault(win, msg, mp1, mp2, handled);

		if (handled)
			return mr;
	}

	return WinDefWindowProc(hwnd, msg, mp1, mp2);
}


XUserWindow :: XUserWindow(const XWindow * w)
{
	if (w)
		XUserWindow(w->GetClientHandle());
	else
		XUserWindow(HWND_DESKTOP);
}


XUserWindow :: XUserWindow(const LONG handle)
{
	if (WinRegisterClass(WinQueryAnchorBlock(handle), (PSZ) "OOL_USERCLASS", (PFNWP) userProc, 0, 4) == FALSE)
		OOLThrow("error creating userwindow - couldnït register class", -10);

	winhandle = WinCreateWindow(handle, (PSZ) "OOL_USERCLASS", (PSZ) "", WS_VISIBLE | FS_SCREENALIGN,
								0, 0, 0, 0, handle, HWND_TOP, 0, this, 0);
}


XUserWindow :: XUserWindow(const XResource * r)
{
	if (WinRegisterClass(r->GetResourceLibrary()->GetProcess()->hab, (PSZ) "OOL_USERCLASS", (PFNWP) userProc, 0, 4) == FALSE)
		OOLThrow("error creating userwindow - couldnït register class", -10);

	winhandle = WinCreateWindow(HWND_DESKTOP, (PSZ) "OOL_USERCLASS", (PSZ) "", WS_VISIBLE | FS_SCREENALIGN,
							  0, 0, 0, 0, HWND_DESKTOP, HWND_TOP, 0, this, 0);
	if (winhandle == 0)
		OOLThrow("error creating userwindow", -10);
}


XUserWindow :: ~XUserWindow()
{
	HWND hwnd;

	HENUM enumWindow = WinBeginEnumWindows(winhandle);

	while ((hwnd = WinGetNextWindow(enumWindow)) != NULLHANDLE)
	{
		XWindow *w = (XWindow *) WinQueryWindowPtr(hwnd, 0);

		if (w && w != this)
			delete w;
	};
	WinEndEnumWindows(enumWindow);
	WinDestroyWindow(winhandle);
}


class bubbletimer:public XTimer
{
		XBubbleHelp *bubble;
	public:
		ULONG id;
		bubbletimer(XBubbleHelp * w):XTimer(w) {	bubble = w;	}
		void TimerEvent(void);
};


void bubbletimer::TimerEvent(void)
{
	POINTL p;
	POINTL buffer;

	if (!bubble->isActive)
		return;
	WinQueryPointerPos(HWND_DESKTOP, &p);
	buffer = p;
	SWP swp;

	WinMapWindowPoints(HWND_DESKTOP, bubble->aktWin->GetHandle(), &buffer, 1);
	WinQueryWindowPos(bubble->aktWin->GetHandle(), &swp);

	if (!(buffer.x > 0 && buffer.x < swp.cx && buffer.y > 0 && buffer.y < swp.cy))
		return;

	XRect rect;

	if (bubble->SetMsgText(id) == FALSE)
		return;
	rect.SetX(p.x);
	rect.SetY(p.y + 2);
	rect.SetWidth(174);
	rect.SetHeight(71);
	bubble->SetSize(&rect);
	bubble->Show();
	Stop();
}


class bhandler:public XMouseHandler
{
	XBubbleHelp *bubble;
	    public:
	    bhandler(XBubbleHelp * b, XWindow * w):XMouseHandler(w)
	{
		bubble = b;
	}
	BOOL HandleEvent(XMouseEvent *);
};


BOOL bhandler::HandleEvent(XMouseEvent *)
{
	if (bubble->IsVisible())
		bubble->Show(FALSE);
	bubble->timer->Stop();
	return TRUE;
}


class bubblehandler:public XMouseHandler
{
		XBubbleHelp *bubble;
	public:
		bubblehandler(XBubbleHelp * b, XWindow * w):XMouseHandler(w) {	bubble = b;	}
		BOOL HandleEvent(XMouseEvent *);
};


BOOL bubblehandler::HandleEvent(XMouseEvent * e)
{
	switch (e->GetEventID())
	{
	default:
		if (bubble->IsVisible())
			bubble->Show(FALSE);
		bubble->timer->Stop();
		break;
	case MOU_MOVE:
		{
			POINTL buffer;

			HWND i = 0;
			SWP swp;

			WinQueryPointerPos(HWND_DESKTOP, &buffer);
			WinMapWindowPoints(HWND_DESKTOP, GetWindow()->GetHandle(), &buffer, 1);
			WinQueryWindowPos(GetWindow()->GetHandle(), &swp);

			if (buffer.x > 0 && buffer.x < swp.cx && buffer.y > 0 && buffer.y < swp.cy)
				i = GetWindow()->GetHandle();
			if (i)
			{
				if (!bubble->IsVisible() && bubble->isActive)
				{
					bubble->timer->id = WinQueryWindowUShort(GetWindow()->GetHandle(), QWS_ID);
					bubble->aktWin = GetWindow();
					bubble->timer->Start(1000);
				}
			}
			else
			{
				bubble->Show(FALSE);
				bubble->timer->Stop();
			}
		}
	}
	return FALSE;
}


/*@ XBubbleHelp::SetMsgText()
@group text functions
@remarks Override this function to select the text to display with SetText()
@parameters ULONG id    the window-id from the window to display a helptext for
@returns    BOOL        TRUE=show the bubble, FALSE=dont display the bubble
*/


/*@ XBubbleHelp::SetText()
@group text functions
@remarks Set the text to display
@parameters char * theText
*/


/*@ XBubbleHelp::Enable()
@group misc
@remarks Enable/disable XBubbleHelp
@parameters BOOL enable    TRUE=enable, FALSE=disable (default is TRUE)
*/


/*@ 
@class XBubbleHelp
@parent XUserWindow
@type overview
@symbol _
@remarks XBubbleHelp is a window which can display short help-messages, it looks like
the bubbles on a mac.<P>
To use XBubbleHelp derive a class of it and override XBubbleHelp::SetMsgText().
See XBubbleHelp::AddWindow() and XBubbleHelp::XBubbleHelp() for details how to
select windows to show help-messages for.<P>
For applications which use XBubblehelp it is nessacary
that two bitmaps are linked to the resources of the application (in the *.RES file):
BUBBLE1.BMP which must have the resource-id 10000 and BUBBLE2.BMP with the resource-id 10001.
You can find these bitmaps in the directory ..OOL\RESOURCE<P>
The destructor is not called automaticaly when the window is hidden.<P>
XBubbleHelp does not work with menus!
*/


/*@ XBubbleHelp: : XBubbleHelp(XResource * r, XWindow * w)
@group constructors/destructors
@remarks Construct a bubblehelp-window
@parameters <t 'ø' c=2>
				øXResource *      øA resource which points to a resource-library which contains the needed bitmaps
            øXWindow *        øThe owner-window.
            øBOOL handleAll   øTRUE=all clients are handled automaticaly, you dont need to call AddWindow<BR>
                             FALSE=no clients are handled, you must add clients to handle with AddWindow()
				</t>
*/
XBubbleHelp :: XBubbleHelp(XResource * r, XWindow * w):XUserWindow(r)
{
	dev = NULL;
	map1 = map2 = map3 = NULL;
	dev = new XGraphicDevice(this, FALSE, FALSE);

	dev->SetWidth(174);
	dev->SetHeight(71);

	XPoint p;

	map3 = new XBitmap(dev);
	map3->Copy(dev, &p);

//   XPoint p(0,0);
	map1 = new XBitmap(dev, &p, ROP_SRCAND);
	XResource res(10000, r->GetResourceLibrary());

	map1->Load(&res);

	XResource res2(10001, r->GetResourceLibrary());

	map2 = new XBitmap(dev, &p, ROP_SRCINVERT);
	map2->Load(&res2);

	XRect rec(12, 3, 152, 61);
	XFont *font = new XFont(dev, "Helv", 8);

	text = new XText(dev, font, &rec, "", DT_LEFT | DT_WORDBREAK | DT_TOP);

	timer = new bubbletimer(this);
	text->Show();

	HWND hwnd;
	XWindow *win;
	HENUM henum = WinBeginEnumWindows(w->GetHandle());

	while ((hwnd = WinGetNextWindow(henum)) != 0)
	{
		win = (XWindow *) WinQueryWindowPtr(hwnd, 0);
		if (win)
			bubblehandler *h = new bubblehandler(this, win);
	}
	WinEndEnumWindows(henum);

	bhandler *b1 = new bhandler(this, w);
	bhandler *b2 = new bhandler(this, this);

	isActive = TRUE;
}


XBubbleHelp :: ~XBubbleHelp()
{
	delete dev;
}


void XBubbleHelp::Draw(void)
{
	if (IsVisible())
		dev->Draw();
}


void XBubbleHelp::Show(const BOOL show)
{
	if (!dev)
		return;
	if (show)
	{
		XPoint p;

		XWindow :: Show(TRUE);
		if (map3)
			map3->Copy(dev, &p);
	}
	else
		XWindow :: Show(FALSE);
}
