/*
 *	ParM.c - Copyright © 1990 by S.R. & P.C.
 *
 *	Created:	01 Jul 1990
 *	Modified:	09 Dec 1990  17:39:57
 *
 *	Make>> make
 */

#include "WB.h"

#define COPYRIGHT "ParM V2.5r Copyright © 1990 by S.R. & P.C."
#define DEFAULT_CONFIG_FILE "S:ParM.cfg"

#define DEFAULT_CMD_WINDOW		"CON:0/11/640/100/Command window"
#define DEFAULT_SHELL_WINDOW	"CON:0/11/640/100/ParM Shell"
#define DEFAULT_SHELL_CMD		"AShell"
#define DEFAULT_WAIT_CMD		"WaitReturn"
#define DEFAULT_TMP_DIR			"T:"

#define THE_END			0
#define NO_ICON			1
#define NO_REQ			2
#define NO_WIN			3
#define NO_MENUS		4	/* This definition MUST be duplicated in MenuAlloc.c */
#define NO_PORT			5

#define OWN_MENU		0

#define OPEN_ITEM		0
#define UPDATE_ITEM		1
#define STD_CFG_ITEM	2
#define CMDMODE_ITEM	3
#define COMMAND_ITEM	4
#define CHDIR_ITEM		5
#define QUIT_ITEM		6


extern void Command(void);
extern BOOL ParseMenus(void);
extern void FreeMenus(void);
extern void InitMenuAlloc(void);
extern void CreateParMenu(short Color);
extern void DoExtMenu(USHORT);
extern void WBFree(struct WBStartup *);


/*****				global variables					*****/

extern struct ExecBase *SysBase;
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern struct ArpBase *ArpBase;
extern struct IconBase *IconBase;
extern struct ReqLib *ReqBase;
extern struct Process *MyProcess;
extern long DefaultStack;
extern char *ReqTitle;
extern struct WBStartup *WBenchMsg;
extern struct Window *Win;
extern struct Menu Menu1;
extern char CurCfg[];
extern char CmdWindow[];
extern char ShellWindow[];
extern char ShellCmd[];
extern char WaitCmd[];
extern char TmpDir[];
extern struct ParmMsgPort *ParMPort;
extern UBYTE menu_pen;
extern BOOL DoNextSelect;


/*****				 local variables					*****/

static BOOL Own_Window = FALSE;
static BOOL quit = FALSE;
static BYTE ParMenuColor = -1;
static struct FileReq FileReq;
static char Dir[REQ_DSIZE+1];
static char File[REQ_FCHARS+1];
static char Path[REQ_DSIZE+REQ_FCHARS+2];

struct ToolTypesArg {
	char *tta_Name;
	char tta_cli_equ;
};

static struct ToolTypesArg TTA_List[] = {
	{"STACKSIZE",	's'},
	{"LEFTEDGE",	'x'},
	{"TOPEDGE",		'y'},
	{"DETAILPEN",	'd'},
	{"BLOCKPEN",	'b'},
	{"MENUCOLOR",	'c'},
	{"CONFIGFILE",	'f'},
	{"NODRAGBAR",	'r'},
	{"LITTLE",		'l'}
};

#define TTANUM	8	/* Number of ToolTypesArg in List */


static struct NewWindow NWS = {
	0, 0,	/* window XY origin relative to TopLeft of screen */
	90, 10,	/* window width and height */
	3, 2,	/* detail and block pens */
	MENUPICK,	/* IDCMP flags */
	WINDOWDRAG + WINDOWDEPTH + SIMPLE_REFRESH + NOCAREREFRESH,	/* other window flags */
	NULL,	/* first gadget in gadget list */
	NULL,	/* custom CHECKMARK imagery */
	(UBYTE *)"ParM",	/* window title */
	NULL,	/* custom screen pointer */
	NULL,	/* custom bitmap */
	5, 5,	/* minimum width and height */
	-1, -1,	/* maximum width and height */
	WBENCHSCREEN	/* destination screen type */
};


/*****  make (and allocate) a copy of the passed string *****/

char *copystr(char *str)
{
	char *newstr;
	if (newstr = AllocMem(strlen(str)+1, MEMF_PUBLIC))
		strcpy(newstr, str);
	return newstr;
}


/***** get CLI window ptr *****/

static struct Window *GetWindow(void)
{
	struct InfoData *infodata;
	struct Window *win;
	long args[8];

	infodata = AllocMem((long) sizeof(struct InfoData), MEMF_CLEAR | MEMF_PUBLIC);
	args[0] = (long)infodata >> 2;
	SendPacket(ACTION_DISK_INFO, args, (struct MsgPort *)MyProcess->pr_ConsoleTask);
	win = (struct Window *)infodata->id_VolumeNode;
	FreeMem(infodata, (long)sizeof(struct InfoData));
	return win;
}


/* Configuration managing functions  */

static void InstallMenus(void)
{
	menu_pen = ParMenuColor;
	if (!ParseMenus())
		FreeMenus();
	SetMenuStrip(Win, &Menu1);
}

void UpDateMenus(void)
{
	ClearMenuStrip(Win);
	InstallMenus();
}

static void OpenMenus(void)
{
	char *yuck;

	FileReq.Title = "Open";
	strcpy(Dir, CurCfg);
	strcpy(File, yuck = BaseName(Dir));
	*yuck = '\0';		/* cut off filename from fr_Dir */
	if (!FileRequester(&FileReq))
		return;	/* quit if Open canceled */
	strcpy(CurCfg, Path);
	UpDateMenus();
}


/* Print busy message in place of window title  */

static void Busy(BOOL status)
{
	SetWindowTitles(Win, (status)?"Busy":"ParM", COPYRIGHT);
}


static void Usage(void)
{
	Printf("%s\nUsage: %s [-w] [-x#] [-y#] [-d#] [-b#] [-c#] [-r] [-l] [-s#] [-o] [-fConfigFile]\n", COPYRIGHT, "ParM");
	ArpExit(0, 0);
}


/* Atcho, bonsoir...  */

void Bye(short err)
{
	char *name;

	switch (err) {
	case THE_END:
		ClearMenuStrip(Win);
	case NO_MENUS:
		FreeMenus();
		Forbid();
		if (ParMPort->pmp_NumParmTask == 1 && ParMPort->pmp_MsgCnt == 0) {
			RemPort((struct MsgPort *)ParMPort);
			name = ParMPort->pmp_MsgPort.mp_Node.ln_Name;
			FreeMem(name, strlen(name));
			FreeMem(ParMPort, sizeof(struct ParmMsgPort));
		}
		else
			ParMPort->pmp_NumParmTask--;
		Permit();
	case NO_PORT:
		if (Own_Window == TRUE)
			CloseWindowSafely(Win, NULL);
		else
			ModifyIDCMP(Win, 0);
	}
	ArpExit(err, 0L);
}


/* change parm current directory */

static void ChangeDir(char *dir)
{
	BPTR NewLock, OldLock;

	NewLock = Lock(dir, ACCESS_READ);
	if (NewLock != NULL) {
		OldLock = CurrentDir(NewLock);
		if (OldLock != NULL)
			UnLock(OldLock);
	}
}


static void parse_arg(char opt, char *args)
{
	BPTR fh;
	long argl;

	argl = Atol(args);
	switch (opt) {
	case 'w':
		Own_Window = TRUE;
		break;
	case 's':
		if (argl >= 4000) DefaultStack = argl;
		break;
	case 'x':
		NWS.LeftEdge = argl;
		Own_Window = TRUE;
		break;
	case 'y':
		NWS.TopEdge = argl;
		Own_Window = TRUE;
		break;
	case 'd':
		NWS.DetailPen = argl;
		Own_Window = TRUE;
		break;
	case 'b':
		NWS.BlockPen = argl;
		Own_Window = TRUE;
		break;
	case 'c':
		ParMenuColor = argl;
		break;
	case 'f':
		strcpy(CurCfg, args);
		break;
	case 'r':	/* no drag bar */
		Own_Window = TRUE;
		NWS.Flags &= ~WINDOWDRAG;
		break;
	case 'l':	/* 'l' for Little window: no depth gadget */
		Own_Window = TRUE;
		NWS.Flags &= ~WINDOWDEPTH;
		NWS.Width -= 51;
		break;
	case 'o':
		if (fh = Open("NIL:", MODE_NEWFILE)) {
			MyProcess->pr_CIS = fh;
			MyProcess->pr_COS = fh;
		}
		break;
	case 'h':	/* those can only happen on CLI invocation */
	default:
		Usage();
	}
}


void main(int argc, char *argv[])
{
	struct CommandLineInterface *cli;
	struct WBStartup *Msg;
	struct DiskObject *dop;
	struct IntuiMessage *Message;
	ULONG Class;
	USHORT Code;
	char *arg;
	short i;

	IntuitionBase = (struct IntuitionBase *)ArpBase->IntuiBase;
	GfxBase = (struct GfxBase *)ArpBase->GfxBase;
	if (!(IconBase = (struct IconBase *)ArpOpenLibrary("icon.library", 0L))) {
		Printf("No icon.library!\n");
		Bye(NO_ICON);
	}
	if (!(ReqBase = (struct ReqLib *)ArpOpenLibrary("req.library", 1L))) {
		Printf("No req.library!\n");
		Bye(NO_REQ);
	}
	FileReq.Dir = Dir;
	FileReq.File = File;
	FileReq.PathName = Path;
	FileReq.dirnamescolor = 3;
	FileReq.devicenamescolor = 3;
	FileReq.stringnamecolor = 2;
	FileReq.stringgadgetcolor = 2;
	FileReq.boxbordercolor = 2;
	FileReq.gadgetboxcolor = 2;
	strcpy(FileReq.Show, "*.cfg");
	MyProcess = (struct Process *)SysBase->ThisTask;
	strcpy(CurCfg, DEFAULT_CONFIG_FILE);

	if (argc == 0) {	/* Tool Types parsing */
		Own_Window = TRUE;
		if (dop = GetDiskObject(WBenchMsg->sm_ArgList->wa_Name)) {
			DefaultStack = dop->do_StackSize;
			for (i = 0; i < TTANUM; i++) {
				if (arg = FindToolType(dop->do_ToolTypes, TTA_List[i].tta_Name))
					parse_arg(TTA_List[i].tta_cli_equ, arg);
			}
			FreeDiskObject(dop);
		}
	}
	else {	/* CLI parsing */
		cli = (struct CommandLineInterface *)((long)MyProcess->pr_CLI << 2);
		DefaultStack = cli->cli_DefaultStack << 2;
		for (i = 1; i < argc; i++) {
			if (*argv[i] != '-' || strlen(argv[i]) < 2)
				Usage();
			parse_arg(argv[i][1], &argv[i][2]);
		}
	}
	if (Own_Window == TRUE) {
		if (!(Win = OpenWindow(&NWS)))
			Bye(NO_WIN);
		Busy(FALSE);	/* SetWindowTitles() */
	}
	else {
		Win = GetWindow();
		if (Win->UserPort) {
			SimpleRequest(ReqTitle, "This window already have menus!");
			ArpExit(0, 0);
		}
		else
			ModifyIDCMP(Win, MENUPICK|CLOSEWINDOW);
	}
	if (ParMenuColor < 0) ParMenuColor = Win->DetailPen;
	CreateParMenu(ParMenuColor);
	Forbid();
	if (!(ParMPort = (struct ParmMsgPort *)FindPort("ParM_Port"))) {
		if (!(ParMPort = AllocMem(sizeof(struct ParmMsgPort), MEMF_CLEAR|MEMF_PUBLIC)))
			Bye(NO_PORT);
		ParMPort->pmp_MsgPort.mp_Node.ln_Name = copystr("ParM_Port");
		ParMPort->pmp_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
		ParMPort->pmp_MsgPort.mp_Flags = PA_IGNORE;
		AddPort((struct MsgPort *)ParMPort); /* also init the msg list */
		ParMPort->pmp_NumParmTask = 1;
	}
	else
		ParMPort->pmp_NumParmTask++;
	Permit();
	strcpy(CmdWindow, DEFAULT_CMD_WINDOW);
	strcpy(ShellWindow, DEFAULT_SHELL_WINDOW);
	strcpy(ShellCmd, DEFAULT_SHELL_CMD);
	strcpy(WaitCmd, DEFAULT_WAIT_CMD);
	strcpy(TmpDir, DEFAULT_TMP_DIR);
	InitMenuAlloc();
	InstallMenus();

	/* Monitor Menu Events */

	while (!quit) {
		WaitPort(Win->UserPort);
		while (Message = (struct IntuiMessage *)GetMsg(Win->UserPort)) {
			Class = Message->Class;
			Code = Message->Code;
			ReplyMsg((struct Message *) Message);
			switch (Class) {
			case 0x0FL:		/* Msg sent bye 'ParMCD' command */
				ChangeDir((char *)Message->IAddress);
				break;
			case CLOSEWINDOW:
				quit = TRUE;
				break;
			case MENUPICK:
				DoNextSelect = TRUE;
				if (Code != MENUNULL) {
					if (Own_Window)
						Busy(TRUE);
					do {
						switch(MENUNUM(Code)) {
						case OWN_MENU:
							switch(ITEMNUM(Code)) {
							case OPEN_ITEM:
								OpenMenus();
								DoNextSelect = FALSE;
								break;
							case UPDATE_ITEM:
								UpDateMenus();
								DoNextSelect = FALSE;
								break;
							case STD_CFG_ITEM:
								strcpy(CurCfg, DEFAULT_CONFIG_FILE);
								UpDateMenus();
								DoNextSelect = FALSE;
								break;
							case COMMAND_ITEM:
								Command();
								break;
							case CHDIR_ITEM:
								PathName(MyProcess->pr_CurrentDir, Dir, REQ_DSIZE);
								FileReq.Flags = FRQDIRONLYM;
								FileReq.Title = "Enter New Dir...";
								if (FileRequester(&FileReq))
									ChangeDir(Dir);
								FileReq.Flags = 0;
								break;
							case QUIT_ITEM:
								if( TwoGadRequest(ReqTitle, "Really Quit ParM ?") ) {
									quit = TRUE;
									DoNextSelect = FALSE;
								}
							}
							break;
						default:	/* custom menus */
							DoExtMenu(Code);
						}
					} while (DoNextSelect && (Code = ItemAddress(&Menu1, Code)->NextSelect) != MENUNULL);
					if (Own_Window)
						Busy(FALSE);
				}
				break;
			}
		}

		/* See if some wb messages have been replied */
		Forbid();
		while(Msg = (struct WBStartup *)GetMsg((struct MsgPort *)ParMPort)) {
			ParMPort->pmp_MsgCnt--;
			WBFree(Msg);
		}
		Permit();
	}
	Bye(THE_END);
}
