#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <dos/var.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/gadtools.h>
#include "/headers/mach.h"
#include "/headers/machlib.h"
#include "/headers/machlib_protos.h"
#include "/headers/machlib_pragmas.h"

#define LIST_LIST_ID    1
#define LIST_VNAME_ID   2
#define LIST_VALUE_ID   3

#define GADGWIDTH       150

#define IDCMP IDCMP_CLOSEWINDOW | IDCMP_RAWKEY | LISTVIEWIDCMP
#define FLAGS WFLG_ACTIVATE | WFLG_SMART_REFRESH | WFLG_CLOSEGADGET | \
			  WFLG_DEPTHGADGET | WFLG_DRAGBAR

kprintf(char *,... );
static void copy_vars(void);
static struct Node *find_value(UWORD code);
static void close_down(void);
static void create_glist(void);
static void set_value(UWORD sel);
static void putmsg_machv(long ev);

struct MachLibrary *MachBase;
struct IntuitionBase *IntuitionBase;
struct Library *GadToolsBase;

static struct TextAttr Topaz80 = {(STRPTR)"topaz.font",8,0,FPF_ROMFONT};
static APTR vi;

static struct Window *listw;
static struct Gadget *gad,*glist,*listG,*nameG,*valueG;
static struct NewWindow lwindow = {
	0,30, GADGWIDTH+4,146, -1,-1,
	IDCMP,
	FLAGS,
	NULL,
	NULL,
	(UBYTE*) " Variables",
	NULL,NULL,
	-1,-1,
	-1,-1,
	WBENCHSCREEN
	};

static struct LocalVar *vars;

static struct MachMessage machmsg = {{{NULL,NULL,NT_MESSAGE},NULL,sizeof(struct MachMessage)}};

main(int argc, char **argv)
{
	struct Process		*pr;
	struct IntuiMessage	*msg;
	struct Screen		*s;
	long				 list_sig,selected;
	ULONG				 class;
	UWORD				 code,gid;

	if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37L)) {
		if (GadToolsBase = OpenLibrary("gadtools.library",37L)) {
			if (MachBase = (struct MachLibrary*)OpenLibrary("mach.library",37L)) {
				s = LockPubScreen(NULL);
				lwindow.LeftEdge = (((s->Width - s->LeftEdge) - lwindow.Width) / 2);
				UnlockPubScreen(NULL,s);
				if (listw = OpenWindowTags(&lwindow, WA_AutoAdjust,TRUE,TAG_DONE)) {
					pr = (struct Process*)MachBase->ml_MachV_Task.Task;
					vars = (struct LocalVar*)&pr->pr_LocalVars;
					selected = 3; /* show below process, Result and RC */
					create_glist();
					if (gad) {
						AddGList(listw,glist, -1, -1, NULL);
						RefreshGList(glist, listw, NULL, -1);
						GT_RefreshWindow(listw, NULL);
						list_sig = (1L << (listw->UserPort->mp_SigBit));
						while (listw) {
							Wait(list_sig);
							while (listw && (msg = GT_GetIMsg(listw->UserPort))) {
								class = msg->Class;
								code = msg->Code;
								if (class == GADGETUP)
									gid = ((struct Gadget *)msg->IAddress)->GadgetID;
								GT_ReplyIMsg(msg);
								switch (class) {
								case IDCMP_CLOSEWINDOW:
									close_down();
									break;
								case IDCMP_GADGETUP:
									switch (gid) {
									case LIST_LIST_ID:
										selected = code;
										set_value(code);
										break;
									case LIST_VNAME_ID:
									case LIST_VALUE_ID:
										GT_SetGadgetAttrs(listG,listw,NULL,GTLV_Labels,~0,TAG_DONE);
										copy_vars();
										if (*MachBase->ml_Variable == '\0') {
											*MachBase->ml_Variable = -1;
											selected--;
										}
										putmsg_machv(GE_DO_VAR);
										GT_SetGadgetAttrs(listG,listw,NULL,GTLV_Labels,vars,GTLV_Selected,selected,TAG_DONE);
										set_value(selected);
										GT_SetGadgetAttrs(valueG,listw,NULL,GTST_String,MachBase->ml_Variable,TAG_DONE);
										break;
									}
								case RAWKEY:
									if (code == 0x42) /* tab */
										ActivateGadget(nameG,listw,NULL);
									break;
								}
							}
						}
					}
					close_down();
				}
				CloseLibrary((struct Library*)MachBase);
			}
			CloseLibrary((struct Library*)GadToolsBase);
		}
		CloseLibrary((struct Library*)IntuitionBase);
	}
}

static void set_value(UWORD sel)
{
	struct LocalVar		*lv;

	if (lv = (struct LocalVar*)find_value(sel)) {
		strncpy(MachBase->ml_Variable,lv->lv_Value,lv->lv_Len);
		MachBase->ml_Variable[lv->lv_Len] = '\0';
		GT_SetGadgetAttrs(valueG,listw,NULL,GTST_String,MachBase->ml_Variable,TAG_DONE);
	}
}

static void copy_vars(void)
{
	strcpy(MachBase->ml_VarName,((struct StringInfo *)(nameG->SpecialInfo))->Buffer);
	strcpy(MachBase->ml_Variable,((struct StringInfo *)(valueG->SpecialInfo))->Buffer);
}

static struct Node *find_value(UWORD code)
{
	struct Node *n;

	for (n=vars->lv_Node.ln_Succ;n->ln_Succ;n = n->ln_Succ) {
		if (code-- == 0)
			break;
	}
	return(n->ln_Succ ? n : NULL);
}

static void close_down(void)
{
	if (listw) 
		CloseWindow(listw);
	listw = NULL;
	if (glist)
		FreeGadgets(glist);
	glist = NULL;
}

static void create_glist(void)
{
	WORD  top,loff;
	struct NewGadget ng;
	struct Screen *listws;

	listws = ((struct IntuitionBase*)(IntuitionBase))->FirstScreen;
	vi = GetVisualInfoA(listws,TAG_DONE);
	top = listws->BarHeight + 1;
	loff = (IntuitionBase->LibNode.lib_Version < 38) ? 14 : 24;
	
	gad = CreateContext(&glist);
	
	ng.ng_VisualInfo	= vi;  /* these are required! */
	ng.ng_TextAttr		= &Topaz80;
	
	ng.ng_LeftEdge		= 4;
	ng.ng_TopEdge		= top;
	ng.ng_Width			= GADGWIDTH;
	ng.ng_GadgetText	= NULL;
	ng.ng_Flags			= 0;
	
	ng.ng_Height		= 12;
	ng.ng_GadgetID		= LIST_VNAME_ID;
	gad = CreateGadget(STRING_KIND, gad, &ng, 	GTST_MaxChars,80,
					   TAG_DONE);
	nameG = gad;

	ng.ng_Height		= 100 + loff;
	ng.ng_GadgetID		= LIST_LIST_ID;
	
	gad = CreateGadget(LISTVIEW_KIND, gad, &ng, GTLV_Labels, vars,
						GTLV_Top,			0,
						GTLV_ShowSelected,  nameG,
						GTLV_Selected,		3,
						GTLV_ScrollWidth,	20,
						TAG_DONE);
	listG = gad;

	ng.ng_TopEdge		= nameG->TopEdge+10;
	ng.ng_Width			= GADGWIDTH;
	ng.ng_GadgetText	= NULL;
	ng.ng_Flags			= 0;
	
	ng.ng_Height		= 12;
	ng.ng_GadgetID		= LIST_VALUE_ID;
	set_value(3);
	gad = CreateGadget(STRING_KIND, gad, &ng, 	GTST_MaxChars,80,
					   GTST_String,	(ULONG)MachBase->ml_Variable,
					   TAG_DONE);
	valueG = gad;
}

static void putmsg_machv(long ev)
{
  struct MsgPort *rp;

  rp = CreatePort(NULL,0L);
  if (rp) {
    machmsg.mm_Msg.mn_ReplyPort = rp;
    machmsg.mm_Msg.mn_Node.ln_Name = "MACHV";
    machmsg.mm_Command = MACHV_GENERAL_EVENT;
    machmsg.mm_SubCommand = ev;
    PutMsg(MachBase->ml_MsgPort,(struct Message*)&machmsg);
    WaitPort(rp);
    GetMsg(rp);
    DeletePort(rp);
  }
}
