/**
 * 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 "scout_commodity.h"

extern struct ExecBase  *SysBase;

int  cxcnt;

APTR cxmoretext0,cxmoretext1,cxmoretext2,cxmoretext3,cxmoretext4,cxmoretext5;
APTR cxsublist;

struct Remember *CxRememberKey;

static struct MyCxObj {
   struct Node     mco_Node;
   UBYTE           mco_Flags;
   UBYTE           mco_dummy1;
   struct MinList  mco_SubList;
   APTR            mco_dummy2;
   char            mco_Name[CBD_NAMELEN];
   char            mco_Title[CBD_TITLELEN];
   char            mco_Descr[CBD_DESCRLEN];
   struct Task *   mco_Task;
   struct MsgPort *mco_Port;
   ULONG           mco_dummy3;
   WORD            mco_dummy4;
};

char * GetCxNodeType (UBYTE type) {
   char *CxNodeTypeText[] = {
      "Invalid","Filter","Typefilter","Send",
      "Signal","Translate","Broker","Debug",
      "Custom","Zero","< ??? >"
   };

   if(type>CX_ZERO)
      return("< ??? >");
   else
      return(CxNodeTypeText[type]);
}

__asm LONG cxlist_dspfunc(register __a2 char **array, register __a1 struct CxEntry *cxentry, register __a0 struct Hook *hook) {
   if (cxentry) {
      *array++ = cxentry->cxe_address;
      *array++ = cxentry->cxe_type;
      *array++ = cxentry->cxe_pri;
      *array++ = cxentry->cxe_flags;
      *array++ = cxentry->cxe_port;
      *array   = cxentry->cxe_name;
   } else {
      *array++ = ESC "bAddress";
      *array++ = ESC "bln_Type";
      *array++ = ESC "bln_Pri";
      *array++ = ESC "bFlags";
      *array++ = ESC "bPort";
      *array   = ESC "bName";
   }
   return (0);
}

struct Hook cxlist_dsphook = {
 {NULL, NULL},
 (ULONG (* )())cxlist_dspfunc,
 NULL, NULL
};

void FreeCx (void) {
   MyFreeStructs (&CxRememberKey, cxtext, cxlist);
}

void GetCxEntry (struct CxEntry *cxentry, struct MyCxObj *bc) {

   if (! cxentry->cxe_adr) {
      cxentry->cxe_adr = (char *)bc;

      sprintf (cxentry->cxe_address, "$%08lx", bc);
      strcpy (cxentry->cxe_type, GetCxNodeType (CxObjType((CxObj *)bc)));
   }

   sprintf (cxentry->cxe_pri, "%4ld ", bc->mco_Node.ln_Pri);
   strcpy (cxentry->cxe_name, bc->mco_Name);
   strcpy (cxentry->cxe_title, bc->mco_Title);
   strcpy (cxentry->cxe_descr, bc->mco_Descr);
   sprintf (cxentry->cxe_task, "$%08lx", bc->mco_Task);
   sprintf (cxentry->cxe_port, "$%08lx", bc->mco_Port);
   sprintf (cxentry->cxe_unique, "$%08lx", bc->mco_dummy3);
   sprintf (cxentry->cxe_flags, "$%02lx", bc->mco_Flags);
}

int GetCx (struct CxEntry **first) {
   struct   CxEntry   *cxentry,*previous = NULL;

   int cxcnt = 0;
   *first = 0;

   if (clientstate) {
      if (SendDaemon ("GetCxList")) {
         while ((cxentry = AllocRemember (&CxRememberKey, sizeof (struct CxEntry), MEMF_ANY|MEMF_CLEAR)) \
           && (ReceiveDecodedEntry ((UBYTE *) cxentry, sizeof (struct CxEntry)))) {
            IsHex (cxentry->cxe_address, (long *) &cxentry->cxe_adr);

            if (! *first)
               *first = cxentry;
            if (previous)
               previous->cxe_next = cxentry;

            cxcnt++;
            previous = cxentry;
         }
      }
   } else {
      struct MsgPort *cxport;
      struct NewBroker cxnewbroker =
      {
        NB_VERSION,
        "« Scout Dummy »",
        "« Scout Dummy »",
        "Dummy Broker",
        0,
        0,
        0,
        NULL,
        0
      };
      struct MyCxObj *cxbroker;
      struct Node *broker;

      if(cxport = CreateMsgPort()) {
         cxnewbroker.nb_Port = cxport;
         if(cxbroker = (struct MyCxObj *)CxBroker(&cxnewbroker,NULL)) {
            Forbid();
              for(broker=&cxbroker->mco_Node; broker->ln_Pred; broker=broker->ln_Pred);   /* Search the list head */
              for(broker=broker->ln_Succ; broker->ln_Succ; broker=broker->ln_Succ) {
                 if(broker==(struct Node *)cxbroker) continue;                            /* Skip own dummy broker */
                 if(cxentry = AllocRemember (&CxRememberKey, sizeof(struct CxEntry), MEMF_ANY|MEMF_CLEAR)) {
                    GetCxEntry (cxentry,(struct MyCxObj *)broker);

                    if (! *first)
                       *first = cxentry;
                    if (previous)
                       previous->cxe_next = cxentry;

                    cxcnt++;
                    previous = cxentry;
                 }
              }
            Permit();
            DeleteCxObjAll((CxObj *)cxbroker);
         }
         DeleteMsgPort(cxport);
      }
   }
   return (cxcnt);
}

void PrintCx (char *filename) {
   int   i=1;
   BPTR  handle;
   struct CxEntry *entryp;

   handle = HandlePrintStart (filename);
   if ((handle) && (PrintOneLine (handle, "\n  Address  Type     Pri Flags  Port      Name\n\n"))) {
      if (! WI_Cx) {
         i = GetCx (&entryp);
      }
      if (i) {
         for (i=0;;i++) {
            if (WI_Cx)
               DoMethod (cxlist,MUIM_List_GetEntry,i,&entryp);
            if (!entryp) break;

            sprintf (tmpstr2, " %ls %-7.7ls %3ls %3ls   %ls %ls\n", entryp->cxe_address, entryp->cxe_type, entryp->cxe_pri, entryp->cxe_flags, entryp->cxe_port, entryp->cxe_name);
            if (! (PrintOneLine (handle, tmpstr2)))
               break;

            if (! WI_Cx)
               entryp = entryp->cxe_next;
         }
      }
   }
   HandlePrintStop();
}

void ShowCx (void) {
   struct   CxEntry   *cx;

   ApplicationSleep();
   set(cxlist,MUIA_List_Quiet,TRUE);
   set(cxlist,MUIA_List_CompareHook,cxlist_cmphook_ptr);
   set(BT_CxRemove, MUIA_Disabled, TRUE);
   set(BT_CxPriority, MUIA_Disabled, TRUE);
   set(BT_CxMore, MUIA_Disabled, TRUE);
   set(BT_CxAppear, MUIA_Disabled, TRUE);
   set(BT_CxDisappear, MUIA_Disabled, TRUE);
   set(BT_CxEnable, MUIA_Disabled, TRUE);
   set(BT_CxDisable, MUIA_Disabled, TRUE);
   set(BT_CxKill, MUIA_Disabled, TRUE);
   set(BT_CxListChg, MUIA_Disabled, TRUE);
   set(BT_CxUnique, MUIA_Disabled, TRUE);
   FreeCx();

   cxcnt = GetCx (&cx);

   while (cx) {
      InsertSortedEntry (cxlist, (APTR *) &cx);
      cx = cx->cxe_next;
   }

   SetCountText (cxcount, cxcnt);
   AwakeApplication();
   set(cxlist,MUIA_List_Quiet,FALSE);
}

void SendCxList (void) {
   struct   CxEntry   *cx;

   FreeCx();
   GetCx (&cx);

   while (cx) {
      SendEncodedEntry ((UBYTE *) cx, sizeof (struct CxEntry));
      cx = cx->cxe_next;
   }
   FreeCx();
}

__asm LONG cxmore_dspfunc(register __a2 char **array, register __a1 struct CxSubEntry *subentry, register __a0 struct Hook *hook) {
   if (subentry) {
      *array++ = subentry->cse_address;
      *array++ = subentry->cse_type;
      *array   = subentry->cse_pri;
   } else {
      *array++ = ESC "bAddress";
      *array++ = ESC "bln_Type";
      *array   = ESC "bln_Pri";
   }
   return (0);
}

struct Hook cxmore_dsphook = {
 {NULL, NULL},
 (ULONG (* )())cxmore_dspfunc,
 NULL, NULL
};

void GetSubList (struct MyCxObj *cxo, struct Remember **remkey) {
   struct CxSubEntry  *subentry;
   struct Node *node;

   set(cxsublist,MUIA_List_Quiet,TRUE);

   for(node=(struct Node *)cxo->mco_SubList.mlh_Head; node->ln_Succ; node=node->ln_Succ)
   {
      if(subentry = AllocRemember (remkey, sizeof (struct CxSubEntry), MEMF_ANY|MEMF_CLEAR)) {
         sprintf (subentry->cse_address, "$%08lx", node);
         strcpy  (subentry->cse_type   , GetCxNodeType(CxObjType((CxObj *)node)));
         sprintf (subentry->cse_pri    , "%ld", node->ln_Pri);

         InsertBottomEntry (cxsublist, (APTR *) &subentry);
      }
   }

   set(cxsublist,MUIA_List_Quiet,FALSE);
}

void GetCxMore (struct MyCxObj *bc) {
   unsigned char     *title = "COMMODITY: ";
   struct   WinFree  *ptr;
   struct MsgPort *cxport;
   struct NewBroker cxnewbroker =
   {
     NB_VERSION,
     "« Scout Dummy »",
     "« Scout Dummy »",
     "Dummy Broker",
     0,
     0,
     0,
     NULL,
     0
   };
   struct MyCxObj *cxbroker;
   struct Node *broker;
   BOOL found = FALSE;

   if(cxport = CreateMsgPort()) {
      cxnewbroker.nb_Port = cxport;
      if(cxbroker = (struct MyCxObj *)CxBroker(&cxnewbroker,NULL)) {
         Forbid();
           for(broker=&cxbroker->mco_Node; broker->ln_Pred; broker=broker->ln_Pred);   /* Search the list head */
           for(broker=broker->ln_Succ; broker->ln_Succ; broker=broker->ln_Succ) {
              if(broker==(struct Node *)cxbroker) continue;                            /* Skip own dummy broker */
              if(broker==(struct Node *)bc) {
                 found = TRUE;
                 break;
              }
           }
         Permit();
         DeleteCxObjAll((CxObj *)cxbroker);
      }
      DeleteMsgPort(cxport);
   }

   if (found && (ptr = AllocWinFree())) {
      ptr->wf_Window = (APTR) WindowObject,
      MUIA_HelpNode, CommoditiesText,
      MUIA_Window_ID, MakeDetailID('.','C','X','X'),
      WindowContents, VGroup,
         Child, ColGroup(2),
            Child, MyLabel2 ("Name:"),
            Child, cxmoretext0 = MyTextObject(),
            Child, MyLabel2 ("Title:"),
            Child, cxmoretext1 = MyTextObject(),
            Child, MyLabel2 ("Descr:"),
            Child, cxmoretext2 = MyTextObject(),
         End,
         Child, HGroup, MUIA_Group_SameWidth, TRUE,
            Child, ColGroup(2),
               Child, MyLabel2 ("Address:\nType:\nPri:\nTask:\nPort:"),
               Child, cxmoretext3 = MyTextObject2(),
               Child, MyLabel2 ("Flags:"),
               Child, cxmoretext4 = KeyButtonF ('b', bc->mco_Flags),
            End,
            Child, ColGroup(2),
               Child, MyLabel2 ("\nSub CxObj:\n\n\n\n"),
               Child, cxsublist = ListviewObject,
                  MUIA_Listview_Input, FALSE,
                  MUIA_Listview_List, ListObject,
                     MUIA_List_Format, "DELTA=8,DELTA=8 P=\33c,P=\33c",
                     MUIA_List_Title, TRUE,
                     MUIA_List_DisplayHook, &cxmore_dsphook,
                     ReadListFrame,
               End, End,
            End,
         End,
         Child, HGroup,
            Child, MyLabel2 ("TaskName:"),
            Child, cxmoretext5 = MyTextObject(),
         End,
      End, End;

      if (ptr->wf_Window) {
         MySetContents (cxmoretext0, "%s", bc->mco_Name);
         MySetContents (cxmoretext1, "%s", bc->mco_Title);
         MySetContents (cxmoretext2, "%s", bc->mco_Descr);
         MySetContents (cxmoretext3, ESC "r$%08x\n" ESC "c%s\n%d\n" ESC "r$%08x\n$%08x", bc, GetCxNodeType(CxObjType((CxObj *)bc)),bc->mco_Node.ln_Pri, bc->mco_Task, bc->mco_Port);
         MySetContentsHealed (cxmoretext5, "%s", nonetest (GetTaskName (bc->mco_Task)));

         GetSubList (bc, &ptr->wf_RememberKey);

         HandleFlagsButtonPressed (cxmoretext4, ptr, "(COMMODITY)", "Flags", bc->mco_Flags, (struct LongFlag *) &bc_flags, NULL, 'b');
         HandleWindowOpen (ptr, title, bc->mco_Name);
         set (ptr->wf_Window,MUIA_Window_ActiveObject,cxsublist);
         HandleWindowClose (ptr);
      }
   }
}

