#define VERSION   "2.8"
#define DATENUM   "(12.12.96)"
#define DATETEXT  "December 12, 1996"
#define COPYRIGHT "Copyright © 1996 John Hughes"

/* THIS VERSION REQUIRES EXEC.LIBRARY V39  ie, WB3.0 */

//#define DEBUG 1

/*********************************************************************************/

#include <exec/types.h>
#include <clib/dos_protos.h>
#include <stdio.h>
#include <stdlib.h>
#include <utility/tagitem.h>    /* TAG_DONE */
#include <dos/exall.h>
#include <clib/alib_protos.h>   /* List */
#include <clib/exec_protos.h>   /* AllocVec() */
#include <string.h>
#include <exec/memory.h>        /* MEMF_PUBLIC */
#include <workbench/startup.h>
#include <dos/dostags.h>
#include <prefs/wbpattern.h>

#include "WBStartup+.h"

#include <exec/execbase.h>

#include <proto/dos.h>
#include <proto/icon.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/commodities.h>
#include <proto/utility.h>
#include <proto/input.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/iffparse.h>
#include <proto/layers.h>

#include "ReadKeyboard.h"
#include "ProgressWindow.h"

#include <proto/wbstart.h>
struct Library *WBStartBase;


char WBSTARTUPPLUS[] = "WBStartup+";

char const version[]="\0$VER: WBStartup+ "VERSION" "DATENUM"\r\n"COPYRIGHT"\r\njohughes@heartland.bradley.edu\r\nThis is the OS3.x version.\0";


void GetFilenames(struct List *filenamequeue, APTR memPool, char *directory, BOOL ShowWindow);
void RunPrograms(struct List *filenamequeue, struct WBStartupPrefs *prefs);
void GetArguments(int argc, char **argv, struct WBStartupPrefs *prefs);
void ShowRequester(STRPTR RequesterText);
void DisplayVars(void);
void FreeIcons(struct List *list);
void RunPrefs(struct WBStartupPrefs *prefs);
struct Node *FindNameNoCase(struct List *list, char *name);
BOOL CheckSemaphore(void);

extern struct ExecBase *SysBase;

struct IntuitionBase *IntuitionBase;
struct Library *CxBase, *IconBase, *UtilityBase, *GadToolsBase, *IFFParseBase, *DataTypesBase, *LayersBase;
struct GfxBase *GfxBase;


main (int argc, char **argv)
{
  struct List filenamequeue;
  struct WBStartupPrefs prefs={NULL,NULL,0,0,0,0,0,0,0,0,0,0,0};
  APTR   filenamePool;

  if (SysBase->LibNode.lib_Version>=39)
  {
    if (IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37))
    {
      if (CxBase = OpenLibrary("commodities.library", 37L))
      {
        if (IconBase = OpenLibrary("icon.library", 36L))
        {
          if (UtilityBase = OpenLibrary("utility.library", 37L))
          {
            if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 37L))
            {
              if (GadToolsBase = OpenLibrary("gadtools.library", 37L))
              {
                if (IFFParseBase = OpenLibrary("iffparse.library", 37L))
                {
                  if (DataTypesBase=OpenLibrary("datatypes.library",39L))
                  {
                    if (LayersBase=OpenLibrary("layers.library",37L))
                    {
                      if (WBStartBase=OpenLibrary("wbstart.library",0L))
                      {
                        if (filenamePool=CreatePool(MEMF_PUBLIC,31,31))  /* Node is 14 bytes, largest filename is 30 */
                        {

                          GetArguments(argc, argv, &prefs);

                          if (!IsQualifierDepressed(&prefs))
                          {
//DisplayVars();

                            if (CheckSemaphore())
                            {

                              NewList(&filenamequeue);

                              GetFilenames(&filenamequeue, filenamePool, prefs.ExecutePath, prefs.ShowWindow);

                              if (!IsListEmpty(&filenamequeue))
                                RunPrograms(&filenamequeue, &prefs);

                              if (prefs.ShowWindow)
                                FreeIcons(&filenamequeue);
                            }
                          }
                          DeletePool(filenamePool);
                        }
                        CloseLibrary(WBStartBase);
                      }
                      CloseLibrary(LayersBase);
                    }
                    CloseLibrary(DataTypesBase);
                  }
                  CloseLibrary(IFFParseBase);
                }
                CloseLibrary((struct Library *)GfxBase);
              }
              CloseLibrary(GadToolsBase);
            }
            CloseLibrary(UtilityBase);
          }
          CloseLibrary(IconBase);
        }
        CloseLibrary(CxBase);
      }
      CloseLibrary((struct Library *)IntuitionBase);
    }
  }
  else
    ShowRequester("This is the Amiga OS 3.0 version of WBStartup+, please install the OS 2.0 version.");

  exit(0);
}

void GetFilenames(struct List *filenamequeue, APTR memPool, char *directory, BOOL ShowWindow)
{
  struct ExAllControl *myexallctrl;  /* The ExAllControl structure */
  struct ExAllData    *eadptr;       /* temp pointer to data structure */
  BPTR mylock;                       /* Lock on the directory */
  int more;                          /* Are there more entries ? */
  struct ExAllData ExAllBuf[20];     /* hold the filenames and types */
  struct Node *node;                 /* hold the filenames and proiority for the List */  /* Is actually WBStartupNode */
  struct DiskObject *diskobj;        /* Pointer to the icon info */
  char *toolstring;                  /* Pointer to a tooltype string */
  char pathname[500];                /* path and filename of the icon */
  char filename[32];                 /* parsed match string 2*length+2=22 */


  if (mylock=Lock(directory,SHARED_LOCK))
  {
    if (myexallctrl=(struct ExAllControl *)AllocDosObjectTags(DOS_EXALLCONTROL,TAG_END))
    {
      myexallctrl->eac_LastKey = 0;
      myexallctrl->eac_Entries = 0;
      myexallctrl->eac_MatchString = NULL;
      myexallctrl->eac_MatchFunc = NULL;

      do   /* go until more==0 */
      {
        more = ExAll(mylock, ExAllBuf, sizeof(ExAllBuf), ED_TYPE, myexallctrl);
        if ((!more) && (IoErr() != ERROR_NO_MORE_ENTRIES))
        {
          ShowRequester("ExAll failed abnormally");//: %ld.", IoErr());
          break;
        }

        if (myexallctrl->eac_Entries)
        {
          eadptr=ExAllBuf;

          while (eadptr)
          {
            if (eadptr->ed_Type < 0)  /* make sure it is a file, not a directory, see end of dos/dosextens.h */
            {
              strcpy(filename, eadptr->ed_Name);

              /* truncate the filename if it is an icon, ie. remove the ".info" */
              if (!Stricmp(filename+strlen(filename)-5,".info"))
                filename[strlen(filename) - 5] = NULL;  /* take the .info off of the string */
              else
                filename[strlen(filename)] = NULL;  /* take the .info off of the string */

              /* See if the file is already in the list */
              if (!FindNameNoCase(filenamequeue,filename))
              {
                if (Stricmp(filename,WBSTARTUPPLUS))  /* Make sure we don't recursively run ourself */
                {
                  strcpy(pathname,directory);
                  AddPart(pathname, filename, 500);
                  if (diskobj=GetDiskObjectNew(pathname))
                  {
                    if ((diskobj->do_Type==WBPROJECT) || (diskobj->do_Type==WBTOOL))  /* Make sure we got an icon that isn't a drawer icon */
                    {
                      if (node=(struct Node *)AllocPooled(memPool,sizeof(struct WBStartupNode)))
                      {
                        if (node->ln_Name=(char *)AllocPooled(memPool, strlen(pathname)+1))
                        {
                          strcpy(node->ln_Name, filename);
                          if (toolstring=FindToolType(diskobj->do_ToolTypes,"STARTPRI"))
                            node->ln_Pri=atoi((char *)toolstring);
                          else
                            node->ln_Pri=0;
                          ((struct WBStartupNode *)node)->StackSize = diskobj->do_StackSize;
                          if (toolstring=FindToolType(diskobj->do_ToolTypes,"TOOLPRI"))
                            ((struct WBStartupNode *)node)->toolpri = strtol(toolstring,NULL,10);
                          else
                            ((struct WBStartupNode *)node)->toolpri = 0;
                          if (toolstring=FindToolType(diskobj->do_ToolTypes,"WAIT"))
                            ((struct WBStartupNode *)node)->wait = strtoul(toolstring,NULL,10);
                          else
                            ((struct WBStartupNode *)node)->wait = 0;
                          if (ShowWindow)
                            ((struct WBStartupNode *)node)->diskobj = diskobj;
                          else
                            FreeDiskObject(diskobj);
                          Enqueue(filenamequeue,node);
                        }
                      }
                    }
                    else
                      FreeDiskObject(diskobj);
                  }
                }
              }
            }
            eadptr=eadptr->ed_Next;
          }
        }

      } while (more);

      FreeDosObject(DOS_EXALLCONTROL,myexallctrl);
    }
    else
      ShowRequester("Not enough memory for ExAllControl.");
    UnLock(mylock);
  }
  else
    ShowRequester("Couldn't lock directory.");
}


void RunPrograms(struct List *filenamequeue, struct WBStartupPrefs *prefs)
{
  struct Node *node;           /* used to go through the filenames queue */
  BPTR fl;
  BPTR olddirlock;
  LONG numprograms=0,currentprogram=0;      // used for the progress bar
  struct ProgressWindowData *windata=NULL;  // this must be initialized to NULL!


  if (prefs->ShowWindow)
  {
    /* Count the # of programs to run */
    for (node=filenamequeue->lh_Head; node->ln_Succ; node = node->ln_Succ)
      numprograms++;
    /* Open and set up the Progress Window */
    windata=CreateProgressWindow(prefs);
  }

  fl=Lock(prefs->ExecutePath,SHARED_LOCK);
  olddirlock=CurrentDir(fl);

  for (node=filenamequeue->lh_Head; node->ln_Succ; node=node->ln_Succ)
  {
    currentprogram++;

    /* Update Progress Bar in Window */
    if (windata)
    {
      UpdateProgressBar(windata->win,currentprogram,numprograms);
      ShowIconImage(windata,((struct WBStartupNode *)node)->diskobj->do_Gadget.GadgetRender);
      DisplayProgramName(windata,node->ln_Name, (prefs->Interactive) ? TRUE : FALSE);
      /* Interactive Mode */
      if (prefs->Interactive)
        if (!InteractiveRunProgram(windata->win))
          continue;  //Skip this icon
    }

    WBStartTags(WBStart_Name, node->ln_Name, WBStart_DirectoryLock, fl, TAG_DONE);

    /* Wait the amount of time specified in the WAIT= tooltype */
    if (((struct WBStartupNode *)node)->wait)
      Delay(((struct WBStartupNode *)node)->wait*50);

  }
  /* Free resources */
  CurrentDir(olddirlock);
  UnLock(fl);

  if (windata)
    CloseProgressWindow(windata);

  /* All OK! */
  return;
}

void GetArguments(int argc, char **argv, struct WBStartupPrefs *prefs)
{
  UBYTE **ttypes;
  UBYTE *toolstring;

  ttypes = ArgArrayInit(argc,argv);
  strcpy(prefs->ExecutePath , ArgString(ttypes,"ENABLEDPATH","SYS:WBStartup/WBStartup (Enabled)"));
  strcpy(prefs->StoragePath , ArgString(ttypes,"DISABLEDPATH","SYS:WBStartup/WBStartup (Disabled)"));
  prefs->ShowWindow = ((FindToolType(ttypes,"PROGRESSWINDOW")) ? TRUE : FALSE);
  prefs->BackgroundFilename[0]=NULL;
  if (toolstring=FindToolType(ttypes,"BACKGROUNDPIC"))
  {
    if (MatchToolValue(toolstring,"WORKBENCH"))
      prefs->BackgroundType=WORKBENCH;
    else if (MatchToolValue(toolstring,"SCREEN"))
      prefs->BackgroundType=SCREEN;
    else if (MatchToolValue(toolstring,"WINDOWS"))
      prefs->BackgroundType=WINDOWS;
    else if (MatchToolValue(toolstring,"NONE"))
      prefs->BackgroundType=NONE;
    else
    {
      strncpy(prefs->BackgroundFilename,toolstring,200);
      prefs->BackgroundFilename[strlen(toolstring)]=NULL;
      prefs->BackgroundType=USERDEFINED;
    }
  }
  else
  {
    prefs->BackgroundType=WINDOWS;
  }
  strcpy(prefs->PrefsPath , ArgString(ttypes,"PREFSPATH","SYS:Prefs/WBStartup+Prefs"));
  strcpy(prefs->PubScreenName , ArgString(ttypes,"PUBSCREEN","Workbench"));
  ArgArrayDone();
}

void ShowRequester(STRPTR RequesterText)
{
  struct EasyStruct myRequestStruct={
    sizeof (struct EasyStruct ),
    0,
    WBSTARTUPPLUS,
    NULL,
    "Ok"};

    myRequestStruct.es_TextFormat=RequesterText;
    EasyRequestArgs(NULL,&myRequestStruct,NULL,NULL);
}

/*
#include <dos/dosextens.h>
#include <dos/var.h>
void DisplayVars(void)
{
  struct Process *pr;
  struct LocalVar *node;
  char   buffer[1000];
  BPTR file;

  if (file=Open("CON:////",MODE_NEWFILE))
  {
    Write(file,"These are vars in WBStartup+:\n",30);
    if (pr = (struct Process *)FindTask(NULL))
    {
      for (node = (struct LocalVar *)pr->pr_LocalVars.mlh_Head; node->lv_Node.ln_Succ; node = (struct LocalVar *)node->lv_Node.ln_Succ)
      {
        sprintf(buffer,"%s\n",node->lv_Node.ln_Name);
        Write(file,buffer,strlen(buffer));
      }
      Delay(50*5);
    }
    Close(file);
  }
}

*/


void FreeIcons(struct List *list)
{
  struct Node *node;

  for (node=list->lh_Head; node->ln_Succ; node=node->ln_Succ)
    FreeDiskObject(((struct WBStartupNode *)node)->diskobj);
}

void RunPrefs(struct WBStartupPrefs *prefs)
{
  struct WBStartupNode node;
  struct List list;
  struct MsgPort *mp;
  struct WBStartupPrefs newprefs;
  char filename[35];

  /* Set up filename list, which only consists of the WBStartup+Prefs program */
  NewList(&list);
  node.diskobj=NULL;
  node.StackSize=4096;
  node.wait=0;
  node.toolpri=0;
  node.node.ln_Name=filename;
  strcpy(filename,FilePart(prefs->PrefsPath));
  AddHead(&list,&node);

  /* Set up New Prefs structure */
  strncpy(newprefs.ExecutePath,prefs->PrefsPath,PathPart(prefs->PrefsPath)-prefs->PrefsPath);
  newprefs.StoragePath[0]=NULL;
  newprefs.ShowWindow=FALSE;
  newprefs.Interactive=FALSE;
  newprefs.PrefsPath[0]=NULL;

  RunPrograms(&list,&newprefs);

  if (mp=CreatePort(WBSTARTUPPLUS,0))
  {
    Wait( (1 << mp->mp_SigBit) | SIGBREAKF_CTRL_C);   /* Wait for WBStartup+Prefs to complete OR a CTRL-C */
    DeletePort(mp);
  }
}

struct Node *FindNameNoCase(struct List *list, char *name)
{
  struct Node *node;
  struct Node *result=NULL;

  for (node=list->lh_Head; node->ln_Succ; node = node->ln_Succ)
    if (!Stricmp(name,node->ln_Name))
    {
      result = node;
      break;
    }
  return(result);
}

BOOL CheckSemaphore(void)
{
  /* RETURN TRUE if this is the 1st time WBStartup+ has been run, OR if the user says it is ok to run it again */
  struct SignalSemaphore *sema;
  char   *name;
  BOOL ContinueRunning = TRUE;

  Forbid();
  if (!FindSemaphore(WBSTARTUPPLUS))
  {
    if (name=(char *)AllocMem(11,MEMF_PUBLIC))
    {
      strcpy(name,WBSTARTUPPLUS);
      if (sema=(struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),MEMF_PUBLIC|MEMF_CLEAR))
      {
        sema->ss_Link.ln_Name=name;
        AddSemaphore(sema);
      }
    }
    Permit();
  }
  else  /* Semaphore was found, meaning WBStartup+ has already been run */
  {
    struct EasyStruct myRequestStruct={
      sizeof (struct EasyStruct ),
      0,
      WBSTARTUPPLUS,
      "Run WBStartup+ again?",
      "Ok|Cancel"};

    ContinueRunning = (BOOL)EasyRequestArgs(NULL,&myRequestStruct,NULL,NULL);

    Permit();
  }

  return(ContinueRunning);
}
