
/*
 * MAIN.C
 * (c) 1992-3 J.Harper
 */

#include "jed.h"
#include "jed_protos.h"

Local	    BOOL	parseargs   (VOID);
Prototype   VALUE *	cmd_ilock   (LONG, VALUE *);
Prototype   VOID	doconmsg    (STRPTR);
__stkargs   VOID	_exit	    (LONG);

Prototype   const UBYTE NoMemMsg[];
	    const UBYTE NoMemMsg[]	 = "panic: no memory!";
Prototype	  UBYTE RexxName[];
		  UBYTE RexxName[]	 = "JED.XXXX";
Local	    const UBYTE NoStartupBdy[]	 = "Can't find a startup script, this means no keybindings or menus.\nAre you sure you want to go on? (I'd read the docs if I was you)";
Local	    const UBYTE NoStartupGad[]	 = "OK|Exit";
Local	    BOOL	ILock;
extern	struct Library *DOSBase;
extern	    APTR	_WBMsg;

/*
 * This function has to be stack based since c.o doesn't like a registered
 * _main().
 */
__stkargs VOID
_main(LONG cmdLen, STRPTR cmdLine)
{
    LONG rc = 5;
    if(DOSBase->lib_Version < 36)
    {
	doconmsg("error: need system 2.0+\n");
	_exit(20);
    }
    NewMList(&TXList);
    if(_WBMsg ? newfile(NULL) : parseargs())
    {
	initpath();
	if(initcommands())
	{
	    LONG rexxsig;
	    WORD i;
	    BOOL donerexx = FALSE;
	    Forbid();
	    for(i = 1;; i++)
	    {
		sprintf(RexxName, "JED.%ld", i);
		if(!FindPort(RexxName))
		{
		    rexxsig = upRexxPort(RexxName, "jed");
		    break;
		}
	    }
	    Permit();
	    if(scriptfile("jed-startup") || scriptfile("s:jed/jed-startup") || scriptfile("s:jed-startup") || ezreq(NoStartupBdy, NoStartupGad, NULL))
	    {
		rc = 0;
		while(CurrVW)
		{
		    ULONG signals;
		    struct IntuiMessage *imsg;

		    stdtitle();
		    if(ILock && rexxsig)
			signals = Wait(rexxsig);
		    else
			signals = Wait((1 << CurrVW->vw_Window->UserPort->mp_SigBit) | rexxsig);
		    if(rexxsig && (signals & rexxsig))
			dispRexxPort();
		    while(CurrVW && (imsg = GetMsg(CurrVW->vw_Window->UserPort)))
		    {
			struct IntuiMessage imsgcopy = *imsg;
			ReplyMsg((struct Message *)imsg);

			CurrVW = (VW *)imsgcopy.IDCMPWindow->UserData;
			if(((imsgcopy.Class != IDCMP_RAWKEY) || (!(imsgcopy.Code & IECODE_UP_PREFIX))) && ((imsgcopy.Class != IDCMP_MENUPICK) || (imsgcopy.Code != MENUNULL)))
			{
			    switch(imsgcopy.Class)
			    {
				case IDCMP_NEWSIZE:
				    updatedimensions(CurrVW);
				    resyncxy();
				    CurrVW->vw_RefreshType |= RFF_ALL;
				    refresh();
				    cursor(ON);
				    break;
				case IDCMP_MOUSEBUTTONS:
				    if(imsgcopy.Code == IECODE_LBUTTON)
				    {
					resettitle();
					cursor(OFF);
					positioncursorfine(imsgcopy.MouseX, imsgcopy.MouseY);
					if(DoubleClick(CurrVW->vw_ClickSecs, CurrVW->vw_ClickMics, imsgcopy.Seconds, imsgcopy.Micros))
					{
					    switch(CurrVW->vw_BlockStatus)
					    {
						case 0:
						    CurrVW->vw_BlockStatus = -1;
						    setblockrefresh();
						    break;
						case 1:
						    CurrVW->vw_Block[1] = CurrVW->vw_CursorPos;
						    CurrVW->vw_BlockStatus = 0;
						    orderblock();
						    setblockrefresh();
						    break;
						case 2:
						    CurrVW->vw_Block[0] = CurrVW->vw_CursorPos;
						    CurrVW->vw_BlockStatus = 0;
						    orderblock();
						    setblockrefresh();
						    break;
						case -1:
						    CurrVW->vw_Block[0] = CurrVW->vw_CursorPos;
						    CurrVW->vw_BlockStatus = 1;
						    break;
					    }
					}
					resyncxy();
					refresh();
					cursor(ON);
					CurrVW->vw_ClickSecs = imsgcopy.Seconds;
					CurrVW->vw_ClickMics = imsgcopy.Micros;
				    }
				    else if(imsgcopy.Code == IECODE_RBUTTON)
				    {
					if(CurrVW->vw_Sleeping)
					{
					    unsleep();
					    refresh();
					    cursor(ON);
					}
				    }
				    break;
				case IDCMP_MOUSEMOVE:
				    if(imsgcopy.Qualifier & IEQUALIFIER_LEFTBUTTON)
				    {
					resettitle();
					cursor(OFF);
					positioncursorfine(imsgcopy.MouseX, imsgcopy.MouseY);
					resyncxy();
					refresh();
					cursor(ON);
				    }
				    break;
				case IDCMP_MENUPICK:
				    resettitle();
				    evalmenu(imsgcopy.Code, imsgcopy.Qualifier);
				    break;
				case IDCMP_CLOSEWINDOW:
				    TX *tx = CurrVW->vw_Tx;
				    if((numviews(tx) > 1) || (!tx->tx_Changes) || (ezreq("OK to lose %ld changes\nto file %s", "Yeah|Cancel", tx->tx_Changes, tx->tx_TitleName)))
				    {
					cursor(OFF);
					killwindow();
					if(CurrVW)
					{
					    refresh();
					    cursor(ON);
					}
				    }
				    break;
				case IDCMP_RAWKEY:
				    usekey(&imsgcopy);
				    break;
				case IDCMP_ACTIVEWINDOW:
				    updatedimensions(CurrVW);
				    cursor(OFF);
				    resyncxy();
				    if(CurrVW->vw_LastRefresh != CurrVW->vw_Tx->tx_Changes)
					CurrVW->vw_RefreshType |= RFF_ALL;
				    refresh();
				    cursor(ON);
				    break;
			    }
			}
		    }
		    if(CurrVW)
			stdtitle();
		}
		killclipstuff();
		killfilereq();
		killprompthist();
		killmenu();
		killbindings();
	    }
	    else
		killwindow();
	    dnRexxPort();
	    killsymbols();
	}
	else
	{
	    killwindow();
	    doconmsg("error: no memory to initialize symbol table\n");
	}
	killpath();
    }
    else
	doconmsg("error: can't open window\n");
    _exit(rc);
}

/*
 * CLI only.
 */
const UBYTE ArgTemplate[] = "FILES/M,PUBSCREEN/K,DTAB/N/K,CD/K";
enum ArgRef
{
    ARG_FILES,
    ARG_PUB,
    ARG_DT,
    ARG_CD,
    NUM_ARGS
};
LONG ArgVals[NUM_ARGS];
BOOL
parseargs(VOID)
{
    BOOL rc = FALSE;
    struct RDArgs *rd;
    if(rd = ReadArgs(ArgTemplate, ArgVals, NULL))
    {
	if(ArgVals[ARG_PUB])
	    strncpy(DefPrefs.prf_ScreenName, (STRPTR)ArgVals[ARG_PUB], 100);
	if(ArgVals[ARG_DT])
	    DefPrefs.prf_DiskTab = *((ULONG *)ArgVals[ARG_DT]);
	if(ArgVals[ARG_CD])
	{
	    BPTR dlck;
	    if(dlck = Lock((STRPTR)ArgVals[ARG_CD], SHARED_LOCK))
	    {
		dlck = CurrentDir(dlck);
		UnLock(dlck);
	    }
	    else
		PutStr("can't lock specified CD\n");
	}
	if(ArgVals[ARG_FILES])
	{
	    STRPTR *thisfi = (STRPTR *)ArgVals[ARG_FILES];
	    while(*thisfi)
	    {
		if(!newfile(*thisfi++))
		    Printf("warning: can't open file %s\n", (LONG)(*thisfi));
		else
		{
		    rc = TRUE;
		    refresh();
		    cursor(ON);
		}
	    }
	}
	if(!rc)
	{
	    if(rc = newfile(NULL))
	    {
		refresh();
		cursor(ON);
	    }
	}
	FreeArgs(rd);
    }
    else
	PutStr("error: bad argument specification\n");
    return(rc);
}

/*
 * Input lock, when this is on only ARexx messages can get through.
 */
VALUE *
cmd_ilock(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	setnumres(ILock);
	ILock = ARG1.val_Value.Number;
    }
    return(&RES);
}

/*
 * CLI/WB & 1.3/2.0 compatible
 */
VOID
doconmsg(STRPTR msg)
{
    if(_WBMsg)
    {
	BPTR fh = Open("CON:///80/JEd output/WAIT/CLOSE", MODE_NEWFILE);
	if(fh)
	    Write(fh, msg, strlen(msg));
	Close(fh);
    }
    else
	Write(Output(), msg, strlen(msg));
}

/*
 * reference to pull in WB startup
 */
VOID _waitwbmsg(VOID);
Local VOID
dummy(VOID)
{
    _waitwbmsg();
}
