#include "ToolManager.h"

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

/* Structures for icon */
extern struct DiskObject MyIcon;
static struct AppIcon *MyAppIcon;

/* Name of the message port & icon */
static char *MyName="ToolManager";

/* Tags for System() */
extern struct TagItem MyTags[];
#define SYSTAGS_IN  0
#define SYSTAGS_OUT 1

/* miscellaneous */
static struct AppMenuItem *MyAppMenuItem;

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

 fl=CurrentDir(wbarg->sm_ArgList->wa_Lock); /* Goto a valid directory */
 startup();                                 /* common startup code */
 CurrentDir(fl);                            /* Go back to old directory */
                                            /* Process WB startup parameters */
 WBAddToolNode(&wbarg->sm_ArgList[1],wbarg->sm_NumArgs-1);
 mainloop();                                /* Go into main loop */
}

/* CLI main entry point */
void main(int argc, char **argv)
{
 int i;
 BPTR fl;

 startup();           /* common startup code */
 fl=CurrentDir(NULL); /* Get current directory lock */
                      /* Process CLI startup parameters */
 for (i=1; i<argc; i++) AddToolNode(fl,argv[i],NULL);
 CurrentDir(fl);      /* Go back to old directory */
 mainloop();          /* Go into main loop */
}

/* Buffer length for one config file line */
#define BUFLEN 100

/* Handle common startup operations */
void startup(void)
{
 BPTR fl;
 FILE *fh;                /* Filehandle for config file */
 char ConfigLine[BUFLEN]; /* Buffer for one config file line */

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

 Forbid();                     /* Is "ToolManager" already running? */
 MyMP=FindPort(MyName);
 Permit();
 if (MyMP)
  {                            /* Yes, exit gracefully */
   puts("ToolManager already running!");
   exit(5);
  }

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

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

 if (!(GadToolsBase=OpenLibrary("gadtools.library",0)))
  cleanup(3);

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

 /* Notify Workbench about icon */
 if (!(MyAppIcon=AddAppIcon(NULL,NULL,MyName,MyMP,NULL,&MyIcon,NULL)))
  cleanup(5);

 /* Notify Workbench about special menu item. If this item is selected,
    the program will quit */
 if (!(MyAppMenuItem=AddAppMenuItem(NULL,NULL,"Quit ToolManager",MyMP,NULL)))
  cleanup(6);

 NewList(&ToolList);  /* Initialize tool list */
 fl=CurrentDir(NULL); /* Get the current directory */

 if (fh=fopen(ConfigName,"r")) /* Scan config file */
  {
   while (!feof(fh)) /* if not end of file, read one line into buffer */
    if (fgets(ConfigLine,BUFLEN,fh) && (strlen(ConfigLine)>1))
     {
      char *tp;

      ConfigLine[strlen(ConfigLine)-1]='\0'; /* Strip newline */
      if (tp=strchr(ConfigLine,';'))         /* scan config line */
       {
        *tp='\0';                        /* Menu entry ; real program name */
        AddToolNode(fl,ConfigLine,++tp);
       }
      else
       AddToolNode(fl,ConfigLine,NULL);  /* Menu entry == real program name */
     }
   fclose(fh);  /* close config file */
  }
 CurrentDir(fl); /* go back to old directory */
}

/* The main processing loop */
void mainloop(void)
{
 BOOL end=TRUE;                  /* Flag for main loop */
 BOOL windowopen=FALSE;          /* Flag for status window */
 ULONG sigs,bsigs,psigs,wsigs;   /* Buffers for signals */

 bsigs=SIGBREAKF_CTRL_C|         /* break signals */
       SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F;
 psigs=1L<<MyMP->mp_SigBit;      /* port signal */
 sigs=bsigs|psigs;               /* merge signals */

 while (end)                     /* main loop */
  {
   struct AppMessage *msg;       /* pointer to received message */
   ULONG gotsigs;                /* received signals */

   gotsigs=Wait(sigs);           /* Wait for specified signals */

   if (gotsigs&bsigs)            /* Got break signals? */
    end=FALSE;                   /* Yes, quit program */

   if (gotsigs&psigs)            /* Message arrived at message port? */
    while (msg=GetMsg(MyMP))     /* Yes, empty message queue */
     {
      switch(msg->am_Type)       /* Switch between message types */
       {
        case MTYPE_APPWINDOW:    /* Window action */
        case MTYPE_APPICON:      /* Icon action */
         if (msg->am_NumArgs==0) /* Did the user double click my icon? */
          {                      /* Yes! If window not open, open it */
           if ((!windowopen) && (wsigs=OpenStatusWindow()))
            {
             sigs|=wsigs;        /* Merge with other signals */
             windowopen=TRUE;    /* Window is open */
            }
          }
         else                    /* User dropped an icon on my icon */
          {                      /* Add Workbench parameters to tool list */
           if (!WBAddToolNode(msg->am_ArgList,msg->am_NumArgs))
            DisplayBeep(NULL);
           if (windowopen)       /* Refresh status window if open */
            RefreshStatusWindow();
          }
         break;

        case MTYPE_APPMENUITEM:  /* Menu action */
         if (msg->am_ID==NULL)   /* Special menu item selected? */
          end=FALSE;             /* Yes, quit program */
         else                    /* No, scan list for selected tool */
          {
           struct ToolNode *tn;

           for (tn=GetHead(&ToolList); tn; tn=GetSucc(tn))
            if (tn->tn_ID==msg->am_ID)
             {                                /* Corresponding tool found */
              BPTR fl,dfh;                    /* AmigaDOS Filehandles */
              char *cp;

              fl=CurrentDir(tn->tn_DirLock);  /* Change to tool's directory */
              dfh=Open("NIL:",MODE_NEWFILE);  /* Open dummy files for */
              MyTags[SYSTAGS_IN].ti_Data=dfh; /* program I/O */
              dfh=Open("NIL:",MODE_NEWFILE);
              MyTags[SYSTAGS_OUT].ti_Data=dfh;
              if (!(cp=tn->tn_RealName))      /* Get tool name */
               cp=tn->tn_Node.ln_Name;
              if (System(cp,MyTags)==-1)      /* Start tool */
                DisplayBeep(NULL);
              CurrentDir(fl);                 /* Change to old directory */
              break;                          /* quit loop */
             }
          }
         break;
       } /* end of switch(msg->am_Type) */

      ReplyMsg(msg); /* Reply message to sender */
     } /* end of while(msg=GetMsg(MyMP)) */

   if (windowopen && (gotsigs&wsigs)) /* If window open, got window signal? */
    if (HandleWindowEvent())          /* Handle window event */
    {                                 /* Window close event? */
     CloseStatusWindow();             /* Yes, close window */
     sigs&=~wsigs;                    /* Remove window signals */
     windowopen=FALSE;                /* Window closed */
    }
  } /* end of main loop */

 /* If window open, close it */
 if (windowopen) CloseStatusWindow();

 /* Exit program */
 cleanup(99);
}

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

 switch(i)
  {
   case 99:
           RemoveTools();
           RemoveAppMenuItem(MyAppMenuItem);
   case  6:RemoveAppIcon(MyAppIcon);
   case  5:RemPort(MyMP);                           /* Remove message port */
           while (msg=GetMsg(MyMP)) ReplyMsg(MyMP); /* Reply all messages */
           DeleteMsgPort(MyMP);
   case  4:CloseLibrary(GadToolsBase);
   case  3:CloseLibrary(IconBase);
   case  2:CloseLibrary(WorkbenchBase);
   case  1:break;
  }

 if (i!=99) exit(i); /* error if i!=99 */
 exit(RETURN_OK);    /* all o.k. */
}
