/* ClockLoader.c */
/* 
 * StartClock(): - by Jeff Lydiatt, Vancouver, Canada, B.C.
 *
 * Code to load AtermClock, send it a wake up message, and the
 * address of the window where the clock/calendar is to be displayed.
 * DeleteClock(): Send message to AtermClock to shut down, then
 *   unload it's space.
 *
 *    This module uses the AmigaDos LoadSeg and CreateProc functions to
 * load the clock/calendar, AtermClock, from the current directory and to
 * start it as a separate process.  With the way the parameters are set up,
 * AtermClock thinks it has been loaded by WorkBench and by convention waits
 * for a start up message from WorkBench containing some needed parameters.
 * This part of the AtermClock code is handled by an initialization program
 * provided by Aztec that is called before the "main" subroutine.  The loader
 * program first sends the wakeup call together with the WorkBench parameters
 * that are normally provided by WorkBench.  The loader then sends a message
 * giving AtermClock the address of the display window, and waits for an
 * "OK" reply before returning.
 *
 *   The DeleteClock() subroutine sends a message to request AtermClock to
 * wind up, and waits for a reply.  AtermClock does not check the contents
 * of the message, so it doesn't matter what the message content is.  A
 * second "Wait" is needed to capture the "Reply" from AtermClock for the
 * loader's first wakeup message.  The "Reply" is sent by the Aztec-provided
 * exit() code.  When the "Reply" has been received, DeleteClock()
 * frees any resources opened by the loader and returns. 
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/tasks.h>
#include <exec/execbase.h>
#include <intuition/intuition.h>
#include <workbench/startup.h>
#include <functions.h>
#include "Clock.h"
#include "ConsoleIO.h"
 
#define PRIORITY	0
#define STACKSIZE	4096
#define CLOCKNAME	"AtermClock"
#define CCLOCKNAME	"C:AtermClock"

static struct Process *myProcess = NULL;
static struct Process *ClockProc = NULL;
static struct WBStartup *msg = NULL;
static struct ParmMsg *parms = NULL;
static struct Segment *ClockSeg = NULL;
static struct MsgPort *myPort = NULL;    /* Pointer to my private port */
static char *startName = "StartMessage";
static char *parmName  = "Parameter";

   /*------------------------------------------------------------*/
   /*		Cleanup: after Clock is stopped			 */
   /*------------------------------------------------------------*/

static void CleanUp()
{
   if ( ClockSeg != NULL )
      UnLoadSeg( ClockSeg );
   if ( msg != NULL )  { FreeMem( msg, (long)sizeof( struct WBStartup ) );     }
   if ( parms != NULL) { FreeMem( parms, (long)sizeof( struct ParmMsg ) ); }
   if ( myPort != NULL){ DeletePort( myPort ); }
   msg = NULL;
   parms = NULL;
   ClockSeg = NULL;
   myPort = NULL;
}

   /*------------------------------------------------------------*/
   /*		StartClock: as a subtask			 */
   /*------------------------------------------------------------*/

BOOL StartClock( window )
struct Window *window;
{
   register struct WBStartup *wPtr;
   register struct ParmMsg   *pPtr;

   /*-------- See if we have enough scratch memory----------*/

    myProcess = (struct Process *)FindTask( NULL );
    myPort = CreatePort( "ClockPort", NULL );
    msg = (struct WBStartup *) AllocMem(
          (long)sizeof( struct WBStartup ), (long)(MEMF_CLEAR) );
    parms = (struct ParmMsg *)AllocMem(
	    (long)sizeof( struct ParmMsg), (long)(MEMF_CLEAR) );
    if ( myPort == NULL || msg == NULL || parms == NULL )
      {
	PutString( "\x9b33mNote: Insufficent memory to run the clock!\n\x9bm" );
	CleanUp();
	return FALSE;
      }
    wPtr = msg;
    pPtr = parms;

   /*-------- Load the Clock Program --------------*/

   ClockSeg = LoadSeg( CLOCKNAME );
   if ( ClockSeg == NULL )
	ClockSeg = LoadSeg( CCLOCKNAME );
	if ( ClockSeg == NULL )
		{
		PutString( "\x9b33mNote: \"" );
		PutString( CLOCKNAME );
		PutString( "\" Not Found\n\x9bm" );
		CleanUp();
		return FALSE;
		}

    /*------Create a Process for the Clock----------*/

   ClockProc = CreateProc( CLOCKNAME, (long)(PRIORITY),
		ClockSeg, (long)(STACKSIZE) );
   if ( ClockProc == NULL )
     {
	PutString( "\x9b33mCan't start the Clock Process.\n\x9bm" );
	CleanUp();
	return FALSE;
     }

    /*------- Wake Up the Process we Created -----*/

    wPtr->sm_Message.mn_ReplyPort = myPort;
    wPtr->sm_Message.mn_Length = sizeof( struct WBStartup );
    wPtr->sm_Message.mn_Node.ln_Name = startName;
    wPtr->sm_ArgList = NULL;
    wPtr->sm_ToolWindow = NULL;
    PutMsg( ClockProc, wPtr );

    /*------- Now Send the process the address of my window -------*/

    pPtr->mm_Message.mn_ReplyPort = myPort;
    pPtr->mm_Message.mn_Length = sizeof( struct ParmMsg  );
    pPtr->mm_Message.mn_Node.ln_Name = parmName;
    pPtr->windowPtr = window;
    PutMsg( ClockProc, pPtr );

    /* ... and wait for reply to Parm msg received */

    WaitPort( myPort );
    (void) GetMsg( myPort );

    return TRUE;
}

   /*------------------------------------------------------------*/
   /*	Delete the Clock Task.					 */
   /*------------------------------------------------------------*/

void DeleteClock()
{

   if ( ClockProc != NULL )
      {
	if ( parms != NULL )
	   {
		/* Signal the Clock to Stop */
		PutMsg( ClockProc, parms );
		WaitPort( myPort );
		(void) GetMsg( myPort );
	    }

	if ( msg != NULL )
	    {
		/* Wait for the Wakeup Message Reply */ 
		WaitPort( myPort );
		(void) GetMsg( myPort );
	    }
     }
   ClockProc = NULL;
   CleanUp();
}
