/****************************************************************************
 * These include files define many system equates, structures, and data types
 ****************************************************************************/
#include <exec/types.h>			/* Data Type like UBYTE, ULONG, ... */
#include <exec/memory.h>		/* Memory Types like MEMF_CHIP, ... */
#include <exec/libraries.h>		/* Base Amiga Library Structures    */
#include <graphics/gfxmacros.h>		/* Graphics Macros (IE. ON_DISPLAY) */
#include <graphics/sprite.h>		/* Sprite Stuctures		    */
#include <graphics/gfxbase.h>		/* Graphics Library Stuctures	    */
#include <libraries/dos.h>		/* AmigaDOS structures		    */
#include <libraries/dosextens.h>	/* more AmigaDOS structures	    */
#include <intuition/intuition.h>	/* Intuition Stuctures (Windows...) */
#include <intuition/intuitionbase.h>	/* Intuition Library Stuctures	    */
#include <workbench/startup.h>		/* WorkBench "Startup" structures   */
#include <workbench/workbench.h>
#include <workbench/icon.h>
#include <iff/readpict.h>
#include <functions.h>			/* All function return types	    */
#include <stdio.h>			/* Standard 'C' I/O data types      */
#include <ctype.h>

/****************************************************************************
 * These includes are for this program and also "packages" I have written
 ****************************************************************************/
#include "picture.h"			/* my IFF shape structures	    */
#include "rectcopy.h"			/* my Pic/Shape drawing routines    */

char *PreFix = "";			/* Pointer to path string for all
					   data files for program */

struct	IntuitionBase	*IntuitionBase = 0;	/* Pntr to Intuition Routines */
struct	GfxBase		*GfxBase = 0;		/* Pntr to Graphics Routines  */

extern	struct WBStartup	*WBenchMsg;
extern	struct Library		*IconBase;
extern	char			*index ();

/* Global graphics variables
************************************************************************
*/

struct	Window		*MainWindow = NULL;
struct	Screen		*WScreen = NULL;
struct	BitMap		*WBitMap = NULL;
struct	BitMap		MyBitMap;
struct	FileLock	*oldlock = NULL;
struct	MsgPort		*SPort = NULL;
struct	MsgPort		*SRPort = NULL;
Picture			*BackPic = NULL;
UWORD			OldColors[16];
int			FromCLI = FALSE;
int			Tile	= FALSE;
int			WorkBench = FALSE;
int			KeepColors  = FALSE;
int			TileXOff = 0;
int			TileYOff = 0;

extern struct NewWindow NewWindow;
extern int Message();

/*
** AboutToLoadBody ************************************************************
**
** Tells IFF routines where to load Picture.
*/
AboutToLoadBody (ilbmframe)
	ILBMFrame	*ilbmframe;
{
	NewImage	*ni	= ilbmframe->ni;
	int		pos;
	
	if (!Tile) {
		/*
		** Load Picture in center of screen
		*/
		ni->Left = (ni->Width >> 1) - (ilbmframe->bmHdr.w >> 1);
		if (ni->Left < 0) {
			ni->FLeft = -ni->Left;
			ni->Left  = 0;
		}
		ni->Top = (ni->Height >> 1) - (ilbmframe->bmHdr.h >> 1);
		if (ni->Top < 0) {
			ni->FTop = -ni->Top;
			ni->Top  = 0;
		}
	} else {
		/*
		** Tile Picture at users offset.
		*/
		ni->Left = TileXOff; 
		ni->Top  = TileYOff;
	}
}

/*
** ShutDownOld ******************************************************
**
** Checks for and shuts down other instances of SimGen.
*/

char portname[] = "SimGen_Close_Port";

ShutDownOld ()
{
	struct	MsgPort	*port;
	struct	Message	*msg;

	while (port = FindPort (portname)) {
		msg = GetMsg (port);
		if (msg) {
			ReplyMsg (msg);
		}
		Delay (30);
	}
}

/*
** Initialize *****************************************************************
**
** This Routine intializes most of the stuff needed for the game
*/

void Initialize (name)
	char	*name;
{
	UWORD	*wcolors;
	int	i, j;
	int	x, y, ox;

	if (!( SPort = CreatePort (portname, 0)))
		Quit ("Couldn't create message port");

	if (!( SRPort = CreatePort (NULL, 0)))
		Quit ("Couldn't create reply port");

	if (!( GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0L)))
		Quit ("Couldn't open graphics library");

	if (!( MainWindow = OpenWindow (&NewWindow)))
		Quit ("Couldn't open MainWindow");

	WScreen = MainWindow->WScreen;
	WBitMap = WScreen->ViewPort.RasInfo->BitMap;

	if (!( BackPic = CreatePic (name, WScreen->Width, WScreen->Height)))
		Quit2 ("Couldn't open ", name);

	/*
	** If tiling was requested then tile it.
	*/
	if (Tile) {
		/*
		** Set Cliping Area for Drawing Routines.
		*/
		ClipLeft   = 0;
		ClipTop	   = 0;
		ClipWidth  = WScreen->Width;
		ClipHeight = WScreen->Height;

		/* Find First "Grid" XPos before left edge */
		ox = PicHotX(BackPic);
		while (ox > 0) {
			ox -= PicWidth (BackPic);
		}

		/* Find First "Grid" YPos before right edge */
		y = PicHotY(BackPic);
		while (y > 0) {
			y -= PicHeight (BackPic);
		}

		/*
		** Now copy image in grid until entire screen is covered.
		*/
		do {
			x = ox;
			do {
				RectCopy (&BackPic->RastPort,
					PicHotX (BackPic),
					PicHotY (BackPic),
					&BackPic->RastPort,
					x, y,
					PicWidth (BackPic),
					PicHeight (BackPic));
				x += PicWidth (BackPic);
			} while (x < WScreen->Width);

			y += PicHeight (BackPic);
		} while (y < WScreen->Height);
	}

	MyBitMap = *WBitMap;
	MyBitMap.Depth = 2 + PicDepth(BackPic);
	MyBitMap.Planes[2] = BackPic->BitMap.Planes[0];
	MyBitMap.Planes[3] = BackPic->BitMap.Planes[1];
	WScreen->ViewPort.RasInfo->BitMap = &MyBitMap;

	wcolors = (UWORD *)WScreen->ViewPort.ColorMap->ColorTable;
	for (j = 0; j < 15; j++) {
		OldColors[j] = wcolors[j];
	}
	for (j = 1; j < 4; j++) {
		for (i = 1; i < 4; i++) {
			wcolors[j * 4 + i] = wcolors[i];
		}
	}
	for (j = 0; j < 4; j++) {
		wcolors[j * 4] = PicColorMap(BackPic)[j];
	}
	LoadRGB4 (&WScreen->ViewPort, wcolors, 16);

	RemakeDisplay ();

	CloseWindow (MainWindow);
	MainWindow = NULL;
}

MyClosePort (mp)
	struct	MsgPort	*mp;
{
	struct	Message	*msg;

	Forbid ();
	while (msg = GetMsg (mp));
	DeletePort (mp);
	Permit ();
}

/*
** Quit2 *********************************************************************
*/
Quit2 (mess1, mess2)
char *mess1, *mess2;
{
	char mess[250];

	strcpy (mess, mess1);
	strcat (mess, mess2);
	Quit (mess);
}

/*
** Quit *********************************************************************
**
** This routine deallocates all used resources and then exits the program
*/
Quit (message)
char	*message;
{
	int i;

	if (BackPic)	{
		WScreen->ViewPort.RasInfo->BitMap = WBitMap;
		RemakeDisplay ();
		LoadRGB4 (&WScreen->ViewPort, OldColors, 16);
		DeletePic (BackPic);
	}
	if (MainWindow)		CloseWindow (MainWindow);
        if (IntuitionBase)	CloseLibrary (IntuitionBase);
	if (GfxBase)		CloseLibrary (GfxBase);
	if (!FromCLI)		CurrentDir(oldlock);
	
	Forbid ();
	if (SRPort)		MyClosePort (SRPort);
	if (SPort)		MyClosePort (SPort);
	Permit ();

	if (message) {
		ReportError (message);
	}

	exit (0);
}

/*
** GetOffset ***************************************************************
**
** Sets Tile offsets from string of format xxx,yyy
**
**/

char *GetOffset (s)
	char	*s;
{
	if (isdigit(*s)) {
		TileXOff = atoi (s);
		s = index (s, ',');
		if (s == NULL || !isdigit(s[1])) {
			Quit ("Bad Tile Offset specification");
		}
		s++;
		TileYOff = atoi (s);
		while (isdigit (*s)) {
			s++;
		}
		--s;
	} else {
		--s;
	}
	return (s);
}

/*
** UsePickFile ************************************************************
**
** Picks one of X Pictures from file.
*/
char	fname[257];
char	perr[] = "I/O Error Reading PickFile.";

char *UsePickFile (filename)
	char	*filename;
{
	FILE	*fp;
	char	line[257];
	int	c;
	int 	i;
	char	*s;

	if (!(fp = fopen (filename, "r")))
		Quit2 ("Could open pickfile ", filename);

	if (!fgets(line, 256, fp))
		Quit (perr);

	c = atoi (line);
	c = Random (c);
	for (i = 0; i <= c; i++) {
		fgets(line, 256, fp);
	}
	fclose (fp);
	s = index (line + 1, '"');
	if (!s)
		Quit ("Syntax Error in PickFile");
	*s = '\0';
	strcpy (fname, line + 1);

	if (tolower(s[1]) == 't') {
		Tile = TRUE;
		GetOffset (s + 2);
	}

	return (fname);
}

/**************************************************************************/


char wbhelp[] = "\
From the Workbench you may use extened-selection to choose \
a picture to use with SimGen.  Select a Picture, Hold Shift, \
and double-click on SimGen.\n\nYou may also set the default \
tool of a picture to SimGen.\
";

char wbhelp1[] = "\
Valid ToolTypes for SimGen are \n\
KEEPCOLORS\n\
\n\
Keeps correct colors even when changed by other \
programs.\n\
\n\
WORKBENCH\n\
\n\
Restores SimGen after WorkBench has been closed.\n\
\n\
";

char wbhelp2[] = "\
TILE\n\
\n\
'Tiles' Picture. By default the picture is centered. \
This option 'tiles' the picture.  An optional offset may be \
specified as in 'TILE=10,20'.\
";

char help[] = "\
Usage: %s [-option ...] picture [picture]...\n\
\tt = Tile Picture. Normally the Picture is centered but\n\
\t    with this option the picture will be used as a pattern.\n\
\t    Use with brushes. An offset may also be specified.\n\
\t    Example: -t10,20\n\
\tw = WorkBench Restore. Restores SimGen after WorkBench\n\
\t    is closed and re-opened.\n\
\tk = Keep Colors. Keeps the colors correct even when they\n\
\t    are changed by other programs like preferneces.\n\
\tp = PickFile.  This option must be followed by a filename\n\
\t    as in '-pPicList' where PicList is a text file which\n\
\t    on the first line contains the number of choices and\n\
\t    the following lines contain Path/filename (surrounded\n\
\t    by quotes) to valid IFF pictures to randomly choose from.\n\
\tr = Remove. Removes any previous SimGen\n\
\n\
\t\Type CTRL-C to Exit, use the 'Break' command or\n\
\t\Type 'SimGen -r' to remove SimGen.\n\
";

main (argc, argv)
	int	argc;
	char	**argv;
{
	char	**line;
	char 	*name = NULL;
	char	*s;
	int	firstname = 1;
	int	c;
	struct	WBArg		*wbarg;
	struct	FileLock	*newlock;
	struct	DiskObject	*dobj;
	struct	Message		msg;

	/*
	** Open Intuition Library (needed here it seed random number).
	*/
	if (!( IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library", 0L)))
		Quit ("Couldn't open intuition library");

	/*
	** Seed Random Number Generator.
	*/
	SeedRandom ();

	/*
	** Startup for CLI or WorkBench.
	*/
	if (argc) {
		/*
		** Set FromCLI Flag
		*/
		FromCLI = TRUE;

		/*
		** Did we get enough arguments?
		*/
		if (argc < 2 || argv[1][0] == '?') {
			printf (help, argv[0]);
			Quit (NULL);
		}

		/*
		** Parse Options.
		*/
		while (argv[firstname][0] == '-') {
			s = argv[firstname] + 1;
			firstname++;
			while (*s) {
				switch (tolower(*s)) {
					case 'r' :
						ShutDownOld ();
						Quit (NULL);
						break;
					case 'k' :
						KeepColors = TRUE;
						break;
					case 'w' :
						WorkBench = TRUE;
						break;
					case 't' :
						Tile = TRUE;
						s = GetOffset (s+1);
						break;
					case 'p' :
						name = UsePickFile (s+1);
						s[1] = '\0';
						break;
					default :
						printf ("Unknown option '%c'\n",
							*s);
						break;
				}
				s++;
			}
		}

		/*
		** Pick Name at Random.
		*/
		if (!name) {
			name = argv[firstname + Random (argc - firstname)];
		}
		printf ("loading '%s'\n", name);
	} else {
		if (WBenchMsg->sm_NumArgs < 2) {
			c = Message (NULL, "SimGen Help", wbhelp,
				" Exit | Remove | More Info ");
			if (c == 2) {
				ShutDownOld ();
				Quit (NULL);
			} else if (c == 3) {
				Message (NULL, "SimGen Help",wbhelp1, " More ");
				Message (NULL, "SimGen Help",wbhelp2, " Exit ");
			}
			Quit (NULL);
		}
		wbarg   = WBenchMsg->sm_ArgList;
		wbarg++;
		name    = wbarg->wa_Name;
		newlock = (struct FileLock *)wbarg->wa_Lock;
		oldlock = CurrentDir(newlock);
		if (!(IconBase = OpenLibrary (ICONNAME, LIBRARY_VERSION)))
			Quit ("Couldn't open Icon.Library");
		if ((dobj = GetDiskObject (name))) {
			if (FindToolType (dobj->do_ToolTypes, "KEEPCOLORS")) {
				KeepColors = TRUE;
			}
			if (FindToolType (dobj->do_ToolTypes, "WORKBENCH")) {
				WorkBench = TRUE;
			}
			if (s = FindToolType (dobj->do_ToolTypes, "TILE")) {
				Tile = TRUE;
				GetOffset (s);
			}
		}
		CloseLibrary (IconBase);
	}

	ShutDownOld ();

	Initialize(name);

	msg.mn_Node.ln_Type = NT_MESSAGE;
	msg.mn_ReplyPort    = SRPort;
	msg.mn_Length       = sizeof (msg);
	PutMsg (SPort, &msg);

	Wait (SIGBREAKF_CTRL_C | (1L << SRPort->mp_SigBit));

        Quit (NULL);
}


SYSMESS (mess)
	char *mess;
{
	if (FromCLI) {
		puts (mess);
	} else {
		Message (NULL, "SimGen", mess, " OK ");
	}
}

ReportError (mess)
	char *mess;
{
	if (FromCLI) {
		puts (mess);
	} else {
		Message (NULL, "SimGen Error", mess, " Exit ");
	}
}

SetColors () { }
RestoreColors () { }
RemovePointer () { }
RestorePointer () { }

/*
** SeedRandom **********************************************************
**
** Seeds random number generator with current time in MicroSeconds.
*/
SeedRandom ()
{
	srand (IntuitionBase->Micros);
}

/*
** Random
**
** returns a random number from 0 to range - 1.
** range must be less than 32767.
*/
int Random (range)
	int range;
{
	return (((rand() & 0x7FFF) * range) >> 15);
}
