/*
 *	Run.c - Copyright © 1991 by S.R. & P.C.
 *
 *	Created:	30 Mar 1991  17:13:14
 *	Modified:	30 Jun 1991  11:11:35
 *
 *	Make>> make
 */

#include "Global.h"
#include "proto/Run.h"
#include "proto/Menus.h"
#include "proto/Windows.h"
#include "proto/Process.h"


/* don't track resources here because workbench's can be released by another process */

#ifdef TRACKER
#undef AllocMem
#undef FreeMem
#undef CopyStr
#undef FreeStr
#undef ParentDir
#undef CreateDir
#undef Lock
#undef DupLock
#undef UnLock
#endif

#define MAX_CLIARGS_LEN 250

extern struct Config Config;
extern struct ParMConfig ParMConfig;
extern struct MinList WindowList;
extern struct BrowserWindow *CurrentWin;
extern struct Menu Menu1;
extern char *ReqTitle;
extern BPTR BrowserDir;
extern short SelectNum;


static struct Extended_WBStartup *BuildWBStartup(struct ScrollEntry *Run, char *Cmd, long Stack)
{
	struct Extended_WBStartup *EWBS;
	struct BrowserWindow *Win;
	struct ScrollEntry *S;
	short NumArg, i, arg=1;

	if (!(EWBS = AllocMem(sizeof(struct Extended_WBStartup), MEMF_PUBLIC|MEMF_CLEAR)))
		return NULL;
	NumArg = SelectNum;
	if (!Run)	/* Menu selection then, so one arg more for the tool from menu */
		NumArg++;
	/* Allocate array for NumArg+1 args. Only NumArg may be needed */
	if (!(EWBS->ArgArray = AllocMem((NumArg+1)*sizeof(struct WBArg), MEMF_PUBLIC|MEMF_CLEAR))) {
		WBFree(EWBS);
		return NULL;
	}
	EWBS->ArrayLength = NumArg + 1;
	EWBS->WBStartup.sm_NumArgs = NumArg;
	EWBS->WBStartup.sm_ArgList = &EWBS->ArgArray[1];

	if (!Run && !MakeWBArg(&ParMConfig, EWBS->WBStartup.sm_ArgList, Cmd)) {
		WBFree(EWBS);
		return NULL;
	}
	Win = (struct BrowserWindow *)WindowList.mlh_Head;
	while(Win->bw_Node.mln_Succ) {
		if (Win->bw_SelectNum > 0) {
			for( i=0 ; i < Win->bw_ShownEntries ; i++ ) {
				S = Win->bw_EntryArray[i];
				if (S->se_State & STATE_SELECTED) {
					if (S == Run) {
						EWBS->WBStartup.sm_ArgList[0].wa_Name = CopyStr(Cmd);
						EWBS->WBStartup.sm_ArgList[0].wa_Lock = DupLock(Win->bw_DirLock);
					}
					else {
						EWBS->WBStartup.sm_ArgList[arg].wa_Name = CopyStr(S->se_FileInfo.fi_Name);
						EWBS->WBStartup.sm_ArgList[arg].wa_Lock = DupLock(Win->bw_DirLock);
						arg++;
					}
				}
			}
		}
		Win = (struct BrowserWindow *) Win->bw_Node.mln_Succ;
	}
	if (!GetTool(&ParMConfig, EWBS, Stack)) {
		WBFree(EWBS);
		return NULL;
	}
	return EWBS;
}


static BOOL BuildCLIArgs(char *Args, BPTR CurDir, BPTR CurRootDir, struct ScrollEntry *Current)
{
	struct BrowserWindow *Win;
	struct ScrollEntry *S;
	char *Dir, *sp1, *sp2;
	short len = 0, dirlen, i;
	char tmpbuf[256];

	sp1 = Args;
	*sp1 = '\0';
	Win = (struct BrowserWindow *)WindowList.mlh_Head;
	while (Win->bw_Node.mln_Succ) {
		if (Win->bw_SelectNum > 0) {
			if (Win->bw_Type == BW_MAIN || CurDir && !CompareLock(CurDir, Win->bw_DirLock)) {
				Dir = NULL;
				dirlen = 0;
			}
			else {
				strcpy(tmpbuf, (char *)Win->bw_Window->Title);
				Dir = tmpbuf;
				if (CurRootDir && !CompareLock(CurRootDir, Win->bw_RootLock))
					while(*Dir && *Dir != ':') Dir++;	/* Remove volume name from dir */
				sp2 = Dir;
				while(*sp2++);
				*sp2-- = '\0';
				if (*(sp2-1) != ':')
					*sp2 = '/';
				dirlen = strlen(Dir);
			}
			for( i=0 ; i < Win->bw_ShownEntries ; i++ ) {
				S = Win->bw_EntryArray[i];
				if ((S->se_State & STATE_SELECTED) && (S != Current)) {
					if (len+dirlen+strlen(sp2 = S->se_FileInfo.fi_Name)+3 > 250) {
						SimpleRequest(ReqTitle, "Command line too long.");
						return FALSE;
					}
					len += SPrintf(sp1, " \"%s%s\"", Dir, S->se_FileInfo.fi_Name);
					sp1 = Args + len;
				}
			}
		}
		Win = (struct BrowserWindow *) Win->bw_Node.mln_Succ;
	}
	return TRUE;
}


static BOOL AddArgs(char *Dest, char *Args)
{
	char *s, tmpbuf[256];

	if (strlen(Dest)+strlen(Args) > 252) {
		SimpleRequest(ReqTitle, "Command line too long.");
		return FALSE;
	}
	tmpbuf[0] = '\0';
	s = Dest;
	while(*s) {
		if (*s == '[' && *(s+1) == ']') {
			strcpy(tmpbuf, s+2);
			break;
		}
		s++;
	}
	strcpy(s, Args);
	strcpy(&Dest[strlen(Dest)], tmpbuf);	/* strcat() */
	return TRUE;
}


/* Result: Tell caller if extended select can be done */

BOOL DoExtMenu(USHORT MenuNum)
{
	struct Extended_MenuItem *Item;
	struct Extended_WBStartup *EWBS;
	struct RunInfo Command;
	BPTR DirLock=0L, RootLock=0L;
	char Args[256], Buffer[256];

	Item = (struct Extended_MenuItem *)ItemAddress(&Menu1, MenuNum);
	Command = Item->emi_RunInfo;
	switch (Item->emi_Mode) {
	case TOK_CFG:	/* new cfg */
		strcpy(ParMConfig.CurCfg, Command.ri_Cmd);
		UpdateMenus();
		return FALSE;	/* Tell caller not to execute next menu selection */
	case TOK_WB:
		SetWaitPointer(TRUE);
		if (EWBS = BuildWBStartup(NULL, Command.ri_Cmd, Command.ri_Stack))
			ASyncWBRun(&ParMConfig, EWBS, Command.ri_Pri);
		SetWaitPointer(FALSE);
		break;
	default:
		if (CurrentWin->bw_Type != BW_MAIN) {
			CurrentDir(DirLock = CurrentWin->bw_DirLock);
			RootLock = CurrentWin->bw_RootLock;
		}
		if (!BuildCLIArgs(Args, DirLock, RootLock, NULL))
			return FALSE;
		SetWaitPointer(TRUE);
		if (Item->emi_Mode == TOK_ARUN) {
			strcpy(Buffer, Command.ri_Args);
			if (AddArgs(Buffer, Args)) {
				Command.ri_Args = Buffer;
				ARun(&ParMConfig, &Command);
			}
		}
		else {
			strcpy(Buffer, Command.ri_Cmd);
			if (AddArgs(Buffer, Args)) {
				Command.ri_Cmd = Buffer;
				Run(&ParMConfig, &Command, Item->emi_Mode);
			}
		}
		SetWaitPointer(FALSE);
		CurrentDir(BrowserDir);
	}
	return TRUE;
}


BOOL DoRun(struct ScrollEntry *S, BPTR RunDir, BPTR RootDir)
{
	struct Extended_WBStartup *EWBS;
	struct DiskObject *DiskObject;
	struct RunInfo Command;
	char Cmd[256], Args[256], RunRequestTitle[40];
	char *p, *ModeTitle;
	short len;

	CurrentDir(RunDir);
	strcpy(Cmd, S->se_FileInfo.fi_Name);
	len = strlen(Cmd);
	if (len>5) {
		p = Cmd + len - 5;
		if (!Strcmp(p, ".info"))
			*p = '\0';		/* remove ".info" extension from filename */
	}
	if (DiskObject = GetDiskObject(Cmd)) {
		FreeDiskObject(DiskObject);
		if (EWBS = BuildWBStartup(S, Cmd, 0))
			ASyncWBRun(&ParMConfig, EWBS, 0);
	}
	else {
		if (BuildCLIArgs(Args, RunDir, RootDir, S)) {
			if (strlen(S->se_FileInfo.fi_Name) + strlen(Args) + 2 > 255) {
				SimpleRequest(ReqTitle, "Command line too long.");
				CurrentDir(BrowserDir);
				return FALSE;
			}
			SPrintf(Cmd, "\"%s\"%s", S->se_FileInfo.fi_Name, Args);
			Command.ri_Cmd = Cmd;
			Command.ri_Args = NULL;
			Command.ri_Window = ParMConfig.ShellWindow;
			Command.ri_Stack = ParMConfig.DefaultStack;
			Command.ri_Pri = 0;
			if (Config.RunMode & RM_REQUEST) {
				switch(Config.RunMode & ~RM_REQUEST) {
				case RM_RUNBACK:
					ModeTitle = "RunBack";
					break;
				case RM_SHELL:
					ModeTitle = "Shell";
					break;
				}
				SPrintf(RunRequestTitle, "Run...  [%s mode]", ModeTitle);
				if (!GetString(Cmd, RunRequestTitle, NULL, 60, 255)) {
					CurrentDir(BrowserDir);
					return FALSE;
				}
			}
			switch(Config.RunMode & ~RM_REQUEST) {
			case RM_RUNBACK:
				Run(&ParMConfig, &Command, TOK_RUN);
				break;
			case RM_SHELL:
				Run(&ParMConfig, &Command, TOK_SHELL);
				break;
			}
		}		
	}
	CurrentDir(BrowserDir);
	return TRUE;
}


void DoCommand(void)
{
	char Args[256];

	SetWaitPointer(TRUE);
	if (CurrentWin->bw_Type != BW_MAIN)
		CurrentDir(CurrentWin->bw_DirLock);
	if (SelectNum > 0 && BuildCLIArgs(Args, CurrentWin->bw_DirLock, CurrentWin->bw_RootLock, NULL))
		strcpy(ParMConfig.CommandBuffer, Args);
	Command(&ParMConfig);
	CurrentDir(BrowserDir);
	SetWaitPointer(FALSE);
}


