/*
 * toolmanager.c   V1.4
 *
 * startup routines
 *
 * (c) 1991 by Stefan Becker
 *
 */
#include "ToolManager.h"

/* Library pointers */
extern struct Library *SysBase,*IntuitionBase,*GfxBase; /* Autoinit Libs */
extern struct Library *GadToolsBase;                    /* Autoinit Libs */
struct Library *WorkbenchBase,*IconBase,*CxBase;

/* Tooltypes "YES" string */
static char YesString[]="YES";

/* ReadArgs() stuff */
static char Template[]=
  "NOICON/S,CONFIG/K,POPUP/S,POPKEY/K,CXPRIO/K/N,NOREQ/S,Tools/M";
static long defcxprio=0;
static struct { /* All entries in this array MUST be longwords! */
               long noicon;
               char *config;
               long popup;
               char *popkey;
               long *cxprio;
               long noreq;
               char **tools;
              } def={FALSE,NULL,FALSE,NULL,&defcxprio,FALSE,NULL};

/* miscellaneous */
extern char InternalConfigName[];
extern struct NewBroker nb;
static struct DiskObject *dobj=NULL;
static struct AppMenuItem *QTMAppMenuItem;
static APTR OldConsoleTask=NULL;

/* Open libraries and other stuff */
static BOOL openstuff(void)
{
 if (SysBase->lib_Version<36)  /* Sanity check */
  {
   puts("You need a Kickstart 2.0 or better to run " DEFPROGNAME "!");
   exit(20);
  }

 /* Open libraries */
 if (!(WorkbenchBase=OpenLibrary(WORKBENCH_NAME,36)))
  cleanup(1);

 if (!(IconBase=OpenLibrary(ICONNAME,0)))
  cleanup(2);

 if (!(CxBase=OpenLibrary("commodities.library",36)))
  cleanup(3);

 Forbid();                     /* Is "ToolManager" already running? */
 MyMP=FindPort(MyName);
 Permit();
 if (MyMP) return(TRUE);       /* Yes, don't start again! */

 if (!(MyMP=CreateMsgPort()))  /* No, create message port */
  cleanup(4);
 MyMP->mp_Node.ln_Pri=0;
 MyMP->mp_Node.ln_Name=MyName; /* Our name */
 AddPort(MyMP);                /* Announce our presence */

 /* Create Commodities Broker port */
 if (!(MyBrokerPort=CreateMsgPort()))
  cleanup(5);
 MyBrokerPort->mp_Node.ln_Pri=0;
 MyBrokerPort->mp_Node.ln_Name="TM Broker Port";
 nb.nb_Port=MyBrokerPort;

 /* Create Broker */
 if (!(MyBroker=CxBroker(&nb,NULL)))
  cleanup(6);
 return(FALSE);                /* No, start ToolManager */
}

/* Init tool stuff */
static void inittool(void)
{
 SetConfigFileName(InternalConfigName); /* Copy config file name */
 NewList(&ToolList);                    /* Initialize tool list */

 /* Notify Workbench about special menu items. */
 /* 1. If this item is selected, the program will quit */
 if (!(QTMAppMenuItem=AddAppMenuItem(0,NULL,"Quit ToolManager",MyMP,TAG_DONE)))
  cleanup(7);

 /* 2. If this item is selected, the status window will open */
 if (!(OTWAppMenuItem=AddAppMenuItem(1,NULL,"Open TM Window",MyMP,TAG_DONE)))
  cleanup(8);
}

/* Send an AppMessage with our parameters to a running ToolManager process */
static void SendParameters(LONG nargs, struct WBArg *arg)
{
 struct MsgPort *sp,*rp;
 struct AppMessage *msg;

 /* Allocate memory for AppMessage */
 if (!(msg=malloc(sizeof(struct AppMessage)))) goto e1;

 /* Create a reply port */
 if (!(rp=CreateMsgPort())) goto e2;

 /* Build AppMessage */
 msg->am_Message.mn_Node.ln_Type=NT_MESSAGE;
 msg->am_Message.mn_Node.ln_Pri=0;
 msg->am_Message.mn_ReplyPort=rp;
 msg->am_Type=MTYPE_APPICON;
 msg->am_NumArgs=nargs;
 msg->am_ArgList=arg;

 Forbid();                     /* Find "ToolManager" message port */
 sp=FindPort(MyName);
 if (sp) PutMsg(sp,(struct Message *) msg); /* Send AppMessage */
 Permit();

 if (sp)
  {                            /* We have send the message */
   WaitPort(rp);               /* Wait on the reply */
   GetMsg(rp);                 /* Remove reply from port */
  }

    DeleteMsgPort(rp);
e2: free(msg);
e1: return;
}

/* Workbench main entry point */
void wbmain(struct WBStartup *wbarg)
{
 BPTR fl;

 if (openstuff())         /* common startup code */
  {                       /* ToolManager already running, send parameters */
   if (wbarg->sm_NumArgs>1)
    SendParameters(wbarg->sm_NumArgs-1,wbarg->sm_ArgList+1);
   cleanup(4);            /* All done */
  }

 inittool();              /* Init tool stuff */

 /* Process WB startup parameters */
 WBAddToolNode(wbarg->sm_ArgList+1,wbarg->sm_NumArgs-1);

 /* Set global startup current directory */
 StartupCD=wbarg->sm_ArgList->wa_Lock;

 /* Get the program icon */
 fl=CurrentDir(StartupCD);
 if (dobj=GetDiskObject(wbarg->sm_ArgList->wa_Name))
  {
   char *cp1,*cp2,**ttp=dobj->do_ToolTypes;

   /* Retreive ToolTypes from icon */
   /* 1. CONFIG=<name> Set configuration file name */
   if (cp1=FindToolType(ttp,"CONFIG")) SetConfigFileName(cp1);

   /* 2. CX_POPKEY=<key> Set commodities HotKey */
   if (cp1=FindToolType(ttp,"CX_POPKEY")) PopUpHotKey=strdup(cp1);
   if (!PopUpHotKey) PopUpHotKey=DefaultPopUpHotKey;

   /* 3. CX_POPUP=YES|NO Show status window on startup */
   if (cp1=FindToolType(ttp,"CX_POPUP"))
    ShowStatusWindow=MatchToolValue(cp1,YesString);

   /* 4. CX_PRIORITY=<num> Set broker priority */
   if (cp1=FindToolType(ttp,"CX_PRIORITY")) nb.nb_Pri=strtol(cp1,&cp2,10);

   /* 5. SHOWREQ=YES|NO Show requester */
   if (cp1=FindToolType(ttp,"SHOWREQ"))
    ShowQuitReq=MatchToolValue(cp1,YesString);

   /* 6. INTERNALICON Use the internal icon as AppIcon */
   if (!FindToolType(ttp,"INTERNALICON")) MyIcon=dobj;

   /* 7. SHOWICON=YES|NO Show AppIcon */
   if (cp1=FindToolType(ttp,"SHOWICON"))
    if (!(ShowIcon=MatchToolValue(cp1,YesString)))
     {
      FreeDiskObject(dobj);
      dobj=NULL;
     }
  }
 CurrentDir(fl);

 /* Read configuration file */
 ReadConfigFile();

 mainloop(); /* Go into main loop */
}

/* CLI main entry point */
void main(int argc, char **argv)
{
 struct RDArgs *rda;
 struct Process *pr=FindTask(NULL);

 /* Help requested? */
 if ((argc>1) && (*argv[1]=='?'))
  { /* Print out usage, but DON'T start ToolManager */
   puts("");
   puts(CopyrightNote);
   fputs("\nUsage: ToolManager ",stdout);
   puts(Template);
   puts("\n Parameter       Description                         Default");
   puts(" NOICON        : Don't show the program icon         Show icon");
   puts(" CONFIG <file> : Name of configuration file          " DEFCONFIGNAME);
   puts(" POPUP         : Open status window after startup    Don't open");
   puts(" POPKEY <key>  : Commodities HotKey definition       \"" DEFPOPUPHOTKEY "\"");
   puts(" CXPRIO <num>  : Commodities priority                0");
   puts(" NOREQ         : Don't display quit requester        Show requester");
   puts(" Tools         : Name of programs to add to the menu");
   puts("\nRequires Kickstart 2.0 or better!");
   exit(0);
  }

 freopen("*","w",stderr);     /* Reopen the stderr for banner line */
 fputs(CopyrightNote,stderr); /* Put out banner line (only in CLI) */
 fputc('\n',stderr);
 fclose(stderr);

 /* Set global startup current directory */
 StartupCD=CurrentDir(NULL);
 CurrentDir(StartupCD);

 if (openstuff())             /* common startup code */
  {                           /* ToolManager already running, send parameters */
   struct WBArg *wa;

   if (argc<2) cleanup(4);    /* No parameters to send */

   /* Allocate memory for WB parameters */
   if (!(wa=malloc(sizeof(struct WBArg)*(argc-1)))) cleanup(4);

   /* Process CLI startup parameters */
   if (rda=ReadArgs(Template,(LONG *) &def,NULL))
    {
     /* Build WBArgs */
     if (argv=def.tools)
      {
       register struct WBArg *wat=wa;

       argc=0;
       while (*argv)              /* Scan list of tools */
        {
         wat->wa_Lock=StartupCD;  /* Copy parameters */
         wat->wa_Name=*argv++;
         wat++;
         argc++;
        }

       if (argc>0) SendParameters(argc,wa); /* Send parameters */
      }
     FreeArgs(rda);           /* Free RDArgs */
    }

   free(wa);                  /* Free WB parameters */
   cleanup(4);                /* All done */
  }

 inittool();                  /* Init tool stuff */

 /* Process CLI startup parameters */
 rda=ReadArgs(Template,(LONG *) &def,NULL);

 /* Set internal values according to command line parameters */
 ShowIcon=!def.noicon;
 if (def.config) SetConfigFileName(def.config);
 ShowStatusWindow=def.popup;
 if (def.popkey) PopUpHotKey=strdup(def.popkey);
 if (!PopUpHotKey) PopUpHotKey=DefaultPopUpHotKey;
 nb.nb_Pri=*def.cxprio;
 ShowQuitReq=!def.noreq;

 /* Add every other parameter as CLI tool */
 if (argv=def.tools)
  {
   struct ConfigBlock *cb;

   if (cb=malloc(sizeof(struct ConfigBlock))) /* Get memory */
    {
     /* Init config block */
     InitConfigBlock(cb);
     cb->cb_Type=TNTYPE_CLI;

     while (*argv)
      {
       strncpy(cb->cb_Alias,*argv++,BUFLEN-1);
       AddToolNode(cb,StartupCD);
      }

     free(cb);
    }
  }

 /* Free RDArgs */
 if (rda) FreeArgs(rda);

 ReadConfigFile();            /* Read configuration file */

 fclose(stdin);               /* Detach from console window */
 fclose(stdout);
 OldConsoleTask=pr->pr_ConsoleTask;
 pr->pr_ConsoleTask=NULL;
 mainloop();                  /* Go into main loop */
}

/* Final cleanup routine */
void cleanup(int i)
{
 register struct Message *msg;

 switch(i)
  {
   case 99:
   case 10:if (ShowIcon) RemoveAppIcon(MyAppIcon);
           if (dobj) FreeDiskObject(dobj);
   case  9:RemoveTools();
           if (!ShowIcon) RemoveAppMenuItem(OTWAppMenuItem);
   case  8:RemoveAppMenuItem(QTMAppMenuItem);
   case  7:DeleteCxObjAll(MyBroker);                /* Remove CX Objects */
   case  6:while (msg=GetMsg(MyBrokerPort)) ReplyMsg(msg);
           DeleteMsgPort(MyBrokerPort);
   case  5:RemPort(MyMP);                           /* Remove message port */
           while (msg=GetMsg(MyMP)) ReplyMsg(msg);  /* Reply all messages */
           DeleteMsgPort(MyMP);
   case  4:CloseLibrary(CxBase);
   case  3:CloseLibrary(IconBase);
   case  2:CloseLibrary(WorkbenchBase);
   case  1:break;
  }

 /* Did we have a console window? */
 if (OldConsoleTask)
  {
   struct Process *pr=FindTask(NULL);

   pr->pr_ConsoleTask=OldConsoleTask; /* Yes, restore old value */
  }

 exit(RETURN_OK);    /* all o.k. */
}
