#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <dos/dos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>

// This is a version of AMarqueeDebug written to use the
// "Session" C++ wrapper class.  It should work more or
// less exactly the same as the original C version
// (amarqueedebug.c)

#include "include:signal.h"  // for sig_ign()

// Make sure you -I the directory where this file is!
#include "Session.h"

struct Library * AMarqueeBase = NULL;

/* Takes user input until blank line is typed */
void ProcessDebugCommands(Session & session)
{
  while(1)
  {
   char debugline[500] = "\0\0\0\0\0\0\0\0";
   char * keyword, * data;
   ULONG dataLen = 0L;
   LONG res;
   
   printf("Enter your debug command now: "); fflush(stdout);
   gets(debugline);
  
   keyword = &debugline[2];
   if (data = strchr(keyword,'='))
   {
     *data = '\0';  /* terminate the keyword */
     data++;
     dataLen = strlen(data)+1;
   }
   switch((int)(debugline[0]))
   {
     case '\0': res=session.go();                                break;
     case 'A':  res=session.setMessageAccessOp(keyword);         break;
     case 'm':  res=session.messageOp(keyword, data, dataLen);   break;
     case 'M':  res=session.sysMessageOp(keyword, data);         break;
     case 'a':  res=session.setAccessOp(keyword);                break;
     case 's':  res=session.setOp(keyword, data, dataLen);       break;
     case 'S':  res=session.streamOp(keyword, data, dataLen);    break;
     case 'r':  res=session.renameOp(keyword, data);             break;
     case 'D':  res=session.debugOp(keyword);                    break;
     case 'g':  res=session.getOp(keyword);                      break;
     case 'd':  res=session.deleteOp(keyword);                   break;
     case 'i':  res=session.infoOp();                            break;
     case 'c':  res=session.subscribeOp(keyword);                break;
     case 'C':  res=session.getAndSubscribeOp(keyword);          break;
     case 'k':  res=session.clearSubscriptionsOp(atoi(keyword)); break;
     case 'p':  res=session.pingOp();                            break;
     case 'v':  res=session.requestPrivilegesOp(atol(keyword));  break;
     case 'w':  res=session.releasePrivilegesOp(atol(keyword));  break;
     case '!':  res=session.killClientsOp(keyword);              break;
     case '?':  res=session.getParameterOp(keyword);             break;
     case '$':  res=session.setParameterOp(keyword,data);        break;
     default:   printf("Command code %c was not recognized.\n",debugline[0]); break;
   }
   printf("(Op result was %i)\n",res);
   if (debugline[0] == '\0') return;
  }
}


/* Main program */
int main(int argc, char ** argv)
{
  char * connectTo, * progName;
  int port;
    
  signal(SIGINT, SIG_IGN);  /* Don't let the compiler abort us abruptly on CTRL-C */

  printf("Usage Note:  AMarqueeDebug [hostname=localhost] [myname=debug] [port=2957]\n");    
  
  connectTo = (argc>1) ? argv[1] : "localhost";
  progName  = (argc>2) ? argv[2] : "debug";
  port      = (argc>3) ? atoi(argv[3]) : 2957;

  if ((AMarqueeBase = OpenLibrary("amarquee.library",46L)) == NULL)
  {
    printf("Couldn't open amarquee.library v46!\n");
    exit(RETURN_ERROR);
  }
  printf("Connecting to %s:%i\n",connectTo, port);

  try {
    Session session(connectTo, port, progName);  // Connect attempt happens here (disconnects when scope is exited)
    
    printf("Connected to server %s:%i\n",connectTo, port);

    printf("Commands are:\n");
    printf("\n");
    printf("a wildhostpath   Access control (default is /#?/#?)\n");
    printf("A wildhostpath   Access control for incoming messages (default in no access)\n");
    printf("m hosts=data     Send an active message to hosts\n");
    printf("M hosts=string   Send an system message to hosts\n");
    printf("s path=data      Set data node value\n");
    printf("S path=data      Stream data node value\n");
    printf("r path=newlabel  Rename data node\n");
    printf("D debugstring    Send debug string\n");
    printf("g wildpath       Get a node or nodes\n");
    printf("c wildpath       Subscribe to a node or nodes\n");
    printf("C wildpath       Get&Subscribe to a node or nodes\n");
    printf("k opID           Klear subscriptions (by id or 0 for all)\n");
    printf("d wildpath       Delete a node or nodes\n");
    printf("i                Request info packet\n");
    printf("p                Request ping packet\n");
    printf("v #              Request new privileges (by code bitchord)\n");
    printf("w #              Release existing privileges (by code bitchord)\n");
    printf("! hosts          Kill other clients (requires KILLCLIENTS privilege!)\n");
    printf("$ param=string   Set a parameter with setParam()\n");
    printf("? param          Get a parameter by name\n");
    printf("<enter>          Send accumulated transactions (GO!!)\n");
    printf("\n");
    printf("Press CTRL-F to enter commands, or CTRL-C to quit\n");
  
    while(1)
    {
      ULONG signals = (1L << session.getMsgPort()->mp_SigBit) | (SIGBREAKF_CTRL_C) | (SIGBREAKF_CTRL_F);

      /* Wait for next message from the server */
      signals = Wait(signals);
    
      if (signals & (1L << session.getMsgPort()->mp_SigBit))
      {
        struct QMessage * qMsg;
  
        while(qMsg = (struct QMessage *) GetMsg(session.getMsgPort()))
        {
          struct QRunInfo * inf = (qMsg->qm_DataLen == sizeof(struct QRunInfo)) ? ((struct QRunInfo *) qMsg->qm_Data) : NULL;

          /* Handle message */
          printf("Message %p recieved---------\n",qMsg);
          printf("Status:       %i (%s)\n",  qMsg->qm_Status, Session::getErrorName(qMsg->qm_Status));
          printf("Error Line:   %i\n",  qMsg->qm_ErrorLine);
          printf("Message ID:   %i\n",  qMsg->qm_ID);
          printf("Path:        [%s]\n", qMsg->qm_Path?qMsg->qm_Path:"<NULL>");
          printf("Data:        [%s](int=%i)\n", qMsg->qm_Data?qMsg->qm_Data:((UBYTE*)"<NULL>"),qMsg->qm_Data?(*((int*)qMsg->qm_Data)):0);
          printf("DataLen:      %lu\n", qMsg->qm_DataLen);
          printf("ActualLen:    %lu\n", qMsg->qm_ActualLen);

          if (inf) printf("Info: alloced:%li allowed:%li avail:%li curPrivs=0x%x posPrivs=0x%x\n",
            inf->qr_Alloced, inf->qr_Allowed, inf->qr_Avail, inf->qr_CurrentPrivs, inf->qr_PossiblePrivs); 
          
          session.freeQMessage(qMsg);
        }
      }
      if (signals & SIGBREAKF_CTRL_F) ProcessDebugCommands(session);
      if (signals & SIGBREAKF_CTRL_C) break;  /* Quit if CTRL-C pressed */
    }
  }
  catch(SessionCreationFailedException)
  {
    printf("Error, AMarquee connection couldn't be made.\n");
  }  
  CloseLibrary(AMarqueeBase);  
}
