/*
 *--- Put up a requester with a message and get a reply ---*
 */

#include "exec/types.h"
#include "intuition/intuition.h"
#include "intuition/intuitionbase.h"
#include "functions.h"

extern	struct	IntuitionBase	*IntuitionBase;
extern	struct	GfxBase		*GfxBase;

#ifdef TEST
#define LOCAL
#else
#define LOCAL static
#endif

LOCAL	struct	IntuitionBase	*itemp;
LOCAL	struct	GfxBase		*gtemp;

#define LEFT	1
#define CENTER	2

#define MESSLEFT  32
#define MESSTOP   20
#define MESSWIDTH 260

LOCAL struct NewWindow	NewMessWindow = {
	MESSLEFT, MESSTOP,	/* Left, Top Edge		*/
	MESSWIDTH, 0,		/* Width, Height		*/
	0, 0,			/* DetailPen, BlockPen		*/
	GADGETUP,		/* IDCMP Flags			*/
	BORDERLESS | ACTIVATE,	/* WINDOWFLAGS			*/
	NULL,			/* User Gadgets			*/
	NULL,			/* Check Mark			*/
	NULL,			/* Title			*/
	NULL,			/* Screen			*/
	NULL,			/* SuperBitMap			*/
	0,0,0,0,		/* Min, Max Size		*/
	WBENCHSCREEN		/* Screen Type			*/
};

LOCAL SHORT MessLines[] = {
	          0,  0,
	MESSWIDTH-3,  0,
	MESSWIDTH-3, 11,
	          0, 11,
		  0,  0,
		  0,  0, /* Set to HEIGHT-2 */
	MESSWIDTH-3,  0, /* Set to HEIGHT-2 */
	MESSWIDTH-3,  0,
	MESSWIDTH-3,  2, 
	MESSWIDTH-2,  2,
	MESSWIDTH-2,  0, /* Set to HEIGHT-1 */
		  2,  0, /* Set to HEIGHT-1 */
		  2,  0, /* Set to HEIGHT-1 */
	MESSWIDTH-1,  0, /* Set to HEIGHT-1 */
	MESSWIDTH-1,  2 };

LOCAL SHORT MessHeadingLines[] = {
		  1,  1,
	MESSWIDTH-4,  1,
	MESSWIDTH-4, 10,
		  1, 10 };

LOCAL SHORT MessCorner1Lines[] = {
		  0,  0,	/* Set to Height -1 */
		  1,  0 };	/* Set to Height -1 */

LOCAL SHORT MessCorner2Lines[] = {
	MESSWIDTH-2,  0,
	MESSWIDTH-1,  0,
	MESSWIDTH-1,  1,
	MESSWIDTH-2,  1 };

LOCAL struct Border MessBorder[] = {
     0,  0, 0,NULL, JAM1,15,MessLines,		&MessBorder[1],
     0,  0, 0,NULL, JAM1, 4,MessHeadingLines,	&MessBorder[2],
     0,  0, 0,NULL, JAM1, 2,MessCorner1Lines,	&MessBorder[3],
     0,  0, 0,NULL, JAM1, 4,MessCorner2Lines,	NULL };

#define GHEIGHT 13

LOCAL SHORT OrigGLines[20] = {
/* Width - 3 */	  -3,  0,		/*  0,  1 */
		   0,  0,		/*  2,  3 */
		   0,  GHEIGHT - 2,	/*  4,  5 */
/* Width - 3 */	  -3,  GHEIGHT - 2,	/*  6,  7 */
/* Width - 3 */   -3,  1,		/*  8,  9 */
/* Width - 1 */   -1,  1,		/* 10, 11 */
/* Width - 1 */   -1,  GHEIGHT - 1,	/* 12, 13 */
		   2,  GHEIGHT - 1,	/* 14, 15 */
/* Width - 2 */   -2,  GHEIGHT - 1,	/* 16, 17 */
/* Width - 2 */	  -2,  1,		/* 18, 19 */
};

LOCAL struct TextAttr MessageFont = {
	(UBYTE *)"topaz.font",/* Font Name	*/
	TOPAZ_EIGHTY,	/* Font Height		*/
	FS_NORMAL,	/* Style		*/
	FPF_ROMFONT };	/* Preferences		*/

LOCAL struct IntuiText OrigGIText = {
  30,31,JAM2,2,2,&MessageFont, NULL, NULL,
};

LOCAL struct Border OrigGBord = {
  0, 0, 30, 0, JAM1, 10, NULL, NULL,
};

#define GFLAGS	GADGHCOMP
#define GAFLAGS	RELVERIFY | ENDGADGET
#define BGFLAGS REQGADGET | BOOLGADGET

LOCAL struct Gadget OrigMessageGadget = {
 0L,0,0,0,13,GFLAGS,GAFLAGS,BGFLAGS,0L,0L,0L,0L,0L,1,0L,
};

LOCAL struct IntuiText MessageText[16];
LOCAL char TextLines[16][33];

LOCAL struct Requester MessageRequester = {
	NULL,			/* Old Requester	*/
	MESSLEFT,		/* Left Edge		*/
	MESSTOP,		/* Top Edge		*/
	MESSWIDTH,		/* Width		*/
	0,			/* Height		*/
	0,0,			/* Mouse Relative POS.	*/
	0L,			/* First Gadget		*/
	&MessBorder[0],		/* First Border		*/
	&MessageText[0],	/* First IntuiText	*/
	NULL,			/* Flags		*/
	29,			/* Back Fill		*/
	NULL,			/* Layer for Requester  */
};

LOCAL struct Gadget     *MGadget;
LOCAL struct Gadget	*LeftGad;
LOCAL struct Gadget	*RightGad;
LOCAL char		*GOptions;
LOCAL int 		TotalLines,
			TotalChoices,
			HeadingColor = 31,
			MessageColor = 29,
			TextColor    = 30,
			BorderColor =  30;

struct Gadget *
FreeChoice (Gad)
struct Gadget *Gad;
{
	struct Gadget *next;

/*** If this Gadget has a Border ***/
	if (Gad->GadgetRender) {
	/*** Then if this Border has some lines ***/
		if (((struct Border *)Gad->GadgetRender)->XY) {
		/*** Free the Lines ***/
			FreeMem (((struct Border *)Gad->GadgetRender)->XY, 40);
		}
	/*** Free the Border ***/
		FreeMem (Gad->GadgetRender, sizeof (struct Border));
	}
/*** If this Gadget has an IText ***/
	if (Gad->GadgetText) {
	/*** Free the IText ***/
		FreeMem (Gad->GadgetText, sizeof (struct IntuiText));
	}
/*** Free this Gadget and Return the next one ***/
	next = Gad->NextGadget;
	FreeMem (Gad, sizeof (struct Gadget));
	return (next);
}

struct Gadget *
AddChoice (choice)
char *choice;
{
	int i, j, x, width;
	struct IntuiText *IText;
	struct Gadget	 *Gad;
	struct Border    *Border;
	SHORT		 *lines;

/*** Allocate a Gadget struct ***/
	if ((Gad = AllocMem (sizeof (struct Gadget), NULL)) == NULL) {
		return (NULL);
	}
/*** Copy an pre-initialized Gadget into this newone ***/
	*Gad = OrigMessageGadget;

/*** Allocate an IntuiText struct ***/
	if ((IText = AllocMem (sizeof (struct IntuiText), NULL)) == NULL) {
		FreeChoice (Gad);
		return (NULL);
	}
/*** Copy an pre-initialized IntuiText into this new one ***/
	*IText = OrigGIText;

/*** Link it to this button's gadget ***/
	Gad->GadgetText = IText;

/*** Allocate a Border struct ***/
	if ((Border = (struct Border *)AllocMem (sizeof (struct Border), 0L))
	   == NULL) {
		FreeChoice (Gad);
		return (NULL);
	}
/*** Copy a pre-initialize Border into this new one ***/
	*Border = OrigGBord;

/*** Link it to this Gadget ***/
	Gad->GadgetRender = (APTR)Border;

/*** Allocate lines for Border ***/
	if ((lines = AllocMem (40, 0L)) == NULL) {
		FreeChoice (Gad);
		return (NULL);
	}
/*** Link them into the Border ***/
	Border->XY = lines;

/*** Link this button's Text in ***/
	IText->IText = (UBYTE *)choice;

	width = strlen (choice) * 8 + 6;

/*** 'Create' the border lines while copying an original ***/
	for (i = 0; i < 20; i+=2) {
		j = i + 1;
		if (OrigGLines[i] >= 0) {
			lines[i] = OrigGLines[i];
		} else {
			lines[i] = width + OrigGLines[i];
		}
		lines[j] = OrigGLines[j];
	}

	switch (TotalChoices % 3) {
		case 0:	x = MESSWIDTH - 6 - width;
			RightGad = Gad;
			break;
		case 1: x = 4;
			LeftGad = Gad;
			break;
		case 2: x = ( RightGad->LeftEdge -
			    ( LeftGad->LeftEdge +
			    LeftGad->Width - 1 ) ) / 2 -
			    width / 2 +
			    LeftGad->LeftEdge +
			    LeftGad->Width;
			break;
	}

	Gad->LeftEdge = x;
	Gad->TopEdge  = TotalLines * 8 + 8 + (TotalChoices / 3) * 14;
	Gad->Width    = width;
	TotalChoices++;
	Gad->GadgetID = TotalChoices;

	return (Gad);
}

AddLine (mode, line)
int mode;
char *line;
{

	int length;

	length = strlen (line);
	switch (mode) {
		case LEFT:	strcpy (TextLines[TotalLines], " ");
				strcat  (TextLines[TotalLines], line);
				strncat (TextLines[TotalLines],
					"                                ",
				(31-length));
				break;
		case CENTER:	strncpy (TextLines[TotalLines],
					"                                ",
					(32-length)/2);
				TextLines[TotalLines][(32-length)/2] = '\0';
				strcat	(TextLines[TotalLines], line);
				strncat (TextLines[TotalLines],
					"                                ",
				(32-length)/2 + length % 2);
				break;
	}

	MessageText[TotalLines].FrontPen = TextColor;
	MessageText[TotalLines].BackPen  = (TotalLines == 0) ? HeadingColor :
							       MessageColor ;
	MessageText[TotalLines].DrawMode = JAM2;
	MessageText[TotalLines].LeftEdge = 1;
	MessageText[TotalLines].TopEdge  = TotalLines * 8 + 2 + 
						(TotalLines > 0) * 3;
	MessageText[TotalLines].ITextFont= &MessageFont;
	MessageText[TotalLines].IText    = (UBYTE *)TextLines[TotalLines];
	MessageText[TotalLines].NextText = NULL;
	if (TotalLines > 0) {
		MessageText[TotalLines-1].NextText = &MessageText[TotalLines];
	}
	TotalLines++;
}

int GetInput (InputWindow)
struct Window *InputWindow;
{
	struct IntuiMessage *MessMessage;
	struct Screen *OldScreen;
	ULONG IDCMPFlags;
	int flag, i;
#ifndef TEST
	SetColors (InputWindow);
#endif
	flag = 0;
	
	IDCMPFlags = InputWindow->IDCMPFlags;
	ModifyIDCMP (InputWindow, GADGETUP);
	if (Request (&MessageRequester, InputWindow)) {
		ClearPointer (InputWindow);
		OldScreen = IntuitionBase->ActiveScreen;
		if (InputWindow->WScreen != OldScreen) {
			ScreenToFront (InputWindow->WScreen);
		}		
		do {
			while ((MessMessage = (struct IntuiMessage *)
				GetMsg (InputWindow->UserPort)) != NULL) {
				if (MessMessage->Class == GADGETUP) {
					flag = ((struct Gadget *)MessMessage->
						IAddress)->GadgetID;
				}
				ReplyMsg (MessMessage);
			}
			if (flag == 0) {
				Wait (1 << InputWindow->UserPort->mp_SigBit);
			}
		} while (flag == 0);
		if (OldScreen != IntuitionBase->ActiveScreen) {
			ScreenToFront (OldScreen);
		}
	}
	ModifyIDCMP (InputWindow, IDCMPFlags);
#ifndef TEST
	RestoreColors (InputWindow);
#endif
	return (flag);
}


int Message (MessWindow, heading, message, options)
struct Window *MessWindow;
char *heading;
char *message;
char *options;
{
	int i, j, length, height, space, mode;
	struct Gadget *Gad = 0;
	struct Gadget *LastGad;
	char *owork;
	char work[31];
	int input = 0;
	int icon = 0;

	TotalLines   = 0;
	TotalChoices = 0;
	MGadget      = 0L;
	GOptions     = options;

	AddLine (CENTER, heading); 

	i = 0;
	while (message[i] != NULL) {
		length = 0;
		mode = 0;
		while(length < 30 && message[i] != NULL && mode == 0) {
			if (message[i] == '\n') {
				mode = LEFT;
			} else if (message[i] == '\t') {
				mode = CENTER;
			} else {
				work[length] = message[i];
				length++;
			}
			i++;
			if (message[i] == ' ') {
				space = length;
			}
		}
		if (mode == 0 && message[i] != NULL) {
			work[space] = NULL;
			i = i - (length - space) + 1;
		} else {
			work[length] = NULL;
		}
		if (mode == 0) {
			mode = LEFT;
		}
		AddLine (mode, work);

	}

	i=-1;
	do {
		i++;
		owork = &options[i];
		length = 0;
		while (options[i] != '|' && options[i] != '\0') {
			length++; i++;
		}
		j = owork[length];
		owork[length] = '\0';
		if ((Gad = AddChoice (owork)) == NULL) {
			FreeAll ();
			return (NULL);
		}
		if (!MGadget) {
			MGadget = Gad;
		} else {
			LastGad->NextGadget = Gad;
		}
		LastGad = Gad;
	} while (j != '\0');

	height = TotalLines * 8 + 10 + GHEIGHT + 2 + 
		 ((TotalChoices- 1) / 3) * 14;

	MessLines[11] = height - 2;
	MessLines[13] = height - 2;
	MessLines[21] = height - 1;
	MessLines[23] = height - 1;
	MessLines[25] = height - 1;
	MessLines[27] = height - 1;
	MessCorner1Lines[1] = height - 1;
	MessCorner1Lines[3] = height - 1;
	MessageRequester.Height    = height;
	MessageRequester.ReqGadget = MGadget;
	NewMessWindow.Height = height;
	if (MessWindow == NULL) {
		MessageRequester.TopEdge = 0;
		MessageRequester.LeftEdge = 0;
	} else {
		MessageRequester.TopEdge = MESSTOP;
		MessageRequester.LeftEdge = MESSLEFT;
	}

	MessageRequester.BackFill = MessageColor;
	MessBorder[0].FrontPen = BorderColor;
	MessBorder[1].FrontPen = HeadingColor;
	MessBorder[1].BackPen  = HeadingColor;

	itemp = IntuitionBase;
	if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library", 0L))) {
		gtemp = GfxBase;
		if ((GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0L))) {
			if (MessWindow == NULL) {
				MessWindow = OpenWindow(&NewMessWindow);
				if (MessWindow != NULL) {
					input = GetInput (MessWindow);
					CloseWindow(MessWindow);
				}
			} else {
				input = GetInput (MessWindow);
			}
			CloseLibrary (GfxBase);
		}
		GfxBase = gtemp;
		CloseLibrary (IntuitionBase);
	}
	IntuitionBase = itemp;

	FreeAll ();
	return (input);
}

FreeAll ()
{
	int i;
	struct Gadget *oldGad;

	while (MGadget) {
		oldGad = MGadget->NextGadget;
		FreeChoice (MGadget);
		MGadget = oldGad;
	}
	for (i = 0; i < TotalChoices - 1; i++) {
		while (*GOptions != '\0') {
			GOptions++;
		}
		*GOptions++ = '|';
	}
}

#ifdef TEST
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

main (argc, argv)
int argc;
char **argv;
{
	exit (5 * (Message (NULL, argv[1], argv[2], argv[3]) - 1));
}
#endif
