/**
 * Scout - The Amiga System Monitor
 *
 *------------------------------------------------------------------
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * You must not use this source code to gain profit of any kind!
 *
 *------------------------------------------------------------------
 *
 * @author Andreas Gelhausen
 * @author Richard Körber <rkoerber@gmx.de>
 */



#include "system_headers.h"

int  asscnt;

static APTR AssPool = NULL;

__asm __saveds LONG asslist_dspfunc(register __a2 char **array, register __a1 struct AssEntry *assentry, register __a0 struct Hook *hook)
{
   if (assentry) {
      *array++ = assentry->ass_address;
      *array++ = assentry->ass_name;
      *array++ = assentry->ass_path;
      *array   = NULL;
   } else {
      *array++ = ESC "bAddress";
      *array++ = ESC "bName";
      *array++ = ESC "bPath";
      *array   = NULL;
   }
   return(0);
}

struct Hook asslist_dsphook = {
 {NULL, NULL},
 (ULONG (* )())asslist_dspfunc,
 NULL, NULL
};

__asm __saveds LONG asslist_cmpnamefunc (register __a1 struct AssEntry *ae1, register __a2 struct AssEntry *ae2)
{
    LONG result;

    result = strcmpi(ae1->ass_name, ae2->ass_name);
    if (result == 0) result = ae2->ass_type - ae1->ass_type;
    if (result == 0) result = strcmpi(ae1->ass_realpath, ae2->ass_realpath);

    return result;
}

struct Hook asslist_cmpnamehook = {
 {NULL, NULL},
 (ULONG (* )())asslist_cmpnamefunc,
 NULL, NULL
};

__asm __saveds LONG asslist_cmppathfunc (register __a1 struct AssEntry *ae1, register __a2 struct AssEntry *ae2)
{
    LONG result;

    result = strcmpi(ae1->ass_realpath, ae2->ass_realpath);
    if (result == 0) result = strcmpi(ae1->ass_name, ae2->ass_name);

    return result;
}

struct Hook asslist_cmppathhook = {
 {NULL, NULL},
 (ULONG (* )())asslist_cmppathfunc,
 NULL, NULL
};

void FreeAssigns (void)
{
    MyFreePoolStructs(&AssPool, asstext, NULL, asslist);
}

int GetAssigns (struct AssEntry **first) {
   struct   AssEntry       *assentry,*previous = NULL;
   struct   DosList        *dev;
   struct   AssignList     *list;
   struct   FileInfoBlock  *infoBlock;

   int asscnt = 0;
   *first = 0;

   if (!AssPool) AssPool = tbCreatePool(MEMF_CLEAR, 4096, 4096);

   dev = DOSLIST;

   if (clientstate) {
      char  tmpbuffer[256];

      if (SendDaemon ("GetAssList")) {
         while ((assentry = tbAllocPooled(AssPool, sizeof(struct AssEntry))) \
           && (ReceiveDecodedEntry ((UBYTE *) assentry, sizeof (struct AssEntry) - 4)) \
           && (sgets (client_socket, tmpbuffer, 256))) {

            if (assentry->ass_path = tbAllocPooled(AssPool, strlen (tmpbuffer) + 1)) {
               strncpy (assentry->ass_path, tmpbuffer, strlen (tmpbuffer) + 1);
            }

            IsHex (assentry->ass_address, (long *) &assentry->ass_adr);

            if (! *first)
               *first = assentry;
            if (previous)
               previous->ass_next = assentry;

            asscnt++;
            previous = assentry;
         }
      }
   } else {
      if (infoBlock = AllocDosObject(DOS_FIB, TAG_DONE)) {
         while ((dev != 0) && (assentry = tbAllocPooled(AssPool, sizeof (struct AssEntry)))) {
            if ((dev->dol_Type == DLT_DIRECTORY) || (dev->dol_Type == DLT_LATE) || (dev->dol_Type == DLT_NONBINDING)) {
               if (! *first)
                  *first = assentry;
               if (previous)
                  previous->ass_next = assentry;
   
               assentry->ass_adr = (char *) dev;
               _sprintf (assentry->ass_address, "$%08lx", dev);
               b2cstrn(dev->dol_Name, assentry->ass_name, 20);
   
               if (Examine (dev->dol_Lock, infoBlock)) {
                  tmpstr[0] = '\0';
                  NameFromLock (dev->dol_Lock, tmpstr, PATHLENGTH);
   
                  if ((dev->dol_Type == DLT_DIRECTORY) && (assentry->ass_path = tbAllocPooled(AssPool, strlen (tmpstr) + 1)) && (assentry->ass_realpath = tbAllocPooled (AssPool, strlen (tmpstr) + 1))) {
                     strcpy (assentry->ass_path, tmpstr);
                     strcpy (assentry->ass_realpath, tmpstr);
                  } else if ((dev->dol_Type == DLT_LATE) && (assentry->ass_path = tbAllocPooled (AssPool, strlen (dev->dol_misc.dol_assign.dol_AssignName) + 3)) && (assentry->ass_realpath = tbAllocPooled (AssPool, strlen (dev->dol_misc.dol_assign.dol_AssignName) + 3))) {
                     _sprintf (assentry->ass_path, "<%s>", dev->dol_misc.dol_assign.dol_AssignName);
                     strcpy(assentry->ass_realpath, dev->dol_misc.dol_assign.dol_AssignName);
                  } else if ((dev->dol_Type == DLT_NONBINDING) && (assentry->ass_path = tbAllocPooled (AssPool, strlen (dev->dol_misc.dol_assign.dol_AssignName) + 3)) && (assentry->ass_realpath = tbAllocPooled (AssPool, strlen (dev->dol_misc.dol_assign.dol_AssignName) + 3))) {
                     _sprintf (assentry->ass_path, "[%s]", dev->dol_misc.dol_assign.dol_AssignName);
                     strcpy(assentry->ass_realpath, dev->dol_misc.dol_assign.dol_AssignName);
                  }
                  assentry->ass_type = dev->dol_Type;
               }
               asscnt++;
   
               previous = assentry;
               list = dev->dol_misc.dol_assign.dol_List;
   
               while ((list) && (assentry = tbAllocPooled (AssPool, sizeof(struct AssEntry)))) {
                  if (previous)
                     previous->ass_next = assentry;
   
                  assentry->ass_adr = (char *) (list->al_Lock);
                  _sprintf (assentry->ass_address, "$%08lx", BADDR(list->al_Lock));
                  b2cstr(dev->dol_Name, assentry->ass_name);
   
                  if (Examine (list->al_Lock, infoBlock)) {
                     tmpstr[0] = '\0';
                     NameFromLock (list->al_Lock, tmpstr, PATHLENGTH);
   
                     if ((dev->dol_Type == DLT_DIRECTORY) && (assentry->ass_path = tbAllocPooled(AssPool, strlen (tmpstr) + 7)) && (assentry->ass_realpath = tbAllocPooled (AssPool, strlen (tmpstr) + 7))) {
                        _sprintf (assentry->ass_path, " +  %s", tmpstr);
                        strcpy(assentry->ass_realpath, tmpstr);
                     }
                  }
                  asscnt++;
   
                  previous = assentry;
                  list = (struct AssignList *) (list->al_Next);
               }
            }
            dev = (struct DosList *)BADDR(dev->dol_Next);
         }
         FreeDosObject(DOS_FIB, infoBlock);
//    infoBlock = NULL;
      }
   }
   return (asscnt);
}

void PrintAssigns (char *filename) {
   int   i=1;
   BPTR  handle;
   struct AssEntry *entryp = NULL;

   handle = HandlePrintStart (filename);
   if ((handle) && (PrintOneLine (handle, "\n  Address  Name       Path\n\n"))) {
      if (! WI_Assigns) {
         i = GetAssigns (&entryp);
      }
      if (i) {
         for (i=0;;i++) {
            if (WI_Assigns)
               DoMethod (asslist,MUIM_List_GetEntry,i,&entryp);
            if (!entryp) break;

            _sprintf (tmpstr2, " %9s %-10s %s\n", entryp->ass_address, entryp->ass_name, entryp->ass_path);
            if (! (PrintOneLine (handle, tmpstr2)))
               break;

            if (! WI_Assigns)
               entryp = entryp->ass_next;
         }
      }
   }
   HandlePrintStop();
}

void ShowAssigns (void) {
   struct AssEntry *ass;

   ApplicationSleep();
   set (asslist,MUIA_List_Quiet,TRUE);
   set (asslist,MUIA_List_CompareHook,asslist_cmphook_ptr);
   set (BT_AssRemove, MUIA_Disabled, TRUE);

   FreeAssigns();
   asscnt = GetAssigns (&ass);

   while (ass) {
      InsertSortedEntry (asslist, (APTR *) &ass);
      ass = ass->ass_next;
   }

   SetCountText (asscount, asscnt);
   AwakeApplication();
   set (asslist,MUIA_List_Quiet,FALSE);
}

void SendAssList (void) {
   struct AssEntry *ass;

   FreeAssigns();
   asscnt = GetAssigns (&ass);

   while (ass) {
      SendEncodedEntry ((UBYTE *) ass, sizeof (struct AssEntry) - 4);
      SendClient ((UBYTE *) ass->ass_path);
      ass = ass->ass_next;
   }
   FreeAssigns();
}


APTR WI_Assigns, asslist, asstext, asscount, CY_AssSort;
int  asssortstate = 0;
APTR BT_AssUpdate, BT_AssPrint, BT_AssRemove, BT_AssExit;

APTR AssSortList[] = {
   &list_cmpnormalhook,
   &asslist_cmpnamehook,
   &list_cmpaddresshook,
   &asslist_cmppathhook,
   NULL
};

static const char *CYA_AssSortText[] = {
   "normal",
   "name",
   "address",
   "path",
   NULL
};

char assigns_title[WINDOWTITLELEN];

void AssignsWindow (BOOL state) {
   if (state) {
      if (WI_Assigns) {
         ShowAssigns();
      } else {
         WI_Assigns = WindowObject,
         MUIA_Window_Title, MyGetWindowTitle (assigns_title, "ASSIGNS"),
         MUIA_HelpNode, AssignsText,
         MUIA_Window_ID, MakeListID('A','S','S','I'),
         WindowContents, VGroup,
            Child, asslist = MyListviewObject ("COL=0 DELTA=8,COL=1 DELTA=8,COL=2",&asslist_dsphook),
            Child, MyBelowSortedListview (&asstext, &asscount, &CY_AssSort, CYA_AssSortText, asssortstate),
            Child, MyVSpace(2),
            Child, HGroup, MUIA_Group_SameSize, TRUE,
               Child, BT_AssUpdate  = KeyButtonA (UpdateText,ID_ASSUPDATE),
               Child, BT_AssPrint   = KeyButtonA (PrintText ,ID_ASSPRINT),
               Child, BT_AssRemove  = KeyButtonA (RemoveText,ID_ASSREMOVE),
               Child, BT_AssExit    = KeyButtonA (ExitText  ,ID_ASSEXIT),
            End,
         End, End;

         DoMethod (AP_Scout,OM_ADDMEMBER,WI_Assigns);
         DoMethod (WI_Assigns,MUIM_Window_SetCycleChain,asslist,CY_AssSort,BT_AssUpdate,BT_AssPrint,BT_AssRemove,BT_AssExit,NULL);
         DoMethod (CY_AssSort, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, AP_Scout, 2, MUIM_Application_ReturnID, ID_ASSSORT);

         SetCloseRequest (WI_Assigns,ID_ASSEXIT);
         SetListActive (asslist,ID_ASSLV_ACTIVE);

         ShowAssigns();

         SetWindowOpen (WI_Assigns,asslist,ID_ASSEXIT);
      }
   } else if ((! state) && (WI_Assigns)) {
      SetWindowClose (WI_Assigns,TRUE);

      FreeAssigns();

      DoMethod (AP_Scout,OM_REMMEMBER,WI_Assigns);
      MUI_DisposeObject (WI_Assigns);
      WI_Assigns = NULL;
      asslist = NULL;
   }
}

