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

static APTR resimoretext0,resimoretext1,resimoretext2a,resimoretext2b,resimoretext3;

static APTR ResiPool = NULL;

__asm __saveds LONG resilist_dspfunc(register __a2 char **array, register __a1 struct ResiEntry *resientry, register __a0 struct Hook *hook)
{
   if (resientry) {
      *array++ = resientry->rt_address;
      *array++ = resientry->rt_name;
      *array++ = resientry->rt_pri;
      *array++ = resientry->rt_idstring;
      *array   = NULL;
   } else {
      *array++ = ESC "bAddress";
      *array++ = ESC "bln_Name";
      *array++ = ESC "brt_Pri";
      *array++ = ESC "brt_IdString";
      *array   = NULL;
   }
   return(0);
}

struct Hook resilist_dsphook = {
 {NULL, NULL},
 (ULONG (* )())resilist_dspfunc,
 NULL, NULL
};

void FreeResidents (void)
{
    MyFreePoolStructs(&ResiPool, resitext, NULL, resilist);
}

int GetResidents (struct ResiEntry **first) {
   LONG     *resip, resi;
   struct   ResiEntry    *resientry,*previous = NULL;
   struct   ShortList {
      struct   Resident    *sl_Resident;
      struct   ShortList   *sl_Next;
   };
   struct   ShortList   *sl_Actual;

   int resicnt = 0;
   *first = 0;

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

   sl_Actual = (struct ShortList *) SysBase->KickTagPtr;

   if (clientstate) {
      if (SendDaemon ("GetResiList")) {
         while ((resientry = tbAllocPooled(ResiPool, sizeof(struct ResiEntry))) \
           && (ReceiveDecodedEntry ((UBYTE *) resientry, sizeof (struct ResiEntry)))) {
            IsHex (resientry->rt_address, (long *) &resientry->rt_adr);

            if (! *first)
               *first = resientry;
            if (previous)
               previous->rt_next = resientry;

            resicnt++;
            previous = resientry;
         }
      }
   } else {
      while ((sl_Actual) && (sl_Actual->sl_Resident) && (resientry = tbAllocPooled(ResiPool, sizeof(struct ResiEntry)))) {
         if (! *first)
            *first = resientry;
         if (previous)
            previous->rt_next = resientry;

         resientry->rt_adr = sl_Actual->sl_Resident;

         _sprintf (resientry->rt_address, HELL "$%08lx" DUNKEL, sl_Actual->sl_Resident);
         strncpy (resientry->rt_name, nonetest (sl_Actual->sl_Resident->rt_Name), NODENAMELENGTH);
         _sprintf (resientry->rt_pri, "%4ld", sl_Actual->sl_Resident->rt_Pri);
         strncpy (resientry->rt_idstring, nonetest (sl_Actual->sl_Resident->rt_IdString), TEXTLENGTH);

         healstring (resientry->rt_name);
         healstring (resientry->rt_idstring);
         resicnt++;

         previous = resientry;
         sl_Actual = (struct ShortList *) (0x7fffffff & (ULONG) sl_Actual->sl_Next);
      }

      resip = (LONG *) FIRSTRESIDENT;

      while ((resi = *resip) && (resientry = tbAllocPooled(ResiPool, sizeof(struct ResiEntry)))) {
         if (! *first)
            *first = resientry;
         if (previous)
            previous->rt_next = resientry;

         /*HSMOD: must handle the case that has directly jump after each other */
         while (0x80000000 & resi) {
             resip = (long *) (0x7fffffff & resi);
             resi = *resip;
         }
         resientry->rt_adr = (struct Resident *) resi;
         _sprintf (resientry->rt_address, "$%08lx", resi);
         strncpy (resientry->rt_name, nonetest (((struct Resident *) resi)->rt_Name), NODENAMELENGTH);
         _sprintf (resientry->rt_pri, "%4ld", ((struct Resident *) resi)->rt_Pri);
         strncpy (resientry->rt_idstring, nonetest (((struct Resident *) resi)->rt_IdString), TEXTLENGTH);

         healstring (resientry->rt_name);
         healstring (resientry->rt_idstring);
         resicnt++;

         previous = resientry;
         resip += 1; /* plus 4 Bytes */
      }
   }
   return (resicnt);
}

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

   handle = HandlePrintStart (filename);
   if ((handle) && (PrintOneLine (handle, "\n  Address  Name                     Pri IdString\n\n"))) {
      if (! WI_Residents) {
         i = GetResidents (&entryp);
      }
      if (i) {
         for (i=0;;i++) {
            if (WI_Residents)
               DoMethod (resilist,MUIM_List_GetEntry,i,&entryp);
            if (!entryp) break;

            _sprintf (tmpstr2, " $%08lx %-23.23s %4s %s\n", entryp->rt_adr, entryp->rt_name, entryp->rt_pri, entryp->rt_idstring);
            if (! (PrintOneLine (handle, tmpstr2)))
               break;

            if (! WI_Residents)
               entryp = entryp->rt_next;
         }
      }
   }
   HandlePrintStop();
}

void ShowResidents (void) {
   struct ResiEntry *resi;

   ApplicationSleep();
   set (resilist,MUIA_List_Quiet,TRUE);
   set (BT_ResiMore, MUIA_Disabled, TRUE);

   FreeResidents();
   resicnt = GetResidents (&resi);

   while (resi) {
      InsertBottomEntry (resilist, (APTR *) &resi);
      resi = resi->rt_next;
   }

   SetCountText (resicount, resicnt);
   AwakeApplication();
   set (resilist,MUIA_List_Quiet,FALSE);
}

void SendResiList (void) {
   struct   ResiEntry   *resi;

   FreeResidents();
   resicnt = GetResidents (&resi);

   while (resi) {
      SendEncodedEntry ((UBYTE *) resi, sizeof (struct ResiEntry));
      resi = resi->rt_next;
   }
   FreeResidents();
}

void GetResiMore (struct Resident *resi) {
   unsigned char     *title = "RESIDENT: ";
   struct   WinFree  *ptr;

   if (ptr = AllocWinFree()) {
      ptr->wf_Window = (APTR) WindowObject,

//      MUIA_Window_SizeGadget, FALSE,
      MUIA_HelpNode, ResidentsText,
      MUIA_Window_ID, MakeDetailID('.','R','E','S'),
      WindowContents, HGroup,
         Child, VGroup, MUIA_Group_SameWidth, TRUE,
            Child, MyLabel2 ("Name:"),
            Child, MyLabel2 ("Address:\nPri:\nType:\nVersion:"),
            Child, MyLabel2 ("IdString:"),
         End,
         Child, VGroup, MUIA_Group_SameWidth, TRUE,
            Child, resimoretext0 = MyTextObject(),
            Child, HGroup,
               Child, resimoretext1 = MyTextObject(),
               Child, VGroup,
                  Child, MyLabel ("EndSkip:\nInit:"),
                  Child, MyLabel ("Flags:"),
               End,
               Child, VGroup, MUIA_Group_SameWidth, TRUE,
                  Child, resimoretext2a = MyTextObject(),
                  Child, resimoretext2b = KeyButtonF ('b', resi->rt_Flags),
               End,
            End,
            Child, resimoretext3 = MyTextObject(),
         End,
      End, End;

      if (ptr->wf_Window) {
         MySetContents (resimoretext1, ESC "c$%08lx\n%ld\n%s\n%ld", resi, resi->rt_Pri, GetNodeType (resi->rt_Type), resi->rt_Version);
         MySetContents (resimoretext2a, ESC "c$%08lx\n$%08lx", resi->rt_EndSkip, resi->rt_Init);

         HandleFlagsButtonPressed (resimoretext2b, ptr, "(RESIDENT)", "rt_Flags", resi->rt_Flags, (struct LongFlag *) &rtf_flags, NULL, 'b');
         HandleWindowOpen (ptr, title, resi->rt_Name);
         MySetContentsHealed (resimoretext0, resi->rt_Name);
         MySetContentsHealed (resimoretext3, nonetest (resi->rt_IdString));
         HandleWindowClose (ptr);
      }
   }
}


char residents_title[WINDOWTITLELEN];

void ResidentsWindow (BOOL state) {
   if (state) {
      if (WI_Residents) {
         ShowResidents();
      } else {
         WI_Residents = WindowObject,
         MUIA_Window_Title, MyGetWindowTitle (residents_title, "RESIDENTS"),
         MUIA_HelpNode, ResidentsText,
         MUIA_Window_ID, MakeListID('R','E','S','I'),
         WindowContents, VGroup,
            Child, resilist = MyListviewObject ("COL=0 DELTA=8,COL=1 DELTA=8,COL=2 DELTA=8 P=\33r,COL=3",&resilist_dsphook),
            Child, MyBelowListview (&resitext, &resicount),
            Child, MyVSpace(2),
            Child, HGroup, MUIA_Group_SameSize, TRUE,
               Child, BT_ResiUpdate     = KeyButtonA (UpdateText,ID_RESIUPDATE),
               Child, BT_ResiPrint      = KeyButtonA (PrintText ,ID_RESIPRINT),
               Child, BT_ResiMore       = KeyButtonA (MoreText  ,ID_RESIMORE),
               Child, BT_ResiExit       = KeyButtonA (ExitText  ,ID_RESIEXIT),
            End,
         End, End;

         DoMethod (AP_Scout,OM_ADDMEMBER,WI_Residents);
         DoMethod (WI_Residents,MUIM_Window_SetCycleChain,resilist,BT_ResiUpdate,BT_ResiPrint,BT_ResiMore,BT_ResiExit,NULL);

         SetCloseRequest (WI_Residents,ID_RESIEXIT);
         SetListActive (resilist,ID_RESILV_ACTIVE);
         SetListviewDoubleClick (resilist,ID_RESIMORE);

         ShowResidents();

         SetWindowOpen (WI_Residents,resilist,ID_RESIEXIT);
      }
   } else if ((! state) && (WI_Residents)) {
      SetWindowClose (WI_Residents,TRUE);

      FreeResidents();

      DoMethod (AP_Scout,OM_REMMEMBER,WI_Residents);
      MUI_DisposeObject (WI_Residents);
      WI_Residents = NULL;
      resilist = NULL;
   }
}

