/*****************************************************************************\
 * $VER: TetrisQ_main.c 1.4                                                  *
 *                               DICE/LATTICE C/SAS C/AZTEC C + AmigaOS 2.04 *
 *                 _                                                         *
 * 6.10.92    _   // (c)1992 by "Quarky" Dieter Temme                        *
 *            \\ //                                                          *
 * :ts=4       \X/ --- Freeware --- ONLY AMIGA MAKES IT POSSIBLE             *
 *                                                                           *
 * NOTICE: 2.1-Includes needed!                                              *
\*****************************************************************************/

#define PRGDATE "6.10.92"

#include "amigacompq.h"
#include "definitions.h"

#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <clib/alib_protos.h>
#include <clib/commodities_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <devices/inputevent.h>
#include <dos/dos.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/commodities.h>
#include <workbench/startup.h>

#ifdef PRAGMAS_
 #include <pragmas/commodities_lib.h>
 #include <pragmas/dos_lib.h>
 #include <pragmas/exec_lib.h>
 #include <pragmas/intuition_lib.h>
#endif

/* compiler-specific stuff */
#ifdef AZTEC_C
 void _wb_parse(void) {	extern long Enable_Abort; Enable_Abort= FALSE; }
 void _cli_parse(void) { extern long _argc; _argc= 1; }
 void _abort(void) {}
#endif

TEXT VersionString[]= "\0$VER: " PRGNAME " " VERSION " (" PRGDATE ")";


/*>> local variables <<*/
struct Library *AslBase, *CxBase, *GadToolsBase, *GfxBase, *IconBase,
				*IntuitionBase, *KeymapBase, *UtilityBase, *WorkbenchBase;
struct NewBroker newbroker=		/* newbroker structure */
{	5, PRGNAME, "V" VERSION " (c)1992 by \"Quarky\" Dieter Temme", NULL,
	NBU_UNIQUE|NBU_NOTIFY, COF_SHOW_HIDE
};
CxObj *broker;					/* Commodities' broker structure */
TEXT *hotkey;					/* hotkey description */
struct MsgPort *brokport;		/* port for Commodities' messages */
ULONG cxsig;					/* signal flag of Commodities' message port */
TEXT **aargv;					/* ArgArrayInit()/ArgArrayDone() structure */
BPTR cdlock;					/* lock to program's directory */
BPTR syslock;					/* lock to system's directory */

/*==== bring error text to the user ====*/
void PrintNoMem_(void)
{	extern struct Window *win; /* from "playerctrl.c" */

	static struct EasyStruct easystruct=
	{	sizeof(struct EasyStruct), 0, NULL,
			"not enough memory", "Retry|Abort Program"
	};

	if (win)
	{	BOOL result;

		PC_CtrlWindow_(CW_SLEEP_|CW_SYSTEM_);
		DisplayBeep(NULL);
		result= (BOOL)EasyRequest(win, &easystruct, NULL, NULL);
		PC_CtrlWindow_(CW_ACTIV_|CW_SYSTEM_);
		if (result) return;
	}

	exit(RETURN_FAIL);
}

/*==== allocate memory ====*/
void *MAllocQ_(const ULONG size)
{	void *ptr;

	while (!(ptr= malloc(size))) PrintNoMem_();
	return ptr;
}

void *AllocMemQ_(const ULONG size, const ULONG flags)
{	void *ptr;

	while (!(ptr= AllocMem(size, flags))) PrintNoMem_();
	return ptr;
}

/*==== open library ====*/
struct Library *OpenLibraryQ_(TEXT *str)
{	static struct EasyStruct easystruct=
	{	sizeof(struct EasyStruct), 0, NULL,
		"%s\n not found", "Retry|Cancel"
	};
	struct Library *base;

	while (!(base= OpenLibrary(str, 0)))
	{	if (IntuitionBase)
		{	if (!EasyRequest(win, &easystruct, NULL, str))
				exit(RETURN_FAIL);
		} else
		{	Printf(PRGNAME ": %s not found\n", (ULONG)str, (ULONG)NULL);
			exit(RETURN_FAIL);
		}
	}

	return base;
}

/*==== set or clear busy pointer ====*/
void CtrlPointer_(const UBYTE action)
{	extern struct Window *win;		/* from "playerctrl.c" */

	static ULONG idcmpflags;

	/*>> busy mouse pointer image <<*/
	static UWORD *pimage;			/* mouse imagedata in chip mem */
	static UWORD mouseimage[]=		/* a 'simple sprite' */
	{	0, 0,
		0x0400, 0x07c0, 0x0000, 0x07c0, 0x0100, 0x0380, 0x0000, 0x07e0,
		0x07c0, 0x1ff8, 0x1ff0, 0x3fec, 0x3ff8, 0x7fde, 0x3ff8, 0x7fbe,
		0x7ffc, 0xff7f, 0x7efc, 0xffff, 0x7ffc, 0xffff, 0x3ff8, 0x7ffe,
		0x3ff8, 0x7ffe, 0x1ff0, 0x3ffc, 0x07c0, 0x1ff8, 0x0000, 0x07e0,
		0, 0
	};

	switch (action)
	{	case MOUSE_INIT_:
			if (pimage= AllocMem(sizeof(mouseimage), MEMF_CHIP))
				CopyMem(mouseimage, pimage, sizeof(mouseimage));
			break;
		case MOUSE_SET_:
			if (pimage && win && (win->IDCMPFlags
				!= (IDCMP_CHANGEWINDOW|IDCMP_ACTIVEWINDOW)))
			{	idcmpflags= win->IDCMPFlags;
				ModifyIDCMP(win, IDCMP_CHANGEWINDOW|IDCMP_ACTIVEWINDOW);
				SetPointer(win, pimage, 16, 16, -6, 0);
			}
			break;
		case MOUSE_CLR_:
			if (pimage && win)
			{	ClearPointer(win);
				if (idcmpflags) ModifyIDCMP(win, idcmpflags);
				idcmpflags= 0;
			}
			break;
		case MOUSE_REMOVE_:
			if (pimage) FreeMem(pimage, sizeof(mouseimage));
			break;
	}
}

/*==== clean up all ====*/
void CleanUp_(void)
{	/*- perform clean up routines of modules -*/
	LS_CloseTable_();				/* free file requester structure */
	LS_CloseNewLevel_();			/* close startlevel window */
	LS_CloseInputEntry_();			/* close input window */
	FC_CloseFigure_();				/* free memory for figures */
	TC_CloseTimer_();				/* close timer.device */
	PC_CloseWindow_();				/* close window */

	/*- perform clean up of main module -*/
	CtrlPointer_(MOUSE_REMOVE_);	/* free busy mouse pointer image memory */
	CurrentDir(syslock);			/* reset current directory */
	if (broker) DeleteCxObjAll(broker);
	if (brokport)
	{	struct Message *msg;
		while (msg= GetMsg(brokport)) ReplyMsg(msg);
		DeleteMsgPort(brokport);
	}
	if (aargv) ArgArrayDone();

	/*- close libraries -*/
	if (AslBase) CloseLibrary(AslBase);
	if (CxBase) CloseLibrary(CxBase);
	if (GadToolsBase) CloseLibrary(GadToolsBase);
	if (GfxBase) CloseLibrary(GfxBase);
	if (IconBase) CloseLibrary(IconBase);
	if (KeymapBase) CloseLibrary(KeymapBase);
	if (UtilityBase) CloseLibrary(UtilityBase);
	if (WorkbenchBase) CloseLibrary(WorkbenchBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
}

/*==== main program ====*/
int main(int argc, struct WBStartup *argv)
{	extern TEXT *hsdir, *hsname;				/* from "levelscore.c" */

	struct WBArg wbarg;
	TEXT commandname[30+1];
	BOOL popup;

	/*- do not allow OS to be less than 2.04 -*/
	{	extern struct Library *SysBase;
		if (SysBase->lib_Version < 37)
		{	BPTR file= argc? Output()
				: Open("CON:0/0/350/30/" PRGNAME, MODE_NEWFILE);
			Write(file, "Sorry, you'll need at least AmigaOS 2.04!\n", 42);
			if (!argc) Delay(100);
			Close(file);
			return RETURN_FAIL;
		}
	}

	atexit(CleanUp_);

	/*- open libraries -*/
	IntuitionBase= OpenLibraryQ_("intuition.library");
	AslBase= OpenLibraryQ_("asl.library");
	CxBase= OpenLibraryQ_("commodities.library");
	GadToolsBase= OpenLibraryQ_("gadtools.library");
	GfxBase= OpenLibraryQ_("graphics.library");
	IconBase= OpenLibraryQ_("icon.library");
	KeymapBase= OpenLibraryQ_("keymap.library");
	UtilityBase= OpenLibraryQ_("utility.library");
	WorkbenchBase= OpenLibraryQ_("workbench.library");

	/*- process arguments or tool types -*/
	aargv= ArgArrayInit(argc, (TEXT **)argv);
	newbroker.nb_Pri= (BYTE)ArgInt(aargv, "CX_PRIORITY", 0);
	popup= !Stricmp(ArgString(aargv, "CX_POPUP", "TRUE"), "TRUE");
	hotkey= ArgString(aargv, "CX_POPKEY", "ctrl alt t");

	/*- simulate call from Workbench if called from Shell -*/
	if (argc)
	{	argv= (struct WBStartup *)MAllocQ_(sizeof(struct WBStartup));
		argv->sm_NumArgs= 1;
		argv->sm_ArgList= &wbarg;
		wbarg.wa_Lock= GetProgramDir();
		if (!wbarg.wa_Lock) CurrentDir(wbarg.wa_Lock= CurrentDir(NULL));
		GetProgramName(wbarg.wa_Name= commandname, 30+1);
	}

	/*- initialize as commodity with hotkey -*/
	newbroker.nb_Descr= "The famous game Tetris (TM)";
	while (!(brokport= newbroker.nb_Port= CreateMsgPort()))
		PrintNoMem_();
	cxsig= 1<<brokport->mp_SigBit;
	{	CxObj *filter;
		LONG error;

		while (!(broker= CxBroker(&newbroker, &error)) || error
			|| !(filter= HotKey(hotkey, brokport, 0))
			|| (AttachCxObj(broker, filter), CxObjError(filter)))
			if (error == CBERR_DUP)			return RETURN_OK;
			else 							PrintNoMem_();
	}
	ActivateCxObj(broker, TRUE);

	/*- preserve lock from system -*/
#ifdef DEBUG
	/* otherwise Manx' sdb cannot find the source code! */
	syslock= cdlock= CurrentDir(0); CurrentDir(syslock);
#else
	syslock= CurrentDir(cdlock= argv->sm_ArgList[0].wa_Lock);
#endif

	/*- main loop -*/
	{	UWORD evclass;
		UBYTE evnum;
		BOOL end= FALSE;

		TC_InitTimer_();				/* open timer.device */
		CtrlPointer_(MOUSE_INIT_);		/* initialize busy mouse pointer */
		LS_InitTable_();				/* get date, build file req struct */

		/*- get highscores path and filename -*/
		{	BOOL ext;
			TEXT *dir;
			UWORD l= 0;

			/* set highscores file */
			ext= argv->sm_NumArgs != 1;
			if (ext && (SameLock(argv->sm_ArgList[0].wa_Lock,
				argv->sm_ArgList[1].wa_Lock) != LOCK_SAME))
			{	do
				{	if (l) free(hsdir);
					l+= 256;
					dir= MAllocQ_(l);
				} while (!NameFromLock(argv->sm_ArgList[0].wa_Lock, dir, l));
			} else
				dir= "";
			LS_SetTable_(dir,
				ext? (TEXT *)argv->sm_ArgList[1].wa_Name : "TQ_Results");
			if (*dir) free(dir);
		}

		LS_LoadTable_(LT_LOAD_);		/* read in highscores */
		LS_LoadSettings_();				/* read in settings */
		if (popup)
		{	PC_InitWindow_();			/* open window, set menu */
			FC_OpenFigure_();			/* open figure memory */
			FC_ShowTitle_(ST_ABOUT_);	/* show title and copyright */
		}

		/* process messages */
		while (!end)
		{	evclass= PC_WaitForEvents_();
			evnum= (UBYTE)evclass;

			switch (evclass&0xff00)
			{	case EV_EXIT_:
					end= TRUE;
					break;
				case EV_OPEN_:
					PC_InitWindow_();
					FC_OpenFigure_();
					FC_ShowTitle_(ST_ABOUT_);
					break;
				case EV_CLOSE_:
					PC_CloseWindow_();
					PC_ProcessGadget_(GID_ABORT_);
					{ 	extern BYTE players, pl; /* from "playerctrl.c" */
						if (players)
							PC_ProcessGadget_(GID_PLAYER2_|GID_ABORT_);
					}
					FC_CloseFigure_();
					break;
				case EV_MENU_:
					end= PC_ProcessMenu_(evnum);
					break;
				case EV_GADGET_:
					PC_ProcessGadget_(evnum);
					break;
				case EV_RAWKEY_:
					if (evnum&IECODE_UP_PREFIX) break;
					FC_ProcessKey_(evnum);
					if (evnum == 0x5F) FC_ShowTitle_(ST_HELP_);
					else if (evnum == 0x45) PC_CloseWindow_();
					break;
				case EV_TIMER_:
					FC_ProcessTimer_(evnum);
			}
		}
	}

	return RETURN_OK;
}

#ifdef _DCC
int wbmain(struct WBStartup *wbstartup)
{	return main(0, wbstartup);
}
#endif
