/****h *SysSemaphore.c ************************************************
**
** NAME
**    SysSemaphore.c
**
** DESCRIPTION
**    Display a list of all Semaphores currently known to the OS.
**
** FUNCTIONAL INTERFACE:
**
**
**
** FUNCTIONS FROM SysCommon.c:
**
**   PUBLIC BOOL SanityCheck( char *msg, ULONG addr );
**
**   PUBLIC int  SetupSystemList( (*OpenWindowFunc)( void ) );
**
**   PUBLIC void ShutdownSystemList( void );
**
**   PUBLIC void ModifyListView( struct Gadget *lv, 
**                               struct Window *w,
**                               struct List   *list,
**                               struct Gadget *strgadget
**                             );
**
**  GUI Designed by : Jim Steichen
**
***********************************************************************
*/

#include <string.h>

#include <exec/types.h>
#include <exec/execbase.h>

#include <AmigaDOSErrs.h>

#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>

#include <libraries/gadtools.h>

#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <clib/diskfont_protos.h>

#include "CPGM:GlobalObjects/CommonFuncs.h"

#include "SysLists.h"

#define SemLV      0
#define Update     1
#define Remove     2
#define Cancel     3
#define Release    4
#define SemDisplay 5

#define ATS_CNT 6

#define LISTVIEWGADGET ATSGadgets[ SemLV ]
#define SEM_DISPLAY    ATSGadgets[ SemDisplay ]

PUBLIC struct List *SListPtr = NULL;

PRIVATE char ver[] = "$VER: SysSemaphore 1.0 (18-Sep-2000) by J.T. Steichen";

PRIVATE struct Window       *ATSWnd   = NULL;
PRIVATE struct Gadget       *ATSGList = NULL;
PRIVATE struct IntuiMessage  ATSMsg;
PRIVATE struct Gadget       *ATSGadgets[ ATS_CNT ];

PRIVATE UWORD  ATSLeft   = 0;
PRIVATE UWORD  ATSTop    = 16;
PRIVATE UWORD  ATSWidth  = 632;
PRIVATE UWORD  ATSHeight = 238;
PRIVATE UBYTE *ATSWdt    = (UBYTE *) "System Semaphores Info:";

PUBLIC struct TextFont *ATSFont    = NULL;

#define MAXSEMS    30
#define NODELENGTH 80

PRIVATE struct MinList SempList;
PRIVATE struct Node    SempNode;
PRIVATE struct Node    SempNodes[ MAXSEMS      ] = { NULL, };
PRIVATE UBYTE          NodeStrs[  MAXSEMS * NODELENGTH ] = "";

PRIVATE UWORD ATSGTypes[] = {

   LISTVIEW_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND,   BUTTON_KIND, TEXT_KIND
};

PRIVATE int SemLVClicked(   int whichitem );
PRIVATE int UpdateClicked(  int dummy     );
PRIVATE int RemoveClicked(  int dummy     );
PRIVATE int CancelClicked(  int dummy     );
PRIVATE int ReleaseClicked( int dummy     );

PRIVATE struct NewGadget ATSNGad[] = {

     2,   3, 627, 184,                NULL, NULL, SemLV, 
   0, NULL, (APTR) SemLVClicked,
   
     2, 212,  71,  17, (UBYTE *) "_Update", NULL, Update, 
   PLACETEXT_IN, NULL, (APTR) UpdateClicked,

   396, 212,  71,  17, (UBYTE *) "Remove",  NULL, Remove, 
   PLACETEXT_IN, NULL, (APTR) RemoveClicked,

   554, 212,  71,  17, (UBYTE *) "_Cancel", NULL, Cancel, 
   PLACETEXT_IN, NULL, (APTR) CancelClicked,

    82, 212,  71,  17, (UBYTE *) "Release", NULL, Release, 
   PLACETEXT_IN, NULL, (APTR) ReleaseClicked,

     2, 190, 611, 16,                 NULL, NULL, SemDisplay, 
   0, NULL, NULL
};

PRIVATE ULONG ATSGTags[] = {

   GTLV_ShowSelected, NULL, 
   LAYOUTA_Spacing,      2, TAG_DONE,

   GT_Underscore,      '_', TAG_DONE,
   GA_Disabled,       TRUE, TAG_DONE,
   GT_Underscore,      '_', TAG_DONE,
   GA_Disabled,       TRUE, TAG_DONE,
   GTTX_Border,       TRUE, TAG_DONE
};

// -------------------------------------------------------------------

PRIVATE struct SignalSemaphore *CurrentSem = NULL;

PRIVATE int InitializeSemaphoreList( void )
{
   IMPORT struct ExecBase *SysBase;

   struct Task *tc = NULL;
   char        *nm = NULL;
   int          i  = 0;

   HideListFromView( LISTVIEWGADGET, ATSWnd );

   Forbid();

     SListPtr   = &SysBase->SemaphoreList;
     CurrentSem = (struct SignalSemaphore *) SListPtr->lh_Head;

     while (i < MAXSEMS && CurrentSem != NULL)
        {       
        tc = CurrentSem->ss_Owner;
        nm = CurrentSem->ss_Link.ln_Name;
        
        sprintf( &NodeStrs[ i++ * NODELENGTH ], 
                 "%08LX %4d %4u %08LX %08LX %-20.20s %-30.30s",
                 CurrentSem, 
                 CurrentSem->ss_Link.ln_Pri,
                 CurrentSem->ss_NestCount,
                 &CurrentSem->ss_WaitQueue,
                 CurrentSem->ss_QueueCount,
                 nm == NULL ? "** NO NAME **" : nm,      
                 tc == NULL ? "** UNKNOWN **" : tc->tc_Node.ln_Name
               );
        
        CurrentSem = (struct SignalSemaphore *) 
                      CurrentSem->ss_Link.ln_Succ;
        }

     // Reset CurrentSem to the Head of the list.
     CurrentSem = (struct SignalSemaphore *) SListPtr->lh_Head;

   Permit();

   GT_SetGadgetAttrs( LISTVIEWGADGET, ATSWnd, NULL,
                      GTLV_Labels,       &SempList,
                      GTLV_ShowSelected, SEM_DISPLAY,
                      GTLV_Selected,     0, 
                      GTLV_MaxPen,       255,
                      GTLV_ItemHeight,   12,
                      TAG_END
                    );

   SetWindowTitles( ATSWnd, ATSWdt, (UBYTE *) -1 );

   return( i );
}

PRIVATE char wt[80] = { 0, }, *modtitle = &wt[0];

PRIVATE int SemLVClicked( int whichitem )
{
   ULONG addr = 0L;

   if (whichitem == 0)
      {
      // Disable buttons because user selected the title item:

      GT_SetGadgetAttrs( ATSGadgets[ Remove ], ATSWnd, NULL,
                         GA_Disabled, TRUE, TAG_DONE 
                       );

      GT_SetGadgetAttrs( ATSGadgets[ Release ], ATSWnd, NULL,
                         GA_Disabled, TRUE, TAG_DONE 
                       );
   
      SetWindowTitles( ATSWnd, ATSWdt, (UBYTE *) -1 );
      
      GT_SetGadgetAttrs( SEM_DISPLAY, ATSWnd, NULL,
                         GTTX_Text, (STRPTR) "",
                         TAG_DONE
                       );

      CurrentSem = NULL;

      return( (int) TRUE );
      }

   // Now get address from the item:
   
   (void) stch_l( SempNodes[ whichitem ].ln_Name, (long *) &addr );
   CurrentSem = addr;
    
   if (addr != NULL)
      {
      sprintf( modtitle, "%s  You Selected:  %08LX", ATSWdt, addr );
      SetWindowTitles( ATSWnd, modtitle, (UBYTE *) -1 );
      
      GT_SetGadgetAttrs( SEM_DISPLAY, ATSWnd, NULL,
                         GTTX_Text, 
                         (STRPTR) &NodeStrs[ NODELENGTH * whichitem ],
                         TAG_DONE
                       );
      }

   // Enable buttons because user selected a Semaphore from the ListView:

   GT_SetGadgetAttrs( ATSGadgets[ Remove ], ATSWnd, NULL,
                      GA_Disabled, FALSE, TAG_DONE 
                    );

   GT_SetGadgetAttrs( ATSGadgets[ Release ], ATSWnd, NULL,
                      GA_Disabled, FALSE, TAG_DONE 
                    );
   
   return( (int) TRUE );
}

PRIVATE int UpdateClicked( int dummy )
{
   int i;
   
   for (i = 1; i <= MAXSEMS; i++)
       NodeStrs[ i * NODELENGTH ] = '\0'; // Kill old ListView strings.

   if (InitializeSemaphoreList() <= 0)
      {
      // No Semaphores known to SysBase!!
      SetReqButtons( "OKAY" );

      (void) Handle_Problem( "No Semaphores found!", "OS ERROR??", NULL );

      SetReqButtons( "CONTINUE|ABORT" );
      }  

   GT_RefreshWindow( ATSWnd, NULL );

   return( (int) TRUE );
}

PRIVATE void RemoveTheSemaphore( struct SignalSemaphore *ss )
{
   // We should probably check that the ss->ss_QueueCount is 0 first: 

   // ObtainSemaphoreList( SysBase->SemaphoreList );
   // Forbid();

   //   RemSemaphore( ss );
   //   ObtainSemaphore( ss );
   //   ReleaseSemaphore( ss );

   // Permit();
   // ReleaseSemaphoreList( SysBase->SemaphoreList );

   (void) Handle_Problem( "NOT Implemented yet!", 
                          "User Information:", NULL
                        );
   return;
}

PRIVATE int RemoveClicked( int dummy )
{
   /* Do a SanityCheck() before Removing the Semaphore: */

   // Check CurrentSem for a non-NULL value

   if (CurrentSem != NULL)
      {
      if (SanityCheck( "Are you SURE you want to Remove %08lx?" ) != FALSE)
         {
         RemoveTheSemaphore( CurrentSem );

         if (InitializeSemaphoreList() <= 0)
            {
            // No Semaphores known to SysBase!!
            SetReqButtons( "OKAY" );

            (void) Handle_Problem( "No Semaphores found!", 
                                   "OS ERROR??", NULL
                                 );

            SetReqButtons( "CONTINUE|ABORT" );
            }

         GT_RefreshWindow( ATSWnd, NULL );
         }
      }
   else
      {
      // No Semaphores selected by the user:
      SetReqButtons( "OKAY" );

      (void) Handle_Problem( "Select a Semaphores first!", 
                             "USER ERROR:", NULL
                           );

      SetReqButtons( "CONTINUE|ABORT" );

      return( (int) TRUE );
      }

   return( (int) TRUE );
}

PRIVATE void ReleaseTheSemaphore( struct SignalSemaphore *ss )
{
   // int i;

   // We should probably check that the ss->ss_QueueCount is 0 first: 

   // ObtainSemaphoreList( SysBase->SemaphoreList );

   // for (i = 0; i < ss->ss_NestCount; i++)
   //    ReleaseSemaphore( ss );

   // ReleaseSemaphoreList( SysBase->SemaphoreList );

   (void) Handle_Problem( "NOT Implemented yet!", 
                          "User Information:", NULL
                        );
   return;
}

PRIVATE int ReleaseClicked( int dummy )
{
   /* Do a SanityCheck() before Releasing the Semaphore: */

   // Check CurrentSem for a non-NULL value

   if (CurrentSem != NULL)
      {
      if (SanityCheck( "Are you SURE you want to Release %08lx?" )!= FALSE)
         {
         ReleaseTheSemaphore( CurrentSem );

         if (InitializeSemaphoreList() <= 0)
            {
            // No Semaphores known to SysBase!!
            SetReqButtons( "OKAY" );

            (void) Handle_Problem( "No Semaphores found!", 
                                   "OS ERROR??", NULL
                                 );

            SetReqButtons( "CONTINUE|ABORT" );
            }

         GT_RefreshWindow( ATSWnd, NULL );
         }
      else
         return( (int) TRUE );
      }
   else
      {
      // No Semaphores selected by the user:
      SetReqButtons( "OKAY" );

      (void) Handle_Problem( "Select a Semaphores first!", 
                             "USER ERROR:", NULL
                           );

      SetReqButtons( "CONTINUE|ABORT" );

      return( (int) TRUE );
      }

   return( (int) TRUE );
}

PRIVATE void CloseATSWindow( void )
{
   if (ATSWnd != NULL)
      {
      CloseWindow( ATSWnd );
      ATSWnd = NULL;
      }

   if (ATSGList != NULL)
      {
      FreeGadgets( ATSGList );
      ATSGList = NULL;
      }

   if (ATSFont != NULL)
      {
      CloseFont( ATSFont );
      ATSFont = NULL;
      }

   return;
}

PRIVATE int ATSCloseWindow( void )
{
   CloseATSWindow();
   return( (int) FALSE );
}

PRIVATE int CancelClicked( int dummy )
{
   return( ATSCloseWindow() );
}


PRIVATE int OpenATSWindow( void )
{
   struct NewGadget  ng;
   struct Gadget    *g;
   UWORD             lc, tc;
   UWORD             wleft = ATSLeft, wtop = ATSTop, ww, wh;

   ComputeFont( Scr, Font, &CFont, ATSWidth, ATSHeight );

   ww = ComputeX( CFont.FontX, ATSWidth );
   wh = ComputeY( CFont.FontY, ATSHeight );

   if ((wleft + ww + CFont.OffX + Scr->WBorRight) > Scr->Width)
      wleft = Scr->Width - ww;

   if ((wtop + wh + CFont.OffY + Scr->WBorBottom) > Scr->Height)
      wtop = Scr->Height - wh;

   if ( !(ATSFont = OpenDiskFont( Font )))
      return( -5 );

   if ( !(g = CreateContext( &ATSGList )))
      return( -1 );

   for (lc = 0, tc = 0; lc < ATS_CNT; lc++)
      {
      CopyMem( (char *) &ATSNGad[lc], (char *) &ng, 
               (long) sizeof( struct NewGadget ) 
             );

      ng.ng_VisualInfo = VisualInfo;
      ng.ng_TextAttr   = Font;
      ng.ng_LeftEdge   = CFont.OffX + ComputeX( CFont.FontX, 
                                                ng.ng_LeftEdge
                                              );

      ng.ng_TopEdge    = CFont.OffY + ComputeY( CFont.FontY, 
                                                ng.ng_TopEdge
                                              );
                                              
      ng.ng_Width      = ComputeX( CFont.FontX, ng.ng_Width );
      ng.ng_Height     = ComputeY( CFont.FontY, ng.ng_Height );

      ATSGadgets[lc] = g = CreateGadgetA( (ULONG) ATSGTypes[lc], 
                             g, 
                             &ng, 
                             (struct TagItem *) & ATSGTags[tc] );

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

      tc++;

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

   if ( !(ATSWnd = OpenWindowTags( NULL,

                     WA_Left,        wleft,
                     WA_Top,         wtop,
                     WA_Width,       ww + CFont.OffX + Scr->WBorRight,
                     WA_Height,      wh + CFont.OffY + Scr->WBorBottom,
                     WA_IDCMP,       LISTVIEWIDCMP | BUTTONIDCMP
                       | TEXTIDCMP | IDCMP_CLOSEWINDOW 
                       | IDCMP_REFRESHWINDOW | IDCMP_VANILLAKEY,

                     WA_Flags,       WFLG_DRAGBAR | WFLG_DEPTHGADGET 
                       | WFLG_CLOSEGADGET | WFLG_SMART_REFRESH 
                       | WFLG_ACTIVATE | WFLG_RMBTRAP,
                     
                     WA_Gadgets,     ATSGList,
                     WA_Title,       ATSWdt,
                     WA_ScreenTitle, "System Info",
                     TAG_DONE )) 
      )
      return( -4 );

   GT_RefreshWindow( ATSWnd, NULL );

   return( 0 );
}

PRIVATE int ATSVanillaKey( int whichkey )
{
   int rval = TRUE;
   
   switch (whichkey)
      {
      case 'u':
      case 'U':
         UpdateClicked( 0 );
         break;
         
      case 'c':
      case 'C':
      case 'q':
      case 'Q':
         rval = ATSCloseWindow();
         break;
      }

   return( rval );
}

PRIVATE int HandleATSIDCMP( void )
{
   struct IntuiMessage *m;
   int                  (*func)( int code );
   BOOL running = TRUE;

   while (running == TRUE)
      {
      if ((m = GT_GetIMsg( ATSWnd->UserPort ) ) == NULL )
         {
         (void) Wait( 1L << ATSWnd->UserPort->mp_SigBit );
         continue;
         }

      CopyMem( (char *) m, (char *) &ATSMsg, 
               (long) sizeof( struct IntuiMessage ) 
             );

      GT_ReplyIMsg( m );

      switch (ATSMsg.Class)
         {
         case IDCMP_REFRESHWINDOW:
            GT_BeginRefresh( ATSWnd );
            GT_EndRefresh( ATSWnd, TRUE );
            break;

         case IDCMP_CLOSEWINDOW:
            running = ATSCloseWindow();
            break;

         case IDCMP_VANILLAKEY:
            running = ATSVanillaKey( ATSMsg.Code );
            break;

         case IDCMP_GADGETUP:
         case IDCMP_GADGETDOWN:
            func = (void *) ((struct Gadget *) ATSMsg.IAddress)->UserData;
            if (func != NULL)
               running = func( (int) ATSMsg.Code );
            break;
         }
      }

   return( running );
}

PUBLIC int HandleSemaphoreLV( void )
{
   int i = 0;

   if (SetupSystemList( &OpenATSWindow ) < 0)
      {
      (void) Handle_Problem( "Couldn't open a System ListViewer!", 
                             "Allocation Problem:", NULL 
                           );
      return( -1 );
      }

   // Disable buttons until user selects a Semaphore from the ListView:

   GT_SetGadgetAttrs( ATSGadgets[ Remove ], ATSWnd, NULL,
                      GA_Disabled, TRUE, TAG_DONE 
                    );

   GT_SetGadgetAttrs( ATSGadgets[ Release ], ATSWnd, NULL,
                      GA_Disabled, TRUE, TAG_DONE 
                    );
   
   SempNode.ln_Succ = (struct Node *) SempList.mlh_Tail;
   SempNode.ln_Pred = (struct Node *) SempList.mlh_Head;
   SempNode.ln_Type = 0;
   SempNode.ln_Pri  = MAXSEMS - 129;
   SempNode.ln_Name = "Address   Pri Nest Queue    Count    Name"
                      "                 Owner Task ";

   SempNodes[0]     = SempNode;

   SetNotifyWindow( ATSWnd ); // For Handle_Problem().
  
   // ScrNodes[0] is already set up:

   for (i = 1; i <= MAXSEMS; i++)
       {
       SempNodes[i].ln_Name = &NodeStrs[ i * NODELENGTH ];
       SempNodes[i].ln_Pri  = MAXSEMS - i - 129;
       }     

   NewList( (struct List *) &SempList );

   for (i = 0; i < MAXSEMS; i++)
      Enqueue( (struct List *) &SempList, &SempNodes[i] );

   (void) InitializeSemaphoreList();

   GT_SetGadgetAttrs( LISTVIEWGADGET, ATSWnd, NULL,
                      GTLV_Labels,       &SempList,
                      GTLV_ShowSelected, SEM_DISPLAY,
                      GTLV_Selected,     1,
                      GTLV_MaxPen,       255,
                      GTLV_ItemHeight,   12,
                      TAG_END
                    );

   GT_RefreshWindow( ATSWnd, NULL );

   (void) HandleATSIDCMP();
   
   ShutdownSystemList();
   return( 0 );
}

#ifdef DEBUG

PUBLIC int main( void )
{
   return( HandleSemaphoreLV() );
}

#endif

/* --------------------- END of SysSemaphore.c file! --------------- */
