/**
 * 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 LowMemPool = NULL;

__asm __saveds LONG lowmemorylist_dspfunc(register __a2 char **array, register __a1 struct LowMemoryEntry *lowmemoryentry, register __a0 struct Hook *hook)
{
   if (lowmemoryentry) {
      *array++ = lowmemoryentry->lowmemory_address;
      *array++ = lowmemoryentry->lowmemory_name;
      *array++ = lowmemoryentry->lowmemory_type;
      *array++ = lowmemoryentry->lowmemory_pri;
      *array++ = lowmemoryentry->lowmemory_data;
      *array++ = lowmemoryentry->lowmemory_code;
      *array   = NULL;
   } else {
      *array++ = ESC "bAddress";
      *array++ = ESC "bln_Name";
      *array++ = ESC "bln_Type";
      *array++ = ESC "bln_Pri";
      *array++ = ESC "bis_Data";
      *array++ = ESC "bis_Code";
      *array   = NULL;
   }
   return(0);
}

struct Hook lowmemorylist_dsphook = {
 {NULL, NULL},
 (ULONG (* )())lowmemorylist_dspfunc,
 NULL, NULL
};

void FreeLowMemory (void)
{
    MyFreePoolStructs(&LowMemPool, lowmemorytext, NULL, lowmemorylist);
}

int GetLowMemory (struct LowMemoryEntry **first) {
   struct   Interrupt      *intr;
   struct   LowMemoryEntry *lowmemoryentry,*previous = NULL;
   char     code[FILENAMELENGTH + 1];

   int lowmemorycnt = 0;
   *first = 0;

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

   if (clientstate) {
      if (SendDaemon ("GetLowMemList")) {
         while ((lowmemoryentry = tbAllocPooled(LowMemPool, sizeof(struct LowMemoryEntry))) \
           && (ReceiveDecodedEntry ((UBYTE *) lowmemoryentry, sizeof (struct LowMemoryEntry)))) {
            IsHex (lowmemoryentry->lowmemory_address, (long *) &lowmemoryentry->lowmemory_adr);

            if (! *first)
               *first = lowmemoryentry;
            if (previous)
               previous->lowmemory_next = lowmemoryentry;

            lowmemorycnt++;
            previous = lowmemoryentry;
         }
      }
   } else {
      if (SysBase->LibNode.lib_Version >= 39) {
         if (intr = (struct Interrupt *)SysBase->ex_MemHandlers.mlh_Head) {
            while ((intr->is_Node.ln_Succ != 0) && (lowmemoryentry = tbAllocPooled(LowMemPool, sizeof(struct LowMemoryEntry)))) {
               if (! *first)
                  *first = lowmemoryentry;
               if (previous)
                  previous->lowmemory_next = lowmemoryentry;

               lowmemoryentry->lowmemory_adr = intr;

               code[0] = '\0';
               if (points2ram((APTR) intr->is_Code)) {
                  _sprintf (code, HELL "$%08lx" DUNKEL, intr->is_Code);
               } else {
                  _sprintf (code, "$%08lx", intr->is_Code);
               }
               _sprintf (lowmemoryentry->lowmemory_address, "$%08lx", intr);
               strncpy (lowmemoryentry->lowmemory_name, nonetest (intr->is_Node.ln_Name), 27);
               strcpy (lowmemoryentry->lowmemory_type, GetNodeType (intr->is_Node.ln_Type));
               _sprintf (lowmemoryentry->lowmemory_pri, "%4ld ", intr->is_Node.ln_Pri);
               _sprintf (lowmemoryentry->lowmemory_data, "$%08lx", intr->is_Data);
               strcpy (lowmemoryentry->lowmemory_code, code);
               lowmemorycnt++;

               previous = lowmemoryentry;
               intr = (struct Interrupt *) intr->is_Node.ln_Succ;
            }
         }
      }
   }
   return (lowmemorycnt);
}

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

   handle = HandlePrintStart (filename);
   if ((handle) && (PrintOneLine (handle, "\n  Address  Type       Pri    Data       Code     Name\n\n"))) {
      if (! WI_LowMemory) {
         i = GetLowMemory (&entryp);
      }
      if (i) {
         for (i=0;;i++) {
            if (WI_LowMemory)
               DoMethod (lowmemorylist,MUIM_List_GetEntry,i,&entryp);
            if (!entryp) break;

            if (points2ram ((APTR) (entryp->lowmemory_adr->is_Code)))
               strcpy (tmpstr, entryp->lowmemory_code+2);
            else
               strcpy (tmpstr, entryp->lowmemory_code);

            _sprintf (tmpstr2, " %s %-9s %4s %s %-9.9s %s\n", entryp->lowmemory_address, entryp->lowmemory_type, entryp->lowmemory_pri, entryp->lowmemory_data, tmpstr, entryp->lowmemory_name);
            if (! (PrintOneLine (handle, tmpstr2)))
               break;

            if (! WI_LowMemory)
               entryp = entryp->lowmemory_next;
         }
      }
   }
   HandlePrintStop();
}

void ShowLowMemory (void) {
   struct LowMemoryEntry *lowmemory;

   ApplicationSleep();
   set (lowmemorylist,MUIA_List_Quiet,TRUE);
//*   set (BT_LowMemoryCause, MUIA_Disabled, TRUE);
   set (BT_LowMemoryRemove, MUIA_Disabled, TRUE);
   set (BT_LowMemoryPriority, MUIA_Disabled, TRUE);

   FreeLowMemory();
   lowmemorycnt = GetLowMemory (&lowmemory);

   while (lowmemory) {
      InsertBottomEntry (lowmemorylist, (APTR *) &lowmemory);
      lowmemory = lowmemory->lowmemory_next;
   }

   SetCountText (lowmemorycount, lowmemorycnt);
   AwakeApplication();
   set (lowmemorylist,MUIA_List_Quiet,FALSE);
}

void SendLowMemory (void) {
   struct LowMemoryEntry *lowmemory;

   FreeLowMemory();
   lowmemorycnt = GetLowMemory (&lowmemory);

   while (lowmemory) {
      SendEncodedEntry ((UBYTE *) lowmemory, sizeof (struct LowMemoryEntry));
      lowmemory = lowmemory->lowmemory_next;
   }
   FreeLowMemory();
}


char lowmemory_title[WINDOWTITLELEN];

void LowMemoryWindow (BOOL state) {
   if (state) {
      if (WI_LowMemory) {
         ShowLowMemory();
      } else {
         WI_LowMemory = WindowObject,
         MUIA_Window_Title, MyGetWindowTitle (lowmemory_title, "LOWMEMORY"),
         MUIA_HelpNode, LowMemoryText,
         MUIA_Window_ID, MakeListID('L','O','W','M'),
         WindowContents, VGroup,
            Child, lowmemorylist = MyListviewObject ("COL=0 DELTA=8,COL=1 DELTA=8,COL=2 DELTA=8,COL=3 DELTA=8 P=\33r,COL=4 DELTA=8,COL=5",&lowmemorylist_dsphook),
            Child, MyBelowListview (&lowmemorytext, &lowmemorycount),
            Child, MyVSpace(2),
            Child, HGroup, MUIA_Group_SameSize, TRUE,
               Child, BT_LowMemoryUpdate    = KeyButtonA (UpdateText  ,ID_LOWMEMORYUPDATE),
               Child, BT_LowMemoryPrint     = KeyButtonA (PrintText   ,ID_LOWMEMORYPRINT),
//*               Child, BT_LowMemoryCause     = KeyButtonA (CauseText   ,ID_LOWMEMORYCAUSE),
               Child, BT_LowMemoryRemove    = KeyButtonA (RemoveText  ,ID_LOWMEMORYREMOVE),
               Child, BT_LowMemoryPriority  = KeyButtonA (PriorityText,ID_LOWMEMORYPRIORITY),
               Child, BT_LowMemoryExit      = KeyButtonA (ExitText    ,ID_LOWMEMORYEXIT),
            End,
         End, End;

         DoMethod (AP_Scout,OM_ADDMEMBER,WI_LowMemory);
         DoMethod (WI_LowMemory,MUIM_Window_SetCycleChain,lowmemorylist,BT_LowMemoryUpdate,BT_LowMemoryPrint,BT_LowMemoryRemove,BT_LowMemoryPriority,BT_LowMemoryExit,NULL);

         SetCloseRequest (WI_LowMemory,ID_LOWMEMORYEXIT);
         SetListActive (lowmemorylist,ID_LOWMEMORYLV_ACTIVE);

         ShowLowMemory();

         SetWindowOpen (WI_LowMemory,lowmemorylist,ID_LOWMEMORYEXIT);
      }
   } else if ((! state) && (WI_LowMemory)) {
      SetWindowClose (WI_LowMemory,TRUE);

      FreeLowMemory();

      DoMethod (AP_Scout,OM_REMMEMBER,WI_LowMemory);
      MUI_DisposeObject (WI_LowMemory);
      WI_LowMemory = NULL;
      lowmemorylist = NULL;
   }
}
