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

static APTR PortPool = NULL;

__asm __saveds LONG portlist_dspfunc(register __a2 char **array, register __a1 struct PortEntry *portentry, register __a0 struct Hook *hook)
{
   if (portentry) {
      *array++ = portentry->pt_address;
      *array++ = portentry->pt_name;
      *array++ = portentry->pt_pri;
      *array++ = portentry->pt_flags;
      *array++ = portentry->pt_sigbit;
      *array++ = portentry->pt_sigtask;
      *array   = NULL;
   } else {
      *array++ = ESC "bAddress";
      *array++ = ESC "bln_Name";
      *array++ = ESC "bln_Pri";
      *array++ = ESC "bmp_Flags";
      *array++ = ESC "bmp_SigBit";
      *array++ = ESC "bmp_SigTask";
      *array   = NULL;
   }
   return(0);
}

struct Hook portlist_dsphook = {
 {NULL, NULL},
 (ULONG (* )())portlist_dspfunc,
 NULL, NULL
};

void FreePorts (void)
{
    MyFreePoolStructs(&PortPool, porttext, NULL, portlist);
}

int GetPorts (struct PortEntry **first) {
   struct   MsgPort     *port;
   struct   PortEntry   *portentry,*previous = NULL;

   int portcnt = 0;
   *first = 0;

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

   if (clientstate) {
      if (SendDaemon ("GetPortList")) {
         while ((portentry = tbAllocPooled(PortPool, sizeof(struct PortEntry))) \
           && (ReceiveDecodedEntry ((UBYTE *) portentry, sizeof (struct PortEntry)))) {
            IsHex (portentry->pt_address, (long *) &portentry->pt_adr);

            if (! *first)
               *first = portentry;
            if (previous)
               previous->pt_next = portentry;

            portcnt++;
            previous = portentry;
         }
      }
   } else {
      port = FIRSTPORT;
   
      while ((port->mp_Node.ln_Succ != 0) && (portentry = tbAllocPooled(PortPool, sizeof(struct PortEntry)))) {
         if (! *first)
            *first = portentry;
         if (previous)
            previous->pt_next = portentry;
   
         portentry->pt_adr = port;
   
         _sprintf (portentry->pt_address, "$%08lx", port);
         strncpy (portentry->pt_name, nonetest (port->mp_Node.ln_Name), 25);
         _sprintf (portentry->pt_pri, "%4ld ", port->mp_Node.ln_Pri);
         _sprintf (portentry->pt_sigbit, "%3ld ", port->mp_SigBit);
         strncpy (portentry->pt_sigtask, nonetest (GetTaskName ((struct Task *) port->mp_SigTask)), NODENAMELENGTH - 1);
         healstring (portentry->pt_sigtask);
         switch (port->mp_Flags) {
            case PA_SIGNAL : strcpy(portentry->pt_flags, "signal"); break;
            case PA_SOFTINT: strcpy(portentry->pt_flags, "softint"); break;
            case PA_IGNORE : strcpy(portentry->pt_flags, "ignore"); break;
         }
   
         portcnt++;
         previous = portentry;
         port = (struct MsgPort *) port->mp_Node.ln_Succ;
      }
   }
   return (portcnt);
}

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

   handle = HandlePrintStart (filename);
   if ((handle) && (PrintOneLine (handle, "\n  Address  Name                       Pri SigBit SigTask\n\n"))) {
      if (! WI_Ports) {
         i = GetPorts (&entryp);
      }
      if (i) {
         for (i=0;;i++) {
            if (WI_Ports)
               DoMethod (portlist,MUIM_List_GetEntry,i,&entryp);
            if (!entryp) break;

            _sprintf (tmpstr2, " %s %-25.25s %4s %3s   %-26.26s\n", entryp->pt_address, entryp->pt_name, entryp->pt_pri, entryp->pt_sigbit, entryp->pt_sigtask);
            if (! (PrintOneLine (handle, tmpstr2)))
               break;

            if (! WI_Ports)
               entryp = entryp->pt_next;
         }
      }
   }
   HandlePrintStop();
}

void ShowPorts (void) {
   struct   PortEntry   *port;

   ApplicationSleep();
   set(portlist,MUIA_List_Quiet,TRUE);
   set(portlist,MUIA_List_CompareHook,portlist_cmphook_ptr);
   set(BT_PortRemove, MUIA_Disabled, TRUE);
   set(BT_PortPriority, MUIA_Disabled, TRUE);
   set(BT_PortMore, MUIA_Disabled, TRUE);

   FreePorts();
   portcnt = GetPorts (&port);

   while (port) {
      InsertSortedEntry (portlist, (APTR *) &port);
      port = port->pt_next;
   }

   SetCountText (portcount, portcnt);
   AwakeApplication();
   set(portlist,MUIA_List_Quiet,FALSE);
}

void SendPortList (void) {
   struct   PortEntry   *port;

   FreePorts();
   GetPorts (&port);

   while (port) {
      SendEncodedEntry ((UBYTE *) port, sizeof (struct PortEntry));
      port = port->pt_next;
   }
   FreePorts();
}

void GetPortMore (struct MsgPort *port) {
   unsigned char  *title = "PORT: ";
   struct   WinFree  *ptr;

   APTR portmoretext0,portmoretext1,portmoretext2a,portmoretext2b,portmoretext3;
   APTR portmoretext4,portmoretext5;

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

//      MUIA_Window_SizeGadget, FALSE,
      MUIA_HelpNode, PortsText,
      MUIA_Window_ID, MakeDetailID('.','P','O','R'),
      WindowContents, HGroup,
         Child, VGroup, MUIA_Group_SameWidth, TRUE,
            Child, MyLabel2 ("Name:"),
            Child, MyVSpace(0),
            Child, MyLabel2 ("Address:\nPri:\nType:"),
            Child, MyVSpace(0),
            Child, MyLabel2 ("TaskName:"),
            Child, MyLabel2 ("MsgList:\nHead:"),
         End,
         Child, VGroup, MUIA_Group_SameWidth, TRUE,
            Child, portmoretext0 = MyTextObject(),
            Child, HGroup,
               Child, portmoretext1 = MyTextObject2(),
               Child, VGroup,
                  Child, MyLabel ("Flags:"),
                  Child, MyLabel ("SigBit:\nSigTask:"),
               End,
               Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
                  Child, portmoretext2a = KeyButtonF ('b', port->mp_Flags),
                  Child, portmoretext2b = MyTextObject(),
               End,
            End,
            Child, portmoretext3 = MyTextObject(),
            Child, HGroup,
               Child, portmoretext4 = MyTextObject2(),
               Child, MyLabel ("Tail:\nTailPred:"),
               Child, portmoretext5 = MyTextObject2(),
            End,
         End,
      End, End;

      if (ptr->wf_Window) {
         MySetContents (portmoretext1, ESC "r$%08lx\n" ESC "c%ld\n" ESC "c%s", port, port->mp_Node.ln_Pri, GetNodeType (port->mp_Node.ln_Type));
         MySetContents (portmoretext2b, ESC "c%ld\n" ESC "r$%08lx", port->mp_SigBit, port->mp_SigTask);
         MySetContents (portmoretext4, ESC "r$%08lx\n$%08lx", &port->mp_MsgList, port->mp_MsgList.lh_Head);
         MySetContents (portmoretext5, ESC "r$%08lx\n$%08lx", port->mp_MsgList.lh_Tail, port->mp_MsgList.lh_TailPred);

         HandleFlagsButtonPressed (portmoretext2a, ptr, "(PORT)", "mp_Flags", port->mp_Flags, NULL, (struct MaskedLongFlag *) &mp_flags, 'b');
         HandleWindowOpen (ptr, title, port->mp_Node.ln_Name);
         MySetContentsHealed (portmoretext0, "%s", port->mp_Node.ln_Name);
         MySetContentsHealed (portmoretext3, "%s", nonetest (GetTaskName (port->mp_SigTask)));
         HandleWindowClose (ptr);
      }
   }
}


APTR WI_Ports, portlist, porttext, portcount, CY_PortSort;
int  portsortstate = 0;
APTR BT_PortUpdate, BT_PortPrint, BT_PortRemove, BT_PortPriority, BT_PortMore, BT_PortExit;

APTR PortSortList[] = {
   &tasklist_cmpprihook,
   &list_cmpnamehook,
   &tasklist_cmpaddresshook,
   NULL
};

static const char *CYA_PortSortText[] = {
   "priority",
   "name",
   "address",
   NULL
};

char ports_title[WINDOWTITLELEN];

void PortsWindow (BOOL state) {
   if (state) {
      if (WI_Ports) {
         ShowPorts();
      } else {
         WI_Ports = WindowObject,
         MUIA_Window_Title, MyGetWindowTitle (ports_title, "PORTS"),
         MUIA_HelpNode, PortsText,
         MUIA_Window_ID, MakeListID('P','O','R','T'),
         WindowContents, VGroup,
            Child, portlist = MyListviewObject ("COL=0 DELTA=8,COL=1 DELTA=8,COL=2 DELTA=8 P=\33r,COL=3 DELTA=8,COL=4 DELTA=8 P=\33c,COL=5",&portlist_dsphook),
            Child, MyBelowSortedListview (&porttext, &portcount, &CY_PortSort, CYA_PortSortText, portsortstate),
            Child, MyVSpace(2),
            Child, HGroup, MUIA_Group_SameSize, TRUE,
               Child, BT_PortUpdate   = KeyButtonA (UpdateText  ,ID_PORTUPDATE),
               Child, BT_PortPrint    = KeyButtonA (PrintText   ,ID_PORTPRINT),
               Child, BT_PortRemove   = KeyButtonA (RemoveText  ,ID_PORTREMOVE),
               Child, BT_PortPriority = KeyButtonA (PriorityText,ID_PORTPRIORITY),
               Child, BT_PortMore     = KeyButtonA (MoreText    ,ID_PORTMORE),
               Child, BT_PortExit     = KeyButtonA (ExitText    ,ID_PORTEXIT),
            End,
         End, End;

         DoMethod (AP_Scout,OM_ADDMEMBER,WI_Ports);
         DoMethod (WI_Ports,MUIM_Window_SetCycleChain,portlist,CY_PortSort,BT_PortUpdate,BT_PortPrint,BT_PortRemove,BT_PortPriority,BT_PortMore,BT_PortExit,NULL);
         DoMethod (CY_PortSort, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, AP_Scout, 2, MUIM_Application_ReturnID, ID_PORTSORT);

         SetCloseRequest (WI_Ports,ID_PORTEXIT);
         SetListActive (portlist,ID_PORTLV_ACTIVE);
         SetListviewDoubleClick (portlist,ID_PORTMORE);

         ShowPorts();

         SetWindowOpen (WI_Ports,portlist,ID_PORTEXIT);
      }
   } else if ((! state) && (WI_Ports)) {
      SetWindowClose (WI_Ports,TRUE);

      FreePorts();

      DoMethod (AP_Scout,OM_REMMEMBER,WI_Ports);
      MUI_DisposeObject (WI_Ports);
      WI_Ports = NULL;
      portlist = NULL;
   }
}

