/*
** This is a simple example about how to write applications using
** ReAction and GUIs build with ReActor.
*/

#define NO_INLINE_STDARG
#include "example_gui.h"
#include <dos/dos.h>
#include <classes/window.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/locale.h>
#include <proto/resource.h>
#include <clib/alib_protos.h>
#include <stdio.h>


struct Screen  *glbScreen;
struct MsgPort *glbAppPort;
struct Catalog *glbCatalog;
RESOURCEFILE   *glbResource;
struct Window  *glbWindow;
struct Gadget **glbGadgets;
Object *glbWinobj;


int openGUI(void)
{
	/* Get a pointer to the default public screen. */
	glbScreen = LockPubScreen(NULL);
	if(!glbScreen)
	{
		fputs("Failed to lock default public screen.\n", stderr);
		return FALSE;
	}

	/* We need an application message port for iconification. */
	glbAppPort = CreateMsgPort();
	if(!glbAppPort)
	{
		fputs("Failed to create message port.\n", stderr);
		return FALSE;
	}

	/* Open the catalog if existing. */
	glbCatalog = OpenCatalogA(NULL, "example.catalog", NULL);
	/* Open the RCTResource which is linked to our executable. */
	glbResource = RL_OpenResource(RCTResource, glbScreen, glbCatalog);
	if(!glbResource)
	{
		fputs("Failed to create GUI resource.\n", stderr);
		return FALSE;
	}

	/* Create the window. */
	glbWinobj = RL_NewObject(glbResource, WIN_MAIN_ID,
		WINDOW_AppPort, glbAppPort,
		WA_PubScreen, glbScreen,
		WA_RMBTrap, TRUE,
		TAG_DONE);
	if(!glbWinobj)
	{
		fputs("Failed to create window object.\n", stderr);
		return FALSE;
	}

	/* Obtain the array of gadgets of our window. From now on you can
	** access the gadgets through glbGadgets[GAD_ID]. */
	glbGadgets = (struct Gadget**) RL_GetObjectArray(glbResource, glbWinobj, GROUP_MAIN_ID);
	if(!glbGadgets)
	{
		fputs("Could not obtain gadget array.\n", stderr);
		return FALSE;
	}

	/* Open the window (make it visible). */
	glbWindow = (struct Window*) DoMethod(glbWinobj, WM_OPEN);
	if(!glbWindow)
	{
		fputs("Failed to open window.\n", stderr);
		return FALSE;
	}

	/* Now everything is setup correctly. */
	return TRUE;
}


void closeGUI(void)
{
	/* Close the window if open. */
	if(glbWindow)
	{
		DoMethod(glbWinobj, WM_CLOSE);
		glbWindow = NULL;
	}
	/* Free all created objects. */
	RL_CloseResource(glbResource);
	glbGadgets = NULL;
	glbWinobj = NULL;
	glbResource = NULL;
	/* Close the catalog. */
	CloseCatalog(glbCatalog);
	glbCatalog = NULL;
	/* Destroy the application message port. */
	DeleteMsgPort(glbAppPort);
	glbAppPort = NULL;
	/* Unlock the default public screen. */
	UnlockPubScreen(NULL, glbScreen);
	glbScreen = NULL;
}


void loopGUI(void)
{
	BOOL running = TRUE;
	ULONG winsig = 1 << glbWindow->UserPort->mp_SigBit;
	ULONG appsig = 1 << glbAppPort->mp_SigBit;
	ULONG sigs, result;
	UWORD code;

	while(running)
	{
		sigs = Wait(SIGBREAKF_CTRL_C | winsig | appsig);
		/* Handle CTRL-C. */
		if(sigs & SIGBREAKF_CTRL_C)
		{
			running = FALSE;
		}
		/* Handle messages for our window and the application port. */
		if((sigs & winsig) || (sigs & appsig))
		{
			/* Process all pending messages.
			** Both ports are handled by this method WM_HANDLEINPUT.
			** The winobj knows of our app-Port, because we provided it in RL_NewObject(). */
			while((result = DoMethod(glbWinobj, WM_HANDLEINPUT, &code)) != WMHI_LASTMSG)
			{
				switch(result & WMHI_CLASSMASK)
				{
					case WMHI_CLOSEWINDOW:
						running = FALSE;
						break;

					case WMHI_GADGETUP:
						switch(result & RL_GADGETMASK)
						{
							case GAD_CANCEL_ID:
								running = FALSE;
								break;
							/* ... other gadgets can be handled here ... */
						}
						break;

					case WMHI_ICONIFY:
						DoMethod(glbWinobj, WM_ICONIFY);
						glbWindow = NULL;
						winsig = 0;
						break;

					case WMHI_UNICONIFY:
						glbWindow = (struct Window*) DoMethod(glbWinobj, WM_OPEN);
						if(!glbWindow)
						{
							fputs("Failed to reopen window.\n", stderr);
							running = FALSE;
						}
						else
						{
							winsig = 1 << glbWindow->UserPort->mp_SigBit;
						}
						break;
				}
			}
		}
	}
}


int main(void)
{
	if(openGUI())
		loopGUI();
	closeGUI();
	return 0;
}

