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

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

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

/* ReadArgs() stuff */
static char Template[]="NOICON/S,ICONNAME/K,ICONFILE/K,CONFIG/K,OUTPUT/K,"\
                       "PATH/K,CX_POPUP/S,CX_POPKEY/K,CX_PRIORITY/K/N,"\
                       "NOREQ/S,DELAY/K/N,Tools/M";
static long defcxprio=0;
static struct { /* All entries in this array MUST be longwords! */
               long noicon;
               char *iconname;
               char *iconfile;
               char *config;
               char *output;
               char *path;
               long popup;
               char *popkey;
               long *cxprio;
               long noreq;
               long *delay;
               char **tools;
              } def={FALSE,NULL,NULL,NULL,NULL,NULL,FALSE,NULL,&defcxprio,
                     FALSE,NULL,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)
{
 long i;

 if (SysBase->lib_Version<36)  /* Sanity check */
  {
   puts("You need a Kickstart 2.0 or better to run " DEFPROGNAME "!");
   exit(20);
  }

 /* Open libraries */
 for (i=0; i<20; i++) /* Try it 20 times. Workbench can be sloooowwww.... */
  {
   if (WorkbenchBase=OpenLibrary(WORKBENCH_NAME,36)) break;
   Delay(50);
  }
 if (!WorkbenchBase) 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);

 SetConfigFileName(InternalConfigName); /* Copy config file name */
 return(FALSE);                /* No, start ToolManager */
}

/* Init tool stuff */
static void inittool(void)
{
 NewList(&ToolList);                    /* Initialize tool list */

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

 /* 2. If this item is selected, the status window will open */
 if (!(OTWAppMenuItem=AddAppMenuItemA(1,NULL,"Open TM Window",MyMP,NULL)))
  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;
 ULONG delay=0;

 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 */
  }

 /* 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);

   /*  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. NOREQ Don't show requester */
   ShowQuitReq=!FindToolType(ttp,"NOREQ");

   /*  6. DELAY=<num> Wait "num" seconds before adding the tools */
   if (cp1=FindToolType(ttp,"DELAY")) delay=50*strtol(cp1,&cp2,10);

   /*  7. OUTPUT=<name> CLI Tool Output file */
   if (cp1=FindToolType(ttp,"OUTPUT")) CLIOutputFile=strdup(cp1);

   /*  8. PATH=<name> Global CLI Tool path string */
   if (cp1=FindToolType(ttp,"PATH")) GlobalPath=strdup(cp1);

   /*  9. ICONNAME=<name> Name of the AppIcon */
   if (cp1=FindToolType(ttp,"ICONNAME")) IconName=strdup(cp1);

   /* 10. NOICON Show AppIcon */
   ShowIcon=!FindToolType(ttp,"NOICON");

   /* 11. INTERNALICON Use the internal icon as AppIcon */
   if (ShowIcon && !FindToolType(ttp,"INTERNALICON"))
    MyIcon=dobj; /* Disk icon will be used as AppIcon */
   else
    { /* No icon or the internal icon will be used */
     FreeDiskObject(dobj);
     dobj=NULL;
    }
  }
 CurrentDir(fl);

 /* Set defaults if needed */
 if (!PopUpHotKey) PopUpHotKey=DefaultPopUpHotKey;
 if (!CLIOutputFile) CLIOutputFile=DefaultCLIOutputFile;
 if (!IconName) IconName=MyName;

 /* Init tool stuff */
 if (delay) Delay(delay); /* I hope this fixes ALL mysterious crashes... */
 inittool();

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

 /* Read configuration file */
 fl=CurrentDir(StartupCD);
 ReadConfigFile(ConfigName,TRUE);
 CurrentDir(fl);

 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: " DEFPROGNAME " ",stdout);
   puts(Template);
   puts("\n Parameter          Description                         Default");
   puts(" NOICON             Don't show the program icon         Show icon");
   puts(" ICONNAME <string>  Name of the program icon            " DEFPROGNAME);
   puts(" ICONFILE <file>    File name for the program icon      Internal icon");
   puts(" CONFIG <file>      Name of configuration file          " DEFCONFIGNAME);
   puts(" OUTPUT <file>      Name of the CLI output file         (see docs)");
   puts(" PATH <pathlist>    List of directories for CLI path    No path");
   puts(" CX_POPUP           Open status window after startup    Don't open");
   puts(" CX_POPKEY <key>    Commodities HotKey definition       \"" DEFPOPUPHOTKEY "\"");
   puts(" CX_PRIORITY <num>  Commodities priority                0");
   puts(" NOREQ              Don't show quit requester           Show requester");
   puts(" DELAY <num>        Wait \"num\" seconds before startup   Donīt wait");
   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 */
  }

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

 /* Set internal values according to command line parameters */
 ShowIcon=!def.noicon;
 if (def.iconname) IconName=strdup(def.iconname);
 if (!IconName) IconName=MyName;
 if (ShowIcon && def.iconfile && (dobj=GetDiskObject(def.iconfile)))
  MyIcon=dobj;
 if (def.config) SetConfigFileName(def.config);
 if (def.output) CLIOutputFile=strdup(def.output);
 if (!CLIOutputFile) CLIOutputFile=DefaultCLIOutputFile;
 if (def.path) GlobalPath=strdup(def.path);
 ShowStatusWindow=def.popup;
 if (def.popkey) PopUpHotKey=strdup(def.popkey);
 if (!PopUpHotKey) PopUpHotKey=DefaultPopUpHotKey;
 nb.nb_Pri=*def.cxprio;
 ShowQuitReq=!def.noreq;

 /* I hope this fixes ALL mysterious crashes... */
 if (def.delay) Delay(*def.delay*50);

 /* Init tool stuff */
 inittool();

 /* 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(ConfigName,TRUE); /* 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 (MyAppIcon) RemoveAppIcon(MyAppIcon);
           if (dobj) FreeDiskObject(dobj);
   case  9:RemoveTools();
           if (OTWAppMenuItem) 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. */
}
