/*
 * TaskY
 * 
 * Simple replacement for TaskX. Why? Because I wanted to...
 * 
 * Martin W. Scott, 19 March 1993.
 */

#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <dos/dos.h>
#include <dos/var.h>
#include <libraries/gadtools.h>
#include <intuition/intuition.h>
#include <string.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>

#include "sprintf.h"

static UBYTE VersTag[] = "\0$VER: TaskY 1.0";

#define ENVNAME		"TaskY_pos"

#include "ptask.h"
PTASK *ptask;			/* current task node */
WORD n=-1;			/* and its place in list */
TASK *currtask;			/* and task, for relocation */

/* Local protos */
void EasyEasyRequest(char *str);
void CloseLibs(void);
BOOL OpenLibs(void);
void LoadPosition(void);
void SavePosition(void);
VOID __main(char *args);
void HandleWindow(void);

/* Libraries */
struct Library *GadToolsBase, *UtilityBase;
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
extern struct ExecBase *SysBase;

#include "window.c"	/* gadtools-generated... */

/* dead simple requester */
void
EasyEasyRequest(char *str)
{
    struct EasyStruct es;

    es.es_StructSize = sizeof(struct EasyStruct);

    es.es_Flags = 0L;
    es.es_Title = "TaskY Message";
    es.es_TextFormat = str;
    es.es_GadgetFormat = "OK";
    EasyRequestArgs(NULL, &es, NULL, NULL);
}

#define Msg(s) EasyEasyRequest(s)

void
CloseLibs()
{
	if (GadToolsBase) CloseLibrary(GadToolsBase);
	if (UtilityBase) CloseLibrary(UtilityBase);
	if (GfxBase) CloseLibrary(GfxBase);
	if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
}

BOOL
OpenLibs()
{
	if ((IntuitionBase = (void *)OpenLibrary("intuition.library", 0L)) &&
	    (GfxBase = (void *)OpenLibrary("graphics.library", 37L)) &&
	    (UtilityBase = OpenLibrary("utility.library", 37L)) &&
	    (GadToolsBase = OpenLibrary("gadtools.library", 37L)))
	{
		return TRUE;
	}
	CloseLibs();
	return FALSE;
}

/* try to get position of window from env-var */
void
LoadPosition()
{
	UWORD pos[3];
	LONG rc;

	rc = GetVar(ENVNAME, (UBYTE *)pos, 3*sizeof(UWORD), GVF_BINARY_VAR);
	if (rc != -1)	/* okay */
	{
		TaskYLeft = pos[0];
		TaskYTop = pos[1];
	}
}

/* save (as env-var) position of window */
void
SavePosition()
{
	UWORD pos[3];

	pos[0] = TaskYLeft;
	pos[1] = TaskYTop;
	pos[2] = 0;

	SetVar(ENVNAME, (UBYTE *)pos, 2*sizeof(UWORD)+1, GVF_GLOBAL_ONLY); 
	/* don't care if it worked... */
}

VOID
__main(char *args)
{
	if (OpenLibs())
	{
		if (RefreshPTaskList())		/* read & copy list */
		{
			if (!SetupScreen())
			{
				LoadPosition();
				if (!OpenTaskYWindow())
				{
					HandleWindow();
					CloseTaskYWindow();
				}
				else Msg("Couldn't open window");
				CloseDownScreen();
				SavePosition();
			}
			else Msg("Couldn't get screen data");

			DeletePTaskList();	/* and finally, delete list */
		}
		else Msg("Couldn't allocate memory");

		CloseLibs();
	}
}

/* get nth node in list - list MUST have >= n nodes!!! */
struct Node *
GetNode(struct List *lh, UWORD n)
{
	struct Node *ln;

	for (ln = lh->lh_Head; n--; ln = ln->ln_Succ)
		;
	return ln;
}

/* initialise individual gadget */
void
InitGadget(UWORD num, LONG tagtype, LONG tagvalue)
{
	GT_SetGadgetAttrs(TaskYGadgets[num], TaskYWnd, NULL, tagtype, tagvalue, TAG_DONE);
}

/* initialise display */
void
InitGadgets(void)
{
	static char windtitle[25]; 

	InitGadget(GDX_ListView, GTLV_Labels, (LONG)&ptlist);
	InitGadget(GDX_ListView, GTLV_Selected, n);
	if (n >= 0)
		InitGadget(GDX_Pri, GTIN_Number, ptask->pt_TaskPri);
	else
		InitGadget(GDX_Pri, GTIN_Number, 0);

	SPrintf(windtitle, "TaskY 1.0   %ld tasks", num_ptasks);
	SetWindowTitles(TaskYWnd, windtitle, (UBYTE *)~0);
}

/* update list and gadgets */
void
Update(void)
{
	PTASK *pt;
	UWORD new_n;

	if (!RefreshPTaskList())
		Msg("Couldn't allocate memory");

	if (n >= 0)	/* something was selected */
	{
		n = -1;
		for (new_n = 0, pt = (PTASK *)ptlist.lh_Head;
		     pt->pt_Node.ln_Succ;
		     new_n++, pt = (PTASK *)pt->pt_Node.ln_Succ)
		{
			if (pt->pt_Task == currtask)
			{
				n = new_n;
				ptask = pt;
				break;
			}
		}
	}
	InitGadgets();
}

#define GadString(gadget)	((struct StringInfo *)(gadget)->SpecialInfo)->Buffer
#define GadNum(gadget)		((struct StringInfo *)(gadget)->SpecialInfo)->LongInt

/* handle window gadgets/menus */
void
HandleWindow()
{
	struct IntuiMessage *msg;
	struct Gadget *gad;
	struct Task *task;
	ULONG class;
	UWORD code;
	LONG sigs, sigmask, newpri;
	BOOL zipped = FALSE;

	InitGadgets();

	sigmask = 1 << TaskYWnd->UserPort->mp_SigBit |
		  SIGBREAKF_CTRL_C;

	for (;;)	/* loop until return... */
	{
		sigs = Wait(sigmask);

		if (sigs & SIGBREAKF_CTRL_C)
			return;

		while (msg = GT_GetIMsg(TaskYWnd->UserPort))
		{
			class = msg->Class;
			code = msg->Code;
			gad = (struct Gadget *)msg->IAddress;
			GT_ReplyIMsg(msg);

			switch (class)
			{
			case CLOSEWINDOW:
				return;

			case REFRESHWINDOW:
				GT_BeginRefresh(TaskYWnd);
				GT_EndRefresh(TaskYWnd, TRUE);
				break;

			case CHANGEWINDOW:
				if (TaskYWnd->Width == TaskYWidth)
				{
					if (zipped)
					{
						/* unzipped! */
						zipped = FALSE;
						Update();
					}

					/* not zipped, must be moved */
					TaskYLeft = TaskYWnd->LeftEdge;
					TaskYTop = TaskYWnd->TopEdge;
				}
				else if (TaskYWnd->Width < TaskYWidth)
					zipped = TRUE;
				break;

			case VANILLAKEY:
				switch (code)
				{
				case 'u': case 'U':
					Update();
					break;
				case 'z': case 'Z':
					ZipWindow(TaskYWnd);
					break;
				case 27:  /* ESCAPE */
					return;
				}
				break;

			case GADGETDOWN:
			case GADGETUP:
				if (gad->GadgetID == GD_ListView)
				{
					n = code;
					ptask = (PTASK *)GetNode(&ptlist, n);
					currtask = ptask->pt_Task;
					InitGadget(GDX_Pri, GTIN_Number, ptask->pt_TaskPri);
					ActivateGadget(TaskYGadgets[GD_Pri], TaskYWnd, NULL);
					break;
				}
				else if (gad->GadgetID == GD_Update)
				{
					Update();
					break;
				}
				else /* some other button */
				{
					if (n < 0)
						break;
					/* okay, do the changes */
					Forbid();
					if (!(task = GetOrigTask(ptask)))
					{
						Permit();
						break;
					}

					switch (gad->GadgetID)
					{
					case GD_MinusFive:
						SetTaskPri(task, -5);
						break;

					case GD_MinusOne:
						SetTaskPri(task, -1);
						break;

					case GD_Zero:
						SetTaskPri(task, 0);
						break;

					case GD_PlusOne:
						SetTaskPri(task, 1);
						break;

					case GD_PlusFive:
						SetTaskPri(task, 5);
						break;

					case GD_Pri:
						newpri = GadNum(gad);
						if (newpri >= -128 && newpri < 128)
							SetTaskPri(task, newpri);
						break;

					case GD_SigC:
						Signal(task, SIGBREAKF_CTRL_C);
						/* give it a chance to work */
						if (task != SysBase->ThisTask)
							Delay(50);
						break;

					case GD_SigD:
						Signal(task, SIGBREAKF_CTRL_D);
						break;

					case GD_SigE:
						Signal(task, SIGBREAKF_CTRL_E);
						break;

					case GD_SigF:
						Signal(task, SIGBREAKF_CTRL_F);
						break;

					} /* switch (gadget id) */
					Permit();
					Update();
					break;
				}

			} /* switch (class) */

		} /* while */

	} /* for */

} /* HandleWindow() */
