/**
 * 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  comcnt;

static APTR ComPool = NULL;

char * GetUCType (LONG uc) {
   char *UCTypeText[] = {
      "SYSTEM","INTERNAL","DISABLED"
   };

   LONG UCType[] = {
      CMD_SYSTEM,CMD_INTERNAL,CMD_DISABLED,0
   };

   int i = 0;

   while (UCType[i]) {
      if (uc == UCType[i]) {
         return (UCTypeText[i]);
      }
      i++;
   }
   return (NULL);
}

__asm __saveds LONG comlist_dspfunc(register __a2 char **array, register __a1 struct CommandEntry *comentry, register __a0 struct Hook *hook)
{
   if (comentry) {
      *array++ = comentry->cm_address;
      *array++ = comentry->cm_name;
      *array++ = comentry->cm_uc;
      *array++ = comentry->cm_lower;
      *array++ = comentry->cm_upper;
      *array++ = comentry->cm_size;
      *array   = NULL;
   } else {
      *array++ = ESC "bAddress";
      *array++ = ESC "bName";
      *array++ = ESC "bUseCount";
      *array++ = ESC "b" ESC "cLower";
      *array++ = ESC "b" ESC "cUpper";
      *array++ = ESC "bSize";
      *array   = NULL;
   }
   return(0);
}

struct Hook comlist_dsphook = {
 {NULL, NULL},
 (ULONG (* )())comlist_dspfunc,
 NULL, NULL
};

void FreeCommands (void)
{
    MyFreePoolStructs(&ComPool, NULL, NULL, comlist);
}

int GetCommands (struct CommandEntry **first) {
   struct   Segment        *segment;
   struct   CommandEntry   *comentry,*previous = NULL;
   long     *seg, size;
   char     *tmp;

   int comcnt = 0;
   *first = 0;

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

   if (clientstate) {
      if (SendDaemon ("GetComList")) {
         while ((comentry = tbAllocPooled(ComPool, sizeof(struct CommandEntry))) \
           && (ReceiveDecodedEntry ((UBYTE *) comentry, sizeof (struct CommandEntry)))) {
            IsHex (comentry->cm_address, (long *) &comentry->cm_adr);

            if (! *first)
               *first = comentry;
            if (previous)
               previous->cm_next = comentry;

            comcnt++;
            previous = comentry;
         }
      }
   } else {
      segment = (struct Segment *) BADDR(DEVINFO->di_NetHand);
      while ((segment) && (comentry = tbAllocPooled(ComPool, sizeof(struct CommandEntry)))) {
         if (! *first)
            *first = comentry;
         if (previous)
            previous->cm_next = comentry;
   
         comentry->cm_adr = (char *) segment;
         _sprintf (comentry->cm_address, "$%08lx", segment);
         strncpy (comentry->cm_name, (char *) &segment->seg_Name + 1, (UBYTE) segment->seg_Name[0]);
   
         if (tmp = GetUCType (segment->seg_UC)) {
            strcpy (comentry->cm_uc, tmp);
   
            strcpy (comentry->cm_lower, ESC "c---");
            strcpy (comentry->cm_upper, ESC "c---");
            strcpy (comentry->cm_size, ESC "c---");
   
            comcnt++;
            previous = comentry;
         } else {
            _sprintf (comentry->cm_uc, "%ld", segment->seg_UC - 1);
   
            seg = BADDR(segment->seg_Seg);
            comcnt++;
            while (seg) {
               _sprintf (comentry->cm_lower, "$%08lx", ((char *) seg) + 4);
               size = *(seg - 1);
               _sprintf (comentry->cm_size, "%ld", size);
               _sprintf (comentry->cm_upper, "$%08lx", ((char *) seg) - 4 + size);
   
               previous = comentry;
               if (seg = BADDR(*seg)) {
                  comentry = tbAllocPooled(ComPool, sizeof(struct CommandEntry));
                  if (previous)
                     previous->cm_next = comentry;
                  comentry->cm_address[0] = ' ';
               }
            }
         }
         segment = (struct Segment *) BADDR(segment->seg_Next);
      }
   }
   return (comcnt);
}

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

   handle = HandlePrintStart (filename);
   if ((handle) && (PrintOneLine (handle, "\n  Address  Name            UseCount     Lower     Upper    Size\n\n"))) {
      if (! WI_Commands) {
         i = GetCommands (&entryp);
      }
      if (i) {
         for (i=0;;i++) {
            if (WI_Commands)
               DoMethod (comlist,MUIM_List_GetEntry,i,&entryp);
            if (!entryp) break;

            _sprintf (tmpstr2, " %9s %-15.15s %8s", entryp->cm_address, entryp->cm_name, entryp->cm_uc);
            if ((entryp->cm_uc[0] == 'I') || (entryp->cm_uc[0] == 'S') || (entryp->cm_uc[0] == 'D')) {
               _sprintf (tmpstr, " %9s %9s %7s\n", entryp->cm_lower+2, entryp->cm_upper+2, entryp->cm_size+2);
               strcat (tmpstr2, tmpstr);
            } else {
               _sprintf (tmpstr, " %9s %9s %7s\n", entryp->cm_lower, entryp->cm_upper, entryp->cm_size);
               strcat (tmpstr2, tmpstr);
            }
            if (! (PrintOneLine (handle, tmpstr2)))
               break;

            if (! WI_Commands)
               entryp = entryp->cm_next;
         }
      }
   }
   HandlePrintStop();
}

void ShowCommands (void) {
   struct   CommandEntry   *com;

   ApplicationSleep();
   set (comlist,MUIA_List_Quiet,TRUE);
   set (comlist,MUIA_List_CompareHook,comlist_cmphook_ptr);
   set (BT_ComRemove, MUIA_Disabled, TRUE);

   FreeCommands();
   comcnt = GetCommands (&com);

   while (com) {
      InsertSortedEntry (comlist, (APTR *) &com);
      com = com->cm_next;
   }

   SetCountText (comcount, comcnt);
   AwakeApplication();
   set (comlist,MUIA_List_Quiet,FALSE);
}

void SendComList (void) {
   struct   CommandEntry   *com;

   FreeCommands();
   comcnt = GetCommands (&com);

   while (com) {
      SendEncodedEntry ((UBYTE *) com, sizeof (struct CommandEntry));
      com = com->cm_next;
   }
   FreeCommands();
}


APTR WI_Commands, comlist, comtext, comcount, CY_ComSort;
int  comsortstate = 0;
APTR BT_ComUpdate, BT_ComPrint, BT_ComRemove, BT_ComExit;

APTR ComSortList[] = {
   &list_cmpnormalhook,
   &list_cmpnamehook,
   &list_cmpaddresshook,
   NULL
};

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

char commands_title[WINDOWTITLELEN];

void CommandsWindow (BOOL state) {
   if (state) {
      if (WI_Commands) {
         ShowCommands();
      } else {
         WI_Commands = WindowObject,
         MUIA_Window_Title, MyGetWindowTitle (commands_title, "RESIDENT COMMANDS"),
         MUIA_HelpNode, CommandsText,
         MUIA_Window_ID, MakeListID('R','C','O','M'),
         WindowContents, VGroup,
            Child, comlist = MyListviewObject ("COL=0 DELTA=8,COL=1 DELTA=8,COL=2 DELTA=8 P=\33c,COL=3 DELTA=8,COL=4 DELTA=8,COL=5 P=\33r",&comlist_dsphook),
            Child, MyBelowSortedListview (&comtext, &comcount, &CY_ComSort, CYA_ComSortText, comsortstate),
            Child, MyVSpace(2),
            Child, HGroup, MUIA_Group_SameSize, TRUE,
               Child, BT_ComUpdate = KeyButtonA (UpdateText,ID_COMUPDATE),
               Child, BT_ComPrint  = KeyButtonA (PrintText ,ID_COMPRINT),
               Child, BT_ComRemove = KeyButtonA (RemoveText,ID_COMREMOVE),
               Child, BT_ComExit   = KeyButtonA (ExitText  ,ID_COMEXIT),
            End,
         End, End;

         DoMethod (AP_Scout,OM_ADDMEMBER,WI_Commands);
         DoMethod (WI_Commands,MUIM_Window_SetCycleChain,comlist,CY_ComSort,BT_ComUpdate,BT_ComPrint,BT_ComRemove,BT_ComExit,NULL);
         DoMethod (CY_ComSort, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, AP_Scout, 2, MUIM_Application_ReturnID, ID_COMSORT);

         SetCloseRequest (WI_Commands,ID_COMEXIT);
         SetListActive (comlist,ID_COMLV_ACTIVE);

         ShowCommands();

         SetWindowOpen (WI_Commands,comlist,ID_COMEXIT);
      }
   } else if ((! state) && (WI_Commands)) {
      SetWindowClose (WI_Commands,TRUE);

      FreeCommands();

      DoMethod (AP_Scout,OM_REMMEMBER,WI_Commands);
      MUI_DisposeObject (WI_Commands);
      WI_Commands = NULL;
      comlist = NULL;
   }
}

