/*  :ts=8 bk=0
 *
 * text.c:	Subtask to write text onto screen, and support routines.
 *		A lot of this was stolen directly from another published
 *		program I wrote.
 *
 * Leo L. Schwab			8710.6		(415) 456-3960
 */
#include <exec/types.h>
#include <devices/timer.h>
#include <graphics/gfx.h>
#include <graphics/rastport.h>
#include "marketroid.h"

#define docmd(p,r,c)	{ PutMsg (p, c);  WaitPort (r);  GetMsg (r); }

#define TIMERSIG	(1L << tr -> tr_node.io_Message.mn_ReplyPort -> mp_SigBit)
#define PRGSIG		(1L << prgport -> mp_SigBit)
#define	TEXTPORT	"Text Port"

#define	CMD_SUICIDE	CMD_NONSTD
#define	CMD_HELLO	(CMD_NONSTD+1)


struct IOStdReq		*textcmd;
struct MsgPort		*textport, *textreply;
struct Task		*texttask;


dotext (str, x, y)
char *str;
UWORD x, y;
{
	textcmd -> io_Command	= CMD_WRITE;
	textcmd -> io_Data	= (APTR) str;
	textcmd -> io_Offset	= ((long) x << 16) + y;
	PutMsg (textport, textcmd);
}

textdone ()
{
	return (GetMsg (textreply) != NULL);
}

waittext ()
{
	WaitPort (textreply);
	GetMsg (textreply);
}

/*
 * The text printing sub-task.  Designed to run at priority level 1.
 */
void
texter ()
{
	register struct IOStdReq	*msg;
	register long			sigmask;
	register char			*str;
	struct RastPort			rp;
	struct timerequest		*tr = NULL;
	struct IOStdReq			*replythis = NULL;
	struct MsgPort			*timeport = NULL,
					*prgport = NULL;
	long				x, y,
					delay = 100000;
	char				stopped = 1,
					active = 0;

	geta4 ();

	/*
	 * Since this is an independent task, we'll have to do
	 * everything ourselves.....
	 */
	if (!(timeport = CreatePort (NULL, NULL)))
		goto bombout;

	if (!(prgport = CreatePort (TEXTPORT, 1L)))
		goto bombout;

	if (!(tr = CreateExtIO (timeport, (long) sizeof (*tr))))
		goto bombout;

	if (OpenDevice (TIMERNAME, UNIT_VBLANK, tr, 0L))
		goto bombout;
	tr -> tr_node.io_Command = TR_ADDREQUEST;

	/*
	 * Stand around twiddling our thumbs until the main program
	 * wants us to do something.
	 */
	WaitPort (prgport);
	msg = GetMsg (prgport);
	if (msg -> io_Command != CMD_HELLO)
		die ("texter(): Hello???\n");
	rp = *((struct RastPort *) msg -> io_Data);
	SetFont (&rp, msg -> io_Device);
	ReplyMsg (msg);
	sigmask = TIMERSIG | PRGSIG;

	while (1) {
		Wait (sigmask);

		if (CheckIO (tr)) {
			/*  Timer expired, write next chunk of text.  */
			WaitIO (tr);
			active = 0;
			if (!stopped) {
				while (*str < ' ') {
					if (*str == '\033') {
						/*  Escape means Newline  */
						y += 8;
						Move (&rp, x, y);
					} else
						/*  Change color  */
						SetAPen (&rp, (long) *str);
					str++;
				}
				Text (&rp, str++, 1L);
				if (!*str) {
					stopped = 1;
					ReplyMsg (replythis);
				}
			}
		}

		while (msg = GetMsg (prgport))
			/*  Command coming in from main program  */
			switch (msg -> io_Command) {
			case CMD_RESET:
			case CMD_STOP:
			/*  Main program asking us to stop  */
				stopped = 1;
				ReplyMsg (msg);
				break;
			case CMD_START:
				stopped = 0;
				ReplyMsg (msg);
				break;
			case CMD_UPDATE:
				delay = (ULONG) msg -> io_Device;
				ReplyMsg (msg);
				break;
			case CMD_WRITE:
				str = (char *) msg -> io_Data;
				replythis = msg;
				x = msg->io_Offset >> 16;
				y = msg->io_Offset & 0xffff;
				Move (&rp, x, y);
				stopped = 0;
				break;
			case CMD_SUICIDE:
				goto bombout;
			default:
				ReplyMsg (msg);
			}

		if (!stopped && !active) {
			tr -> tr_time.tv_secs	= (ULONG) 0;
			tr -> tr_time.tv_micro	= (ULONG) delay;
			SendIO (tr);
			active = 1;
		}

	}
bombout:
	if (active) {	/*  Outstanding timer request  */
		WaitPort (timeport);
		GetMsg (timeport);
	}
	if (tr)
		if (tr -> tr_node.io_Command == TR_ADDREQUEST)
			/* Command got assigned, so its open */
			CloseDevice (tr);
		DeleteExtIO (tr, (long) sizeof (*tr));
	if (prgport)
		DeletePort (prgport);
	if (timeport)
		DeletePort (timeport);
	if (msg)
		/*  This must be the suicide message, so reply it  */
		ReplyMsg (msg);

	/*  Wait for Godot  */
	Wait (0L);
}


/*  Housekeeping  */
opentext (rp, font)
struct RastPort *rp;
void *font;
{
	if (!(textreply = CreatePort (NULL, NULL)))
		die ("Couldn't allocate textreply port.\n");

	if (!(textcmd = CreateStdIO (textreply)))
		die ("Couldn't allocate textcmd.\n");

	if (!(texttask = CreateTask ("Text Task", 1L, texter, 4096L)))
		die ("Text task failed to spawn\n");

	if (!(textport = FindPort (TEXTPORT)))
		die ("Can't locate text task's command port.\n");

	textcmd -> io_Command	= CMD_HELLO;
	textcmd -> io_Data	= (APTR) rp;
	textcmd -> io_Device	= font;
	docmd (textport, textreply, textcmd);
}

closetext ()
{
	if (textreply)
		while (GetMsg (textreply))
			;

	if (texttask) {
		textcmd -> io_Command = CMD_SUICIDE;
		docmd (textport, textreply, textcmd);
		DeleteTask (texttask);
	}
	if (textcmd)	DeleteStdIO (textcmd);
	if (textreply)	DeletePort (textreply);
}
