/* ModEngine1.c
 * Copyright (C) 1990 Commodore-Amiga, Inc.
 * written by David N. Junod
 *
 * Modular event processing shell for Intuition
 *
 */

#include "mod.h"
#include "ModEngine1.h"

/* Required for Intuition processing */
struct IntuitionBase *IntuitionBase = NULL;

/* Main processing loop */
VOID main ()
{
    struct AppInfo *ai = NULL;
    struct List *list = NULL;
    struct Node *node = NULL;
    struct MsgHandler *mh = NULL;
    ULONG sig_rcvd;

    /* Obtain the needed resources */
    ai = OpenAll ();
    list = &(ai->MsgList);

    /* Process messages until user signals that they are done. */
    /* loop until done and no messages outstanding */
    while (!ai->Done || ai->numcmds)
    {
	/* wait for a message to come in */
	sig_rcvd = Wait (ai->sigbits);

	/* process signals */
	if (list->lh_TailPred != (struct Node *) list)
	{
	    node = list->lh_Head;
	    while (node->ln_Succ)
	    {
		mh = (struct MsgHandler *) node;
		if (node->ln_Type==MH_HANDLER_T && (mh->mh_SigBits & sig_rcvd))
		    (*mh->mh_Func[MH_HANDLE]) (ai, mh);
		node = node->ln_Succ;
	    }
	}
    }
    /* Free up all the resources cleanly */
    CloseAll (ai, RETURN_OK, NULL);
}

/*--- Obtain the needed resources ---*/
struct AppInfo *OpenAll ()
{
    struct AppInfo *ai = NULL;

    /* open required libraries here */
    if (!(IntuitionBase = (struct IntuitionBase *)
	  OpenLibrary ("intuition.library", 33L)))
	CloseAll (ai, RETURN_FAIL, "Could not open intuition.library");

    /* Allocate memory for all our variables */
    if (!(ai = (struct AppInfo *)
	  AllocMem (sizeof (struct AppInfo), MEMF_CLEAR|MEMF_PUBLIC)))
	CloseAll (ai, RETURN_FAIL, "Not enough memory");

    /* Initialize the message handler list */
    NewList (&(ai->MsgList));

    /* set up the function table pointer */
    ai->FuncTable = &FTable[0];

    /* set up ARexx message handler */
    if (!(AddMsgHandler (ai,
			 setup_arexx (ai, "OURAPP", "mod", ACTIVE),
			 OPTIONAL))) /* handler optional */
	CloseAll (ai, RETURN_FAIL, "Could not allocate ARexx resources");

    /* set up DOS command shell message handler */
    if (!(AddMsgHandler (ai,
			 setup_dos (ai, "CON:0/150/600/50/Command Window",
				    "Cmd>", "Waiting for message(s)\n",
				    INACTIVE),
			 OPTIONAL))) /* handler optional */
	CloseAll (ai, RETURN_FAIL, "Could not allocate DOS resources");

    /* set up IDCMP message handler */
    if (!(AddMsgHandler (ai,
			 setup_idcmp (ai, &NewWindow, KeyArray, &Menu1,
			              ACTIVE),
			 REQUIRED))) /* handler required */
	CloseAll (ai, RETURN_FAIL, "Could not allocate IDCMP resources");

    return (ai);
}

/*--- Free up all the resources that we obtained ---*/
VOID CloseAll (struct AppInfo * ai, int value, UBYTE * fmsg)
{
    struct List *list = &(ai->MsgList);
    struct Node *node = NULL, *nxtnode = NULL;
    struct MsgHandler *mh = NULL;

    /* display error message, if there is one */
    if (fmsg)
	NotifyUser (NULL, fmsg);

    /* shutdown all the handlers */
    if (list->lh_TailPred != (struct Node *) list)
    {
	node = list->lh_Head;
	while (nxtnode = node->ln_Succ)
	{
	    mh = (struct MsgHandler *) node;
	    (*mh->mh_Func[MH_SHUTDOWN]) (ai, mh);
	    node = nxtnode;
	}
    }

    /* free our variable space */
    if (ai)
	FreeMem (ai, sizeof (struct AppInfo));

    /* close down libraries now */
    if (IntuitionBase)
	CloseLibrary ((struct Library *) IntuitionBase);

    exit (value);
}

/* add a message handler node to the handler list */
BOOL AddMsgHandler (struct AppInfo * ai, struct MsgHandler * mh,
		    BOOL needed)
{
    BOOL retval = FALSE;

    if (mh)
    {
	Enqueue (&(ai->MsgList), (struct Node *) mh);
	ai->sigbits |= mh->mh_SigBits;
	retval = TRUE;
    }
    return ( (BOOL)((needed) ? retval : TRUE) );
}

/* handle messages between function handlers */
BOOL HandlerFunc (struct AppInfo * ai, UBYTE * name, WORD function)
{
    BOOL retval = FALSE;
    struct MsgHandler * mh;

    if (mh = (struct MsgHandler *)FindName (&(ai->MsgList), name))
    {
	if (mh->mh_Func[function])
	    retval = (*mh->mh_Func[function])(ai, mh);
    }
    return (retval);
}

/* get handler data */
struct MsgHandler * HandlerData (struct AppInfo * ai, UBYTE * name)
{
    return ( (struct MsgHandler *)FindName (&(ai->MsgList), name) );
}

/* First checks to see if the command is an internal function and if so,
 * it executes the function.  Otherwise, it passes the command to ARexx. */
BOOL PerfFunc (struct AppInfo * ai, struct Message * msg, UBYTE * anchor)
{
    extern BOOL send_rexx_command (UBYTE *, struct AppInfo *,
				   struct MsgHandler *);
    struct MsgHandler * mh = NULL;
    register VOID (*func) (struct AppInfo *, struct Message *, UBYTE *);
    register UBYTE *args = anchor;
    register WORD cntr;
    BOOL retval = FALSE;
    UBYTE arg1[50];

    /* get the first word of the command string */
    args = stptok (args, arg1, sizeof (arg1), " ,");

    /* increment past first space */
    if (strlen (args) > 0)
	++args;

    /* check the array to see if it is a name that we understand */
    for (cntr = 1, func = NO_FUNCTION;
	 (ai->FuncTable[cntr].name != NULL) && (func == NO_FUNCTION);
	 cntr++)
    {
	if ((strcmpi (arg1, ai->FuncTable[cntr].name)) == 0)
	    func = ai->FuncTable[cntr].func;
    }

    /* preset the error return to zero */
    ai->pri_ret = 0L;

    if (func != NO_FUNCTION)
    {
	/* valid internal function, let's execute it */

	/* execute the function */
	(*(func)) (ai, (struct Message *) msg, args);

	/* successful command completion */
	retval = TRUE;
    }
    else
    {
	/* see if we are using ARexx */
	if (mh = HandlerData (ai, "AREXX"))
	{
	    /* wasn't an internal function, so let's pass it to ARexx */
	    if (!send_rexx_command (anchor, ai, mh))
	    {
		/* ARexx failed (not present) */
		NotifyUser (NULL, "ARexx not present");
	    }
	    else
		/* successful command completion */
		retval = TRUE;
	}
    }
    return (retval);
}
