/*
***************************************************************************
*
* Datei:
*    RSysMonitor.c
*
* Inhalt:
*
*      --- Globale Routinen ---
*
*    void Monitor ( struct objectid *obj );
*
*      --- Lokale  Routinen ---
*
*    static int OpenMemMonitorWindow ( void );
*    static void SetListView ( void );
*    static void ConvertLine ( int type , int offset , char *memline , char *nodeline );
*    static void FreeDisplayMemory ( void );
*    static void ReInitDisplays ( void );
*    static int InitDisplays ( void );
*    static void ReadNextBlock ( void );
*    static void ReadPrevBlock ( void );
*    static int DisplayCYGadClicked ( void );
*    static int SaveCGadClicked ( void );
*    static int ASCIIGadClicked ( void );
*    static int SaveHexGadClicked ( void );
*    static int SaveGadClicked ( void );
*    static int PageBackwardGadClicked ( void );
*    static int PageForwardGadClicked ( void );
*    static int StartAdrGadClicked ( void );
*    static int HandleMemMonitorIDCMP ( void );
*
* Bemerkungen:
*    Speichermonitor von RSys. Wird verwendet, wenn keine
*    Modifikation von Objekten möglich ist.
*
* Erstellungsdatum:
*    29-Jul-93    Rolf Böhme
*
* Änderungen:
*    29-Jul-93    Rolf Böhme    Erstellung
*
***************************************************************************
*/

#include "RSys.h"
/*#include "I.c"*/

int   MemoryLVGadClicked(void);
int   DisplayCYGadClicked(void);
int   SaveCGadClicked(void);
int   ASCIIGadClicked(void);
int   SaveHexGadClicked(void);
int   SaveGadClicked(void);
int   PageBackwardGadClicked(void);
int   PageForwardGadClicked(void);
int   StartAdrGadClicked(void);

static struct Window *MemMonitorWnd = NULL;
static struct Gadget *MemMonitorGList = NULL;
struct IntuiMessage MemMonitorMsg;
static struct Gadget *MemMonitorGadgets[13];
static UWORD MemMonitorLeft = 37;
static UWORD MemMonitorTop = 14;
static UWORD MemMonitorWidth = 616;
static UWORD MemMonitorHeight = 217;
static UBYTE *MemMonitorWdt = (UBYTE *) NAME " - Monitor";

static UBYTE *DisplayCYGad0Labels[]=
{
   (UBYTE *) "Hex/ASCII",
   (UBYTE *) "Hex",
   (UBYTE *) "ASCII",
   NULL};

static char *headerline[3] =
{
   "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF",
   "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F",
   "     0123456789ABCDEF"
};

static enum displaytypes
{
   DT_hexascii, DT_hex, DT_ascii
};

static int CurrentDisplayType = DT_hexascii;
static char  Head[BUFSIZE];

static struct List DisplayLists[DISPLAYCOUNT];
static struct Node DisplayNodes[DISPLAYCOUNT][LINECOUNT];

static union
{
   char  memblock[BLOCKSIZE];
   char  memparts[LINECOUNT][LINESIZE];
   ULONG memlongs[LINECOUNT][LINESIZE / sizeof(ULONG)];
}     MemoryBlock;

static ULONG CurrentAddress,
      FirstAddress;

static struct Remember *MonKey = NULL;

static UWORD MemMonitorGTypes[]=
{
   LISTVIEW_KIND,
   CYCLE_KIND,
   BUTTON_KIND,
   BUTTON_KIND,
   BUTTON_KIND,
   BUTTON_KIND,
   BUTTON_KIND,
   BUTTON_KIND,
   TEXT_KIND,
   TEXT_KIND,
   BUTTON_KIND,
	TEXT_KIND,
	TEXT_KIND
};

static struct NewGadget MemMonitorNGad[]=
{
   12, 50, 589, 136, NULL, NULL, GD_MemoryLVGad, 0, NULL, NULL,
   476, 19, 125, 13, (UBYTE *) "Display", NULL, GD_DisplayCYGad, PLACETEXT_LEFT, NULL, (APTR) DisplayCYGadClicked,
   12, 201, 142, 13, (UBYTE *) "Save C-Code", NULL, GD_SaveCGad, PLACETEXT_IN, NULL, (APTR) SaveCGadClicked,
   161, 201, 142, 13, (UBYTE *) "Save ASCII", NULL, GD_ASCIIGad, PLACETEXT_IN, NULL, (APTR) ASCIIGadClicked,
   310, 201, 142, 13, (UBYTE *) "Save Hex", NULL, GD_SaveHexGad, PLACETEXT_IN, NULL, (APTR) SaveHexGadClicked,
   459, 201, 142, 13, (UBYTE *) "Save as is", NULL, GD_SaveAsIsGad, PLACETEXT_IN, NULL, (APTR) SaveGadClicked,
   12, 186, 193, 13, (UBYTE *) "<<< Prev 512 Bytes", NULL, GD_PageBackwardGad, PLACETEXT_IN, NULL, (APTR) PageBackwardGadClicked,
   408, 186, 193, 13, (UBYTE *) "Next 512 Bytes >>>", NULL, GD_PageForwardGad, PLACETEXT_IN, NULL, (APTR) PageForwardGadClicked,
   232, 19, 89, 13, (UBYTE *) "Current", NULL, GD_AddressTGad, PLACETEXT_LEFT, NULL, NULL,
   64, 19, 89, 13, (UBYTE *) "Start", NULL, GD_StartAdrTGad, PLACETEXT_LEFT, NULL, NULL,
   210, 186, 193, 13, (UBYTE *) "To start address", NULL, GD_StartAdrGad, PLACETEXT_IN, NULL, (APTR) StartAdrGadClicked,
	64, 4, 537, 13, (UBYTE *)"Entry", NULL, GD_EntryInfo, PLACETEXT_LEFT, NULL, NULL,
	12, 36, 589, 13, (UBYTE *)NULL, NULL, GD_HeaderLine, PLACETEXT_LEFT, NULL, NULL
};

static ULONG *MemMonitorGTags[]=
{
   (ULONG *) (GTLV_ReadOnly), (ULONG *) TRUE, (ULONG *) (TAG_DONE),
   (ULONG *) (GTCY_Labels), (ULONG *) & DisplayCYGad0Labels[0], (ULONG *) (TAG_DONE),
   (ULONG *) (TAG_DONE),
   (ULONG *) (TAG_DONE),
   (ULONG *) (TAG_DONE),
   (ULONG *) (TAG_DONE),
   (ULONG *) (TAG_DONE),
   (ULONG *) (TAG_DONE),
   (ULONG *) (GTTX_Border), (ULONG *) TRUE, (ULONG *) (TAG_DONE),
   (ULONG *) (GTTX_Border), (ULONG *) TRUE, (ULONG *) (TAG_DONE),
   (ULONG *) (TAG_DONE),
	(ULONG *) (GTTX_Border), (ULONG *)TRUE, (ULONG *)(TAG_DONE),
	(ULONG *) (GTTX_Border), (ULONG *)TRUE, (ULONG *)(TAG_DONE),
};

static int
OpenMemMonitorWindow(void)
{
   struct NewGadget ng;
   struct Gadget *g;
   UWORD lc,
         tc;
   UWORD wleft = MemMonitorLeft,
         wtop = MemMonitorTop,
         ww,
         wh;
   int   gl[]=
   {GD_MemoryLVGad-GD_MemoryLVGad, GD_AddressTGad-GD_MemoryLVGad,
    GD_StartAdrTGad-GD_MemoryLVGad, GD_EntryInfo-GD_MemoryLVGad,
    GD_HeaderLine-GD_MemoryLVGad};

   AdjustWindowDimensions(Scr, MemMonitorLeft, MemMonitorTop,
                          MemMonitorWidth, MemMonitorHeight,
                          &wleft, &wtop, &ww, &wh);

   if (!(g = CreateContext(&MemMonitorGList)))
      return (1L);

   for (lc = 0, tc = 0; lc < MemMonitor_CNT; lc++)
   {

      CopyMem((char *)&MemMonitorNGad[lc], (char *)&ng, (long)sizeof(struct NewGadget));

      ng.ng_VisualInfo = VisualInfo;
      ng.ng_TextAttr = Font;
      ng.ng_LeftEdge = OffX + ComputeX(ng.ng_LeftEdge);
      ng.ng_TopEdge = OffY + ComputeY(ng.ng_TopEdge);
      ng.ng_Width = ComputeX(ng.ng_Width);
      ng.ng_Height = ComputeY(ng.ng_Height);

      MemMonitorGadgets[lc] = g = CreateGadgetA((ULONG) MemMonitorGTypes[lc], g, &ng, (struct TagItem *) & MemMonitorGTags[tc]);

      while (MemMonitorGTags[tc])
         tc += 2;
      tc++;

      if (NOT g)
         return (2L);
   }

   if (!(MemMonitorWnd = OpenWindowTags(NULL,
                                        WA_Left, wleft,
                                        WA_Top, wtop,
                                        WA_Width, ww,
                                        WA_Height, wh,
                                        WA_IDCMP, LISTVIEWIDCMP |
                                        CYCLEIDCMP | BUTTONIDCMP |
                                        TEXTIDCMP | IDCMP_CLOSEWINDOW |
                                        IDCMP_REFRESHWINDOW |
                                        IDCMP_VANILLAKEY,
                                        WA_Flags, WFLG_DRAGBAR |
                                        WFLG_DEPTHGADGET |
                                        WFLG_CLOSEGADGET |
                                        WFLG_SMART_REFRESH |
                                        WFLG_RMBTRAP,
                                        WA_Title, MemMonitorWdt,
                                        WA_PubScreenFallBack, TRUE,
                                        WA_PubScreen, Scr,
                                        TAG_DONE)))
      return (4L);

   RefreshRastPort(MemMonitorWnd, MemMonitorGadgets, gl, 5, FALSE, MemMonitorGList);

   return (0L);
}

static void
SetTextGadgets(void)
{
   char curraddr[10], addr[10];

   sprintf(curraddr,"%08lx", CurrentAddress);
   sprintf(addr,"%08lx", FirstAddress);

	GT_SetGadgetAttrs(MemMonitorGadgets[GD_AddressTGad-GD_MemoryLVGad], MemMonitorWnd,
							NULL,
							GTTX_Text, (UBYTE *) curraddr,
							TAG_DONE);

	GT_SetGadgetAttrs(MemMonitorGadgets[GD_StartAdrTGad-GD_MemoryLVGad], MemMonitorWnd,
							NULL,
							GTTX_Text, (UBYTE *) addr,
							TAG_DONE);

	GT_SetGadgetAttrs(MemMonitorGadgets[GD_HeaderLine-GD_MemoryLVGad], MemMonitorWnd,
							NULL,
							GTTX_Text, (UBYTE *) headerline[CurrentDisplayType],
							TAG_DONE);

   return;
}

static void
SetListView(void)
{
   InitListView(MemMonitorWnd, MemMonitorGadgets[GD_MemoryLVGad-GD_MemoryLVGad],
                &DisplayLists[CurrentDisplayType], UNSETLVPOS);

   return;
}

static void
ConvertLine(int type, int offset, char *memline, char *nodeline)
{
   char  bytehex[LINESIZE][4],
         i,
         offsetstr[7],
         charline[LINESIZE + 1];

   for (i = 0; i < LINESIZE; i++)
   {
      sprintf(bytehex[i], "%02lx ", (unsigned char)memline[i]);
      charline[i] = (isprint((int)memline[i]) ? memline[i] : '.');
   }

   charline[LINESIZE] = STRINGEND;

   sprintf(offsetstr, "%03lx: ", offset*16);

   switch (type)
   {
      case DT_hexascii:
         strncpy(nodeline, offsetstr, 5);
         for (i = 0; i < LINESIZE; i++) strncat(nodeline, bytehex[i], 4);
         strncat(nodeline, charline, LINESIZE);
         break;

      case DT_hex:
         strncpy(nodeline, offsetstr, 5);
         for (i = 0; i < LINESIZE; i++) strncat(nodeline, bytehex[i], 4);
         break;

      case DT_ascii:
         strncpy(nodeline, offsetstr, 5);
         strncat(nodeline, charline, LINESIZE);
         break;
   }

   return;
}

static void
FreeDisplayMemory(void)
{
   FreeRemember(MONKEY, TRUE);
   return;
}

static void
ReInitDisplays(void)
{
   char  memline[LINESIZE + 1];
   char  displaytype,
         j;

   SetTextGadgets();

   Forbid();
   CopyMem((APTR) CurrentAddress, (APTR) & MemoryBlock, BLOCKSIZE);
   Permit();

   for (displaytype = 0; displaytype < DISPLAYCOUNT; displaytype++)
   {
      NewList(&DisplayLists[displaytype]);

      for (j = 0; j < LINECOUNT; j++)
      {
         CopyMem(&MemoryBlock.memparts[j][0], &memline[0], LINESIZE);

         ConvertLine((int)displaytype, (int)j, memline, DisplayNodes[displaytype][j].ln_Name);

         AddTail(&DisplayLists[displaytype], &DisplayNodes[displaytype][j]);
      }
   }

   SetListView();

   return;
}

static int
InitDisplays(void)
{
   char  memline[LINESIZE + 1];
   char  displaytype,
         j;

   SetTextGadgets();

   Forbid();
   CopyMem((APTR) CurrentAddress, (APTR) & MemoryBlock, BLOCKSIZE);
   Permit();

   for (displaytype = 0; displaytype < DISPLAYCOUNT; displaytype++)
   {
      NewList(&DisplayLists[displaytype]);

      for (j = 0; j < LINECOUNT; j++)
      {
         DisplayNodes[displaytype][j].ln_Name = AllocMonMem(3 * (LINESIZE + 9));

         if (!DisplayNodes[displaytype][j].ln_Name) return FALSE;

         DisplayNodes[displaytype][j].ln_Type = NT_USER;
         DisplayNodes[displaytype][j].ln_Pri = 0;

         CopyMem(&MemoryBlock.memparts[j][0], &memline[0], LINESIZE);

         ConvertLine((int)displaytype, (int)j, memline, DisplayNodes[displaytype][j].ln_Name);

         AddTail(&DisplayLists[displaytype], &DisplayNodes[displaytype][j]);
      }
   }

   SetListView();

   return TRUE;
}

static void
ReadNextBlock(void)
{
   if (CurrentAddress + 512L <= 0x01000000L) CurrentAddress += 512L;
   ReInitDisplays();

   return;
}

static void
ReadPrevBlock(void)
{
   if (CurrentAddress - 512 >= 0) CurrentAddress -= 512L;
   ReInitDisplays();

   return;
}

static int
DisplayCYGadClicked(void)
{
   CurrentDisplayType = MemMonitorMsg.Code;
   SetListView();

   return TRUE;
}

static int
SaveCGadClicked(void)
{
   /* routine when gadget "Save C-Code" is clicked. */
   BPTR fout;
   int i;

   sprintf(Head, "/\*\n   RSys-C-Code Generator"
                 "\n   Memory at 0x%08lx\n\*/\n\n", CurrentAddress);

   if (GetFile(MemMonitorWnd, "T:", "RSysData.c", "#?.c", "Save C-Code...", "Save"))
   {
      fout = AskFileMode((char *)_fullpath, MemMonitorWnd);

      if(fout)
      {
         FPuts(fout, (STRPTR)Head);
         FPuts(fout, (STRPTR)"ULONG RSysData[] = \{\n");

         for(i = 0; i < LINECOUNT; i++)
            FPrintf(fout, (STRPTR)"   0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx,\n",
                    MemoryBlock.memlongs[i][0],
                    MemoryBlock.memlongs[i][1],
                    MemoryBlock.memlongs[i][2],
                    MemoryBlock.memlongs[i][3]);

         FPuts(fout, (STRPTR)"\};\n/\* End of Code \*/\n" );

         Close(fout);
      }
   }

   return TRUE;
}

static int
ASCIIGadClicked(void)
{
   /* routine when gadget "Save ASCII" is clicked. */
   sprintf(Head, "Memory at 0x%08lx", CurrentAddress);

   if (GetFile(MemMonitorWnd, "T:", "RSysMemoryASCII.dat", "#?.dat",
               "Save as ASCII-Data...", "Save"))
      SaveList(MemMonitorWnd, (char *)_fullpath, Head,
               &DisplayLists[DT_ascii], FALSE);

   return TRUE;
}

static int
SaveHexGadClicked(void)
{
   /* routine when gadget "Save Hex" is clicked. */

   sprintf(Head, "Memory at 0x%08lx", CurrentAddress);

   if (GetFile(MemMonitorWnd, "T:", "RSysMemoryHEX.dat", "#?.dat",
               "Save as Hex-Datas...", "Save"))
      SaveList(MemMonitorWnd, (char *)_fullpath, Head,
               &DisplayLists[DT_hex], FALSE);
   return TRUE;
}

static int
SaveGadClicked(void)
{
   /* routine when gadget "Save as is" is clicked. */

   sprintf(Head, "Memory at 0x%08lx", CurrentAddress);

   if (GetFile(MemMonitorWnd, "T:", "MemoryList.dat", "#?.dat",
               "Save List as is...", "Save"))
      SaveList(MemMonitorWnd, (char *)_fullpath, Head,
               &DisplayLists[CurrentDisplayType], FALSE);

   return TRUE;
}

static int
PageBackwardGadClicked(void)
{
   /* routine when gadget "<<< Prev 512 Bytes" is clicked. */
   ReadPrevBlock();

   return TRUE;
}

static int
PageForwardGadClicked(void)
{
   /* routine when gadget "Next 512 Bytes >>>" is clicked. */
   ReadNextBlock();

   return TRUE;
}

static int
StartAdrGadClicked(void)
{
   CurrentAddress = FirstAddress;

   ReInitDisplays();

   return TRUE;
}

static int
HandleMemMonitorIDCMP(void)
{
   struct IntuiMessage *m;
   int   (*func) (void);
   BOOL  running = TRUE;

   while (m = GT_GetIMsg(MemMonitorWnd->UserPort))
   {
      CopyMem((char *)m, (char *)&MemMonitorMsg, (long)sizeof(struct IntuiMessage));

      GT_ReplyIMsg(m);

      switch (MemMonitorMsg.Class)
      {
         case IDCMP_REFRESHWINDOW:
            MakeWindowRefresh(MemMonitorWnd);
            break;

         case IDCMP_CLOSEWINDOW:
            running = FALSE;
            break;

         case IDCMP_VANILLAKEY:
			   if (MemMonitorMsg.Code == ESC) running = FALSE;
            break;

         case IDCMP_GADGETUP:
         case IDCMP_GADGETDOWN:
            HandleHelp(((struct Gadget *)MemMonitorMsg.IAddress)->GadgetID);
            func = (void *)((struct Gadget *) MemMonitorMsg.IAddress)->UserData;
            running = func();
            break;
      }
   }
   return (running);
}

void
Monitor(struct objectid *obj, char *entrystring)
{
   ValidMemoryNode *vmnode;
   char header[2*BUFSIZE];

   HandleHelp(MONITOR);

   CurrentDisplayType = DT_hexascii;

   CurrentAddress = (ULONG)obj->address;
   FirstAddress = (ULONG)obj->address;

   vmnode = CheckNode(CurrentAddress);

   if(!vmnode) ErrorHandle("Address not found in table", MEMORY_ERR, TYPE_FAIL, NO_KILL);
   else
      if(!IsValid(vmnode) && !MyEasyRequest(SysWnd,(STRPTR)NAME " - Memory validation info",
                             (STRPTR)"Call Monitor|Cancel",
                             (STRPTR)"You requested a memory start address which is not valid\n"
                                     "and can produce an Enforcer Hit! The Attributes are:\n"
                                     "%s \n%s \n%s\nComment: %s\n"
                                     "Do you want to call the " NAME "-Monitor anyway?",
                                     "- Invalid",
                                     (IsWriteProtect(vmnode) ? "- Write protected" : "- Not write protected"),
                                     (IsCacheable(vmnode) ? "- Cacheable" : "- Not cacheable"),
                                     vmnode->vm_comment))
         return;

   if (OpenASysWindow(OpenMemMonitorWindow, NO_KILL))
   {
      LockMainWindow(LOCK);

      if(vmnode) sprintf(header,"%s [%s]", &entrystring[9], vmnode->vm_comment);
      else
         sprintf(header,"%s [no valid memory info]", &entrystring[9]);

   	GT_SetGadgetAttrs(MemMonitorGadgets[GD_EntryInfo-GD_MemoryLVGad], MemMonitorWnd,
	   						NULL,
		   					GTTX_Text, (UBYTE *) header,
			   				TAG_DONE);

      if (InitDisplays()) while (HandleMemMonitorIDCMP()) ;
      else
         ErrorHandle("Display nodes", MEMORY_ERR, ALLOC_FAIL, NO_KILL);

      FreeDisplayMemory();

      CloseASysWindow(&MemMonitorWnd, &MemMonitorGList, NULL);

      LockMainWindow(UNLOCK);
   }

   return;
}
