/*	Declarations for CBACK	*/
extern BPTR _Backstdout;		/*	std output when run in background	*/
long _BackGroundIO = 1;			/*	Flag to tell it we want to do I/O	*/
long _stack = 4000;				/*	Amount of stack space task needs	*/
char *_procname = "PUZZ";		/*	The name of the task to create		*/
long _priority = 1;				/*	The priority to run us at			*/

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

int sqrsacross,sqrsdown;
unsigned char start [MAXACROSS] [MAXDOWN];
unsigned char goal  [MAXACROSS] [MAXDOWN];
unsigned char grid	[MAXACROSS] [MAXDOWN];
unsigned char movelist [MAXPIECES] [4];

int topleftx,toplefty;
int sqrwidth,sqrheight;
int slide;

int moves;
int dmapwidth,dmapheight;
int audio;

BitMapHeader bmhd;

struct RastPort *dbuff;

struct TextAttr MyFont =
	{
	(STRPTR)"topaz.font",
	TOPAZ_EIGHTY, 0, 0
	};

extern struct Screen *loadpuzzle(int, char **);
extern struct RastPort *getbuffs(int,int);
extern int get_audio(void);
extern void StopVoices(void);
extern void freebuffs(int,int);
extern void Expand(struct Screen *, BitMapHeader *);
extern void saveundermenu(struct RastPort *);
extern void drawovermenu(struct RastPort *);
extern void print(char *s);
extern struct Menu MyMenu;

void cleanup(int,struct Screen *, struct Window *);
void startpuzzle(struct Screen *,struct Window *);
extern void clicked(struct RastPort *,int,int);

/*	following stuff so we can work from CLI or WorkBench	*/

int runningfromcli;

#define MAXARGS 32

/*	Using _main() and cback.o avoids the stupid console
	window opening when we are run from the Workbench
*/

void _main(char *cmd)
	{
	int argc = 0;
	char *argv[MAXARGS];
	
	struct Screen *screen;
	struct Window *window;
	struct NewWindow nw;
	struct IntuiMessage *msg;

	/*	This code fragment gets argc and argv as if from main()		*/
	if (cmd && *cmd)
		{
		argv[argc] = strtok(cmd,", \n");
		while(argv[argc])
			argv[++argc] = strtok(NULL,", \n");
		}

	runningfromcli = (argc == 0 ? 0 : 1);

	if (runningfromcli)		/*	Output my banner.	*/
		{
		print("\n\2330;33mPUZZ  V1.0\2330m  by\t\2331mMartin Round.\2330m\n");
		print("\t\t17, Naseby Drive, Halesowen, West Mids.\n");
		print("\t\tB63 1HJ  England.  Contact me through\n");
		print("\t\tthe Plug 'Ole B.B.  (021-472-0256) or\n");
		print("\t\tAMLINK B.B.  (021-778-5868).\n\n");
		}
	
	IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L);
	GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);

	screen=loadpuzzle(argc,argv);	/*	loads puzzle data and then		*/
									/*	reads pic into compr. buffer	*/
  									/*	returns pointer to opened		*/
									/*	screen, or NULL for failure		*/

	SetTaskPri(FindTask(NULL),0);	/*	now run at standard priority	*/
	
	dmapwidth = sqrsacross * sqrwidth;
	dmapheight = sqrsdown * sqrheight;

	if (screen == NULL)
		{
		cleanup(0,screen,(window = NULL));
		exit(0L);
		}

	/*	get buffers for saving 'menu' part of pic and double-buffering	*/

	if ((dbuff = getbuffs(dmapwidth,dmapheight)) == NULL)
		{
		cleanup(0,screen,(window = NULL));
		exit(0L);
		}

	/*	attempt to get 4 audio channels - if we can't then we will
		still run, but without sounds.
	*/
	audio = get_audio();
	
	setmem(&nw,sizeof(nw),0);
	nw.IDCMPFlags=MOUSEBUTTONS|MENUPICK;
	nw.Flags=NOCAREREFRESH|BORDERLESS|ACTIVATE;
	nw.Screen=screen;
	nw.Type=CUSTOMSCREEN;
	nw.Height=bmhd.h; nw.Width=bmhd.w;
	nw.DetailPen = 1;
	nw.BlockPen = 0;

	if (!(window=OpenWindow(&nw)))
		{ 
		cleanup (1,screen,window);
		exit(0L);
		}
  
	startpuzzle(screen,window);

	SetMenuStrip(window, &MyMenu);

	for (;;)	/*	FOREVER	*/
		{
		Wait(1 << window->UserPort->mp_SigBit);		/*	sleep	*/

		while ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)) != NULL)
			{
			switch (msg->Class)
				{
				case MENUPICK:
					if (MENUNUM(msg->Code) == 0)		/*	Start	*/
						{
						startpuzzle(screen,window);
						ReplyMsg((struct Message *)msg);
						}
					else if (MENUNUM(msg->Code) == 1)	/*	Quit	*/
						{
						ReplyMsg((struct Message *)msg);
						cleanup (3,screen,window);
						exit (0L);
						}
					else
						{
						drawovermenu(window->RPort);
						ReplyMsg((struct Message *)msg);
						}
					break;

				case MOUSEBUTTONS:
					if (msg->Code == SELECTDOWN)
						{
						drawovermenu(window->RPort);
						clicked(window->RPort,msg->MouseX,msg->MouseY);
						saveundermenu(window->RPort);
						}
					ReplyMsg((struct Message *)msg);
					break;
					
				default:
					ReplyMsg((struct Message *)msg);
					break;
				}
			}
		}

	}	/*	end of main	*/

void cleanup(int level,struct Screen *screen,struct Window *window)
	{
	switch (level)
		{
		case 3:
			if (audio)
				{
				StopVoices();
				clear_audio(0);
				}
		case 2:
			ClearMenuStrip(window);
			freebuffs(dmapwidth,dmapheight);
			CloseWindow(window);
		case 1:
			CloseScreen(screen);
		case 0:
			CloseLibrary((struct Library *) IntuitionBase);
			CloseLibrary((struct Library *) GfxBase);
			if (_Backstdout)  Close(_Backstdout);
			break;
		}
	}

void startpuzzle(struct Screen *screen,struct Window *window)
	{
	int i,j;
	
	Expand(screen,&bmhd);		/*	actually draw the piccy	*/
	saveundermenu(window->RPort);
	
	for (j=0; j<sqrsdown; j++)
		for (i=0; i<sqrsacross; i++)
			grid [i] [j] = start [i] [j];

	moves = 0;
	
	for (i=0; i<MAXPIECES; i++)
		for (j=0; j<4; j++)
			movelist [i] [j] = j+1;
	}
