/*
***************************************************************************
*
* Datei:
*    RSysTreeHunks.c
*
* Inhalt:
*    short ClickedCloseGadget(void);
*    long OpenTreeWindow(char *name, int hunk);
*    void PrintTree(struct objectid *obj);
*
* Bemerkungen:
*    Routinen zur Anzeige von Verzeichnisbäumen und
*    Hunk-Strukturen ausführbarer Files.
*
* Erstellungsdatum:
*    07-Jul-93    Rolf Böhme
*
* Änderungen:
*    07-Jul-93    Rolf Böhme    Erstellung
*
***************************************************************************
*/

#include "RSysDebug.h"
#include "RSysFunc.h"

struct TextFont *Toggleibm8Font(void);
struct TextFont *tf = NULL;
struct TextAttr tree_ta = {(STRPTR)"ibm.font",8,0,2};

static struct diskhunkentry
{
   struct Node denode;
   char *name;
   char *fullname;
   struct diskhunkentry *next;
};

static struct diskhunkentry *loop, *firstde;

static struct List Tree;

static struct Remember *dekey = NULL;

#define RKEY   ((struct Remember **)&dekey)
#define SIZEDE sizeof(struct diskhunkentry)

#define IS_SET(pos)  (mask&(1L<<(pos)))
#define SET(pos)     (mask|=(1L<<(pos)))
#define UNSET(pos)   (mask&=(~(1L<<(pos))))

#define IDIR       "\303"
#define ILASTDIR   "\300"
#define ISUBDIR    "\304 "
#define ILEVEL     "\263  "

#define ADIR       "+"
#define ALASTDIR   "\\"
#define ASUBDIR    "- "
#define ALEVEL     "|  "

static enum
{
   GD_TreeLV,
   GD_SaveGad,
   GD_KindCY
};

struct Window *TreeWnd = NULL;
struct Gadget *TreeGList = NULL;
struct Gadget *TreeGadgets[3];
UBYTE *TreeWdt = (UBYTE *) NAME " " VERSION " - Directory Tree Lister";
UBYTE *TreeWdt1 = (UBYTE *) NAME " " VERSION " - Hunk Lister";
static UBYTE *KindCY0Labels[]=
{
   (UBYTE *) "Tree",
   (UBYTE *) "Path",
   NULL
};

static ULONG mask = 0L;
int decnt = 0, breakit = FALSE;

   /*
    * makede() erzeugt ein Element einer verketteten Liste, deren
    * Elemente später in ein ListView eingebracht werden. Dabei wird
    * ein Eintrag mit einem vollständigen Dateinamen und einer
    * Baumstrukturdarstellung erzeugt
    */
static struct diskhunkentry *
makede(struct diskhunkentry *last, int depth, char *name, int lastde)
{
   int   i;
   char  fpart[MAXFULLNAME];
   static int max = -1;

   strncpy(fpart, (char *)FilePart((UBYTE *) name),MAXFULLNAME);

   if ((last = (struct diskhunkentry *) AllocRemember(RKEY, SIZEDE,
                                                  MEMF_CLEAR | MEMF_ANY)) &&
       (last->name = (char *)AllocRemember(RKEY, depth * 4 + strlen(fpart) + 1,
                                           MEMF_CLEAR | MEMF_ANY)) &&
       (last->fullname = (char *)AllocRemember(RKEY, strlen(name) + 2,
                                               MEMF_CLEAR | MEMF_ANY)))

   {
      last->next = NULL;
      last->denode.ln_Name = last->name;
      last->denode.ln_Type = 0;

      for (i = depth + 1; i <= max; i++)
         UNSET(i);

      max = depth;

      if (lastde)
         SET(depth);
      else
         UNSET(depth);

      strcpy(last->fullname, name);

      if (depth != 0)
         strcat(last->fullname, "/");

      if (depth == 0)
         strcpy(last->name, name);
      else
      {
         if (depth == 1)
         {
            if(tf)
               strcpy(last->name, (lastde ? ILASTDIR ISUBDIR : IDIR ISUBDIR));
            else
               strcpy(last->name, (lastde ? ALASTDIR ASUBDIR : ADIR ASUBDIR));

            strcat(last->name, fpart);
         }
         else
         {
            if (IS_SET(1))
               strcpy(last->name, "   ");
            else
               strcpy(last->name, (tf ? ILEVEL : ALEVEL) );

            for (i = 2; i < depth; i++)
               if (IS_SET(i))
                  strcat(last->name, "   ");
               else
                  strcat(last->name, (tf ? ILEVEL : ALEVEL));

            if(tf)
               strcat(last->name, (lastde ? ILASTDIR ISUBDIR  : IDIR ISUBDIR ));
            else
               strcat(last->name, (lastde ? ALASTDIR ASUBDIR  : ADIR ASUBDIR ));

            strcat(last->name, fpart);
         }
      }

      InitListView(TreeWnd,TreeGadgets[GD_TreeLV],NULL,UNSETLVPOS);

      AddTail(&Tree, &last->denode);

      InitListView(TreeWnd,TreeGadgets[0],&Tree,decnt);

      decnt++;

      return (last->next);
   }
   else
      ErrorHandle(MEMORY_ERR, ALLOC_FAIL, KILL);

   return (NULL);
}

   /*
    * ClickedCloseGadget() prüft, ob das CloseGadget geklickt
    * worden ist und bietet eine Abfrage an, ob die laufenden
    * Operation abgebrochen werden soll
    */
BOOL
ClickedCloseGadget(void)
{
   register struct IntuiMessage *mess;
   ULONG class;
   BOOL  ret = FALSE;

   while ((mess = (struct IntuiMessage *)
           GT_GetIMsg(TreeWnd->UserPort)) != NULL)
   {
      class = mess->Class;
      GT_ReplyIMsg(mess);

      if ((class == IDCMP_CLOSEWINDOW) &&
          Question(TreeWnd, "Do you want to cancel reading?", YES))
      {
         ret = TRUE;
         breakit = TRUE;
      }
   }

   return (ret);
}

   /*
    * ScanDirs() durchläuft rekursiv eine vorgegebene Directory
    * und baut dabei eine Baumstruktur auf
    */
static void
ScanDirs(char *name, int depth, int lastde)
{
   struct ExAllControl *eac;
   struct ExAllData *EAData,
        *ead,
        *eadtmp;
   int   more;
   BPTR  lock;
   UBYTE newdir[MAXFULLNAME];

   if (ClickedCloseGadget()|| breakit)
      return;

   loop = makede(loop, depth, name, lastde);

   if (NOT(lock = Lock((UBYTE *) name, ACCESS_READ)))
      return;

   if (eac = AllocDosObject(DOS_EXALLCONTROL, NULL))
   {
      eac->eac_LastKey = 0;

      EAData = MyAllocVec((MAXLARGEMEM+1) * sizeof(struct ExAllData),
                          MEMF_ANY | MEMF_CLEAR, NO_KILL);

      if (EAData)
      {
         do
         {
            more = ExAll(lock, EAData, MAXLARGEMEM * sizeof(struct ExAllData),
                         ED_SIZE, eac);

            if ((!more) && (IoErr()!= ERROR_NO_MORE_ENTRIES))
            {
               ErrorHandle(DOS_EXALL_ERR, EXALL_FAIL, NO_KILL);
               break;
            }

            if (eac->eac_Entries == 0)
               continue;

            ead = EAData;

            do
            {
               if (ead->ed_Type > 0)
               {
                  int   lastentry = TRUE;

                  strcpy((char *)newdir, name);

                  for (eadtmp = ead->ed_Next; eadtmp; eadtmp = eadtmp->ed_Next)
                     if (eadtmp->ed_Type > 0)
                     {
                        lastentry = FALSE;
                        break;
                     }

                  if (AddPart(newdir, ead->ed_Name, MAXFULLNAME))
                     ScanDirs((char *)newdir, depth + 1, lastentry);
               }

               ead = ead->ed_Next;
            }
            while (ead);

         }
         while (more);

         MyFreeVec(EAData);
      }

      FreeDosObject(DOS_EXALLCONTROL, eac);
   }
   else
      ErrorHandle(MEMORY_ERR, ALLOC_FAIL, NO_KILL);

   UnLock(lock);

   return;
}

static struct TextFont *
Toggleibm8Font(void)
{
   STATIC BOOL Access = FALSE;
   STATIC struct TextFont *ibm8Font = NULL;

   Access ^= TRUE;

   if(Access)
      ibm8Font = OpenDiskFont(&tree_ta);
   else
      if(ibm8Font)
      {
         CloseFont(ibm8Font);
         ibm8Font = NULL;
      }

   return(ibm8Font);
}

   /*
    * OpenTreeWindow() öffnet das Kontrollfenster zur Ausgabe
    * eines Verzeichnisbaumes
    */
long
OpenTreeWindow(char *name, int hunk)
{
   struct NewGadget ng;
   struct Gadget *g;
   UWORD wleft = 113,
         wtop = 26,
         ww,
         wh;
   int gl[] = {GD_TreeLV};

   ComputeFont(Scr, (UWORD) 463, (UWORD) 143);

   ww = compute((UWORD) 0, FontX, 463);
   wh = compute((UWORD) 0, FontY, 143);

   if ((wleft + ww + OffX + Scr->WBorRight) > Scr->Width)
      wleft = Scr->Width - ww;
   if ((wtop + wh + OffY + Scr->WBorBottom) > Scr->Height)
      wtop = Scr->Height - wh;

   ww = compute((UWORD) (OffX + Scr->WBorRight), FontX, 463);
   wh = compute((UWORD) (OffY + Scr->WBorBottom), FontY, 143);

   CenterWindow(Scr, &wtop, &wleft, ww, wh);

   if (NOT(g = CreateContext(&TreeGList)))
      return (1L);

   ng.ng_LeftEdge = compute(OffX, FontX, 8);
   ng.ng_TopEdge = compute(OffY, FontY, 21);
   ng.ng_Width = compute((UWORD) 0, FontX, 449);
   ng.ng_Height = compute((UWORD) 0, FontY, 116);
   ng.ng_GadgetText = (UBYTE *) name;
   ng.ng_TextAttr = (tf ? &tree_ta : Font);
   ng.ng_GadgetID = GD_TreeLV;
   ng.ng_Flags = PLACETEXT_ABOVE | NG_HIGHLABEL;
   ng.ng_VisualInfo = VisualInfo;

   g = CreateGadget(LISTVIEW_KIND, g, &ng,
                    GTLV_Labels, NULL,
                    GTLV_ReadOnly, (hunk ? TRUE : FALSE),
                    TAG_DONE);

   TreeGadgets[0] = g;
   makelabelvisible(TreeGadgets[0]);

   ng.ng_LeftEdge = compute(OffX, FontX, 368);
   ng.ng_TopEdge = compute(OffY, FontY, 5);
   ng.ng_Width = compute((UWORD) 0, FontX, 89);
   ng.ng_Height = compute((UWORD) 0, FontY, 13);
   ng.ng_GadgetText = NOT(hunk) ? (UBYTE *) "Save Tree" : (UBYTE *) "Save List";
   ng.ng_TextAttr = Font;
   ng.ng_GadgetID = GD_SaveGad;
   ng.ng_Flags = PLACETEXT_IN;

   g = CreateGadget(BUTTON_KIND, g, &ng, TAG_DONE);

   TreeGadgets[1] = g;
   makelabelvisible(TreeGadgets[1]);

   if (NOT(hunk))
   {
      ng.ng_LeftEdge = compute(OffX, FontX, 8);
      ng.ng_Width = compute((UWORD) 0, FontX, 105);
      ng.ng_GadgetText = NULL;
      ng.ng_TextAttr = Font;
      ng.ng_GadgetID = GD_KindCY;
      ng.ng_Flags = 0;

      g = CreateGadget(CYCLE_KIND, g, &ng, GTCY_Labels, &KindCY0Labels[0], TAG_DONE);

      TreeGadgets[2] = g;
   }
   else
   {
      ng.ng_LeftEdge = compute(OffX, FontX, 8);
      ng.ng_Width = compute((UWORD) 0, FontX, 105);
      ng.ng_GadgetText = (UBYTE *)"Load";
      ng.ng_TextAttr = Font;
      ng.ng_GadgetID = GD_KindCY;
      ng.ng_Flags = 0;

      g = CreateGadget(BUTTON_KIND, g, &ng, TAG_DONE);

      TreeGadgets[2] = g;
   }

   if (NOT g)
      return (2L);

   if (NOT(TreeWnd = OpenWindowTags(NULL,
                                    WA_Left, wleft,
                                    WA_Top, wtop,
                                    WA_Width, ww,
                                    WA_Height, wh,
                                    WA_IDCMP, BUTTONIDCMP |
                                    LISTVIEWIDCMP |
                                    IDCMP_MOUSEBUTTONS |
                                    IDCMP_MOUSEMOVE |
                                    IDCMP_CLOSEWINDOW |
                                    IDCMP_VANILLAKEY |
                                    IDCMP_REFRESHWINDOW,
                                    WA_Flags, WFLG_DRAGBAR |
                                    WFLG_DEPTHGADGET |
                                    WFLG_CLOSEGADGET |
                                    WFLG_SMART_REFRESH |
                                    WFLG_ACTIVATE |
                                    WFLG_RMBTRAP,
                                    WA_Gadgets, TreeGList,
                                    WA_Title, hunk ? TreeWdt1 : TreeWdt,
                                    WA_PubScreenFallBack,TRUE,
                                    WA_PubScreen, Scr,
                                    TAG_DONE)))
      return (4L);

   RefreshRastPort(TreeWnd,TreeGadgets,gl, 1);

   return (NULL);
}

   /*
    * ToggleListView() schaltet zwischen der Baum- und der
    * Dateidarstellung der Verzeichniseinträge um
    */
static void
ToggleListView(ULONG code)
{
   struct diskhunkentry *de;
   struct Node *node;

   InitListView(TreeWnd,TreeGadgets[0],NULL,UNSETLVPOS);

   for (node = Tree.lh_Head; node->ln_Succ; node = node->ln_Succ)
   {
      de = (struct diskhunkentry *) node;
      node->ln_Name = ((code == 0L) ? de->name : de->fullname);
   }

   InitListView(TreeWnd,TreeGadgets[0],&Tree,UNSETLVPOS);

   return;
}

   /*
    * PrintTree() öffnet ein Fenster und gibt alle Verzeichnisse eines
    * Verzeichnisobjektes obj in einem ListView aus
    */
void
PrintTree(struct objectid *obj)
{
   struct IntuiMessage *message;
   ULONG class,
         code;
   APTR  object;
   APTR  req;
   struct Node *node;
   int id;

   DPOS;

   Flags.quit_tree = 0;

   tf = Toggleibm8Font();

   NewList(&Tree);

   if (NOT(OpenTreeWindow(obj->fullname, FALSE)))
   {
      if (SysWnd)
         req = LockWindow(SysWnd);

      decnt = 0;
      breakit = FALSE;

      loop = firstde;

      PrintInfo("Scanning Device", SPEAK, 0);

      SetWindowTitles(TreeWnd, (UBYTE *) "<- Cancel reading Tree...",
                      NOSCREENTITLECHANGE);

      EnableGadget(TreeWnd, TreeGadgets[GD_SaveGad], FALSE);
      EnableGadget(TreeWnd, TreeGadgets[GD_KindCY], FALSE);

      ScanDirs(obj->fullname, 0, TRUE);

      SetWindowTitles(TreeWnd, TreeWdt, NOSCREENTITLECHANGE);

      EnableGadget(TreeWnd, TreeGadgets[GD_SaveGad], TRUE);
      EnableGadget(TreeWnd, TreeGadgets[GD_KindCY], TRUE);

      do
      {
         Wait(1L << TreeWnd->UserPort->mp_SigBit);

         while ((message = (struct IntuiMessage *)
                 GT_GetIMsg(TreeWnd->UserPort)) != NULL)
         {
            class = message->Class;
            code = message->Code;
            object = message->IAddress;

            GT_ReplyIMsg(message);

            switch(class)
            {
               case IDCMP_CLOSEWINDOW:
                  Flags.quit_tree = 1;
                  break;

               case IDCMP_GADGETUP:
                  id = ((struct Gadget *)object)->GadgetID;

                  switch(id)
                  {
                     case GD_TreeLV:
                        if(node = GetNode(&Tree, code))
                           DisplayDirectoryInfo(((struct diskhunkentry *) node)->fullname);
                        break;

                     case GD_SaveGad:
                        if (GetFile(TreeWnd,"RAM:","RSys-Tree.DAT","#?.dat",
                                    "Select File for saving treelist","Save"))
                           SaveList(TreeWnd,(char *)_fullpath,
                                    (char *)obj->fullname,&Tree, FALSE);
                        break;

                     case GD_KindCY:
                        ToggleListView(code);
                        break;
                  }
                  break;

               case IDCMP_VANILLAKEY:
                  if((char)code == ESC)
                     Flags.quit_tree = 1;
                  break;
            }
         }
      }
      while (NOT(Flags.quit_tree));

      InitListView(TreeWnd,TreeGadgets[GD_TreeLV],NULL,UNSETLVPOS);

      if (NOT(IsListEmpty(&Tree)))
      {
         NewList(&Tree);
         FreeRemember(RKEY, TRUE);
      }

      CloseASysWindow(&TreeWnd, &TreeGList, NULL);

      if (SysWnd)
      {
         UnlockWindow(req);
         RefreshMainWindowPattern();
         RefreshList(LastID);
      }
   }
   else
      ErrorHandle(WINDOW_ERR, OPEN_FAIL, NO_KILL);

   tf = Toggleibm8Font();

   return;
}

