/*********************************************************************\
**                               ________________________________    **
**    A n t h o n y             |________    __    __    ________|   **
**                                       |  |o_|  |o_|  |            **
**            T h y s s e n            __|   __    __   |__          **
**                                  __|   __|  |  |  |__   |__       **
**   `` Dragon Computing ! ''    __|   __|     |  |     |__   |__    **
**                              |_____|        |__|        |_____|   **
**                                                                   **
\*********************************************************************/
/* This is the main process for AMenu.  This gets loaded and run in the
 * background by AMenu.  When started, it finishes initializing itself,
 * and starts monitoring the WorkBench IDCMP port.  If any messages show
 * up that we are interested in, we run them as a CLI or WorkBench
 * process.  We don't do any memory allocation or cleanup and leave that
 * all to AMenu (in order to save some space).  Communication with
 * AMenu is done via a public port - never used as a port, but it holds
 * "global" variables.
 */

#include "AMenu.h"
#include <libraries/dosextens.h>   /* definition for struct Process */

static char *Copyright = COPYRIGHT;

struct ArpBase       *ArpBase = NULL;          /* Library Bases */
struct IntuitionBase *IntuitionBase = NULL;    /* from ArpBase */
struct GfxBase       *GfxBase = NULL;          /* from ArpBase */
struct IconBase      *IconBase = NULL;         /* Opened normally */

struct MPort         *M = NULL;                /* Port & data from AMenu */
struct MsgPort       *WBReplyPort = NULL;      /* WB processes replies */
struct Process       *MyProc;                  /* This Process */

BPTR   WorkDirLock = NULL, OrigDirLock = NULL; /* Directory Locks */
int    WBMenus, WBProcesses=0;                 /* Counts of things */


extern BOOL   StartMonitor();
extern void   Monitor(),FinishMonitor();
extern void   WBFree(), Warn(char *);


DB( BPTR   DBWindow = NULL; )     /* Debuging Output Window - Arp Closes */

/*------------------------------------------------*/

struct IntuiText     /* Exit while WB Processes still running requester */
  WBOpen[] = {
    { 3,1,JAM1,142,4,NULL, (UBYTE*)"WARNING!!", &WBOpen[1] },
    { 0,1,JAM1, 7,12,NULL, (UBYTE*)"A WorkBench program started by AMenu may", &WBOpen[2] },
    { 0,1,JAM1, 7,20,NULL, (UBYTE*)"still be open.  This can cause a crash if", &WBOpen[3] },
    { 0,1,JAM1, 7,28,NULL, (UBYTE*)"the program finishes after AMenu.", &WBOpen[4] },
    { 3,1,JAM1,24,36,NULL, (UBYTE*)"Do you REALLY want to quit now?", NULL },
  },
  TrueMsg  = { 0,1,JAM2, 7,3 ,NULL, (UBYTE*)"QUIT", NULL },
  FalseMsg = { 0,1,JAM2, 7,3 ,NULL, (UBYTE*)"Cancel", NULL };


void
QuitHandler(Code)
  short Code;
  /* return error to AMenu during initialization */
{
  if( M ) {
    M->ErrorCode = Code;
    Signal(M->Parent, 1 << M->ParentSig);  /* Signal Parent */
    Wait(SIGBREAKF_CTRL_C);                /* Wait for parent removal */
    Signal(M->Parent, 1 << M->ParentSig);  /* Final Signal */
  }

  if( WBReplyPort )  DeletePort( WBReplyPort );
  if( OrigDirLock )  CurrentDir( OrigDirLock );
  if( WorkDirLock )  UnLock( WorkDirLock );
  if( IconBase )     CloseLibrary( (struct Library *)IconBase );

  if( ArpBase ) {
    DB( if(DBWindow) FPrintf(DBWindow, "Handler Quit -- %d\n", Code); )
    DB( Delay(600); )
    ArpExit(20+Code,0);     /* OK as no true startup code used by handler */
  } else
    Exit(20+Code);
}


static struct Menu *
SearchWBMenus()
/*   Search the WB menus for either last menu or menu before AMenu
** This Routine also determines the number of WBMenus to determine
** if we recieve a WB menu or AMenu selection.
*/
{
  register struct Menu *Menu;
  for( Menu = M->WBWindow->MenuStrip, WBMenus=1;
         Menu->NextMenu && Menu->NextMenu != M->AMenu;
           Menu = Menu->NextMenu, WBMenus++ );
  return( Menu );
}


BOOL
AddMenuStrip()
/* add personalized menus to menustrip -- return true if menus added */
{
  register struct Menu  *Menu, *MenuStrip;
  ULONG ILock;
  BOOL Added;  /* did we attach the menus or were thay in place? */

  ILock = LockIBase(NULL);
  Menu = SearchWBMenus();
  MenuStrip = M->WBWindow->MenuStrip;
  if( Added = !Menu->NextMenu ) {  /* insure AMenu is not already attached */
    ClearMenuStrip(M->WBWindow);
    Menu->NextMenu = M->AMenu;
    SetMenuStrip(M->WBWindow, MenuStrip);
  }
  UnlockIBase(ILock);
  return Added;   /* return TRUE if we added the menus */
}


void
DelMenuStrip()
/* remove our personalized menus from menustrip */
{
  register struct Menu *Menu, *MenuStrip;
  ULONG ILock;

  ILock = LockIBase(0L);
  Menu = SearchWBMenus();
  MenuStrip = M->WBWindow->MenuStrip;
  if( Menu->NextMenu ) {         /* insure AMenu is not already attached */
    ClearMenuStrip(M->WBWindow);
    Menu->NextMenu = NULL;
    SetMenuStrip(M->WBWindow, MenuStrip);
  }
  UnlockIBase(ILock);
}


/* main program - initialize and start up monitor */
void
main() {

    /* find data set up by parent */
  M = (struct MPort *)FindPort(AMENU_PORT);

    /* Open Libraries */
  ArpBase  = (struct ArpBase *)  OpenLibrary("arp.library",0L);
  IconBase = (struct IconBase *) OpenLibrary("icon.library",0L);
  if( !ArpBase || !IconBase )
    QuitHandler(ERR_LIB);
   /* retrieve other library bases from Arp */
  IntuitionBase = (struct IntuitionBase *) ArpBase->IntuiBase;
  GfxBase       = (struct GfxBase *)       ArpBase->GfxBase;

    /* Check Handler */
  if( !M || M->Handler ) { /* MPort dosn't exist or Handler already running */
    Printf("%s is not an executable\n", AMENU_HANDLER);
    ArpExit(20+ERR_MPORT, 0);    /* parent process not running */
  }

#ifdef DBUG
  if( !(DBWindow = ArpOpen(DBConsole, MODE_NEWFILE) ) ) {
     Warn("Can't open DBWindow!");
     QuitHandler(ERR_MON);
  }
#endif


    /* Initialization */
  DB( FPrintf(DBWindow, "Initializing\n"); )
  M->Handler = FindTask(NULL);
  MyProc = (struct Process *)M->Handler;
  MyProc->pr_ConsoleTask = NULL;       /* no console */
  MyProc->pr_CLI         = NULL;       /* not CLI */
  MyProc->pr_WindowPtr   = (APTR)-1;   /* disable requesters for FindIt() */

    /* set Current Directory */
  DB( FPrintf(DBWindow, "Locking Directory `%s'\n", M->Directory); )
  if( !(WorkDirLock = Lock( M->Directory, ACCESS_READ )) ) {
    DB( FPrintf(DBWindow, "Lock Failed (%ld)\n", IoErr()); )
    QuitHandler(ERR_DIR);
  }
  OrigDirLock = CurrentDir( WorkDirLock );   /* save the old lock */

    /* set up Monitor */
  DB( FPrintf(DBWindow, "Starting Monitor\n"); )
  if( !StartMonitor())
    QuitHandler(ERR_MON);

    /* Reply port for WB Processes */
  if( !(WBReplyPort = CreatePort(AMENU_WBPORT, 0)) )
    QuitHandler(ERR_REPLYPORT);

    /* Initialization Complete */
  DB( FPrintf(DBWindow, "Signaling Parent\n"); )
  M->ErrorCode = ERR_OK;
  Signal(M->Parent, 1 << M->ParentSig);

    /* Add New Menus */
  DB( FPrintf(DBWindow, "Adding Menus\n"); )
  AddMenuStrip();   /* ignore return */

  DB( FPrintf(DBWindow, "Monitoring\n"); )
restart:
  Monitor();

    /* see if we can leave gracefully */
    /* we don't want to terminate and then have a WB reply message */
  DB( FPrintf(DBWindow, "Attempting to Exit\n"); )
  if( (WBProcesses > 0) &&
        !AutoRequest(NULL, WBOpen, &TrueMsg, &FalseMsg,0,0,370,80) ) {
    M->ErrorCode = ERR_WBOPEN;
    Signal(M->Parent, 1 << M->ParentSig);
    goto restart;
  }

    /* clean everything up */
  DB( FPrintf(DBWindow, "Exit cleanup\n"); )
  M->ErrorCode = ERR_OK;
  FinishMonitor();
  DelMenuStrip();
  CloseLibrary((struct Library *)IconBase);
  UnLock( CurrentDir( OrigDirLock ) );   /* return to original directory */

  DB( FPrintf(DBWindow, "Final Pause\n"); Delay(600); )
  Forbid();               /* Disable Task switiching until we are done */

  { register struct Message *Msg;
    while( Msg=GetMsg(WBReplyPort) )
      WBFree(Msg);
    DeletePort(WBReplyPort);
  }

    /* signal parent that we are done */
  Signal(M->Parent, 1 << M->ParentSig);
  ArpExit(0,0);
}
