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

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

#include <clib/AMarquee_protos.h>
#include <pragmas/AMarquee_pragmas.h>

#define UNLESS(x) if(!(x))

struct Library * AMarqueeBase = NULL;
struct QSession * session     = NULL;

void CleanExit(void)
{
  if (session)      QFreeSession(session);       /* This MUST be done before we close the library! */
  if (AMarqueeBase) CloseLibrary(AMarqueeBase);
  printf("Program complete.\n");
}

/* Parses out the nth section of the given path string.  
   May write a NUL to the string to terminate the part, but with 
   amarquee.library that's okay behavior. */
char * GetNthPart(char * path, int n)
{
  char * temp = path;
  
  while((n--)>0)
  { 
    temp++; path = temp;
    UNLESS(temp = strchr(temp, '/')) return(path);
  }
  *temp = '\0';
  return(path);
}

/* There is a problem in this function:  any "regular" update
   messages that arrive while this function is waiting for info
   will be silently thrown away.  This should be fixed but I'm
   too lazy!  :P  */
/* Returns TRUE on completion, FALSE on error */
BOOL ListPeopleInRoom(void)
{
  int getop  = QGetOp(session, "/#?/mini_irc_#?", 0);
  int pingop = QPingOp(session);
  int retVal = -1;
  ULONG signals = (1L << session->qMsgPort->mp_SigBit) | (SIGBREAKF_CTRL_C);
    
  UNLESS((getop)&&(pingop)&&(QGo(session,0L))) return(FALSE);
  
  /* Now wait for data to come back! */
  printf("People currently in the room:--------\n");

  /* Wait for next message from the server */
  while(retVal == -1)
  {
    signals = Wait(signals);
    
    if (signals & (1L << session->qMsgPort->mp_SigBit))
    {
      struct QMessage * qMsg;
            
      while((retVal == -1)&&(qMsg = (struct QMessage *) GetMsg(session->qMsgPort)))
      {
        if (qMsg->qm_Status != QERROR_NO_ERROR) 
        {
          printf("-->Error %i detected, exiting!\n", qMsg->qm_Status);
          retVal = FALSE;
        }
        else
        {
          char * name = qMsg->qm_Path ? (GetNthPart(qMsg->qm_Path, 2)+sizeof("mini_irc_")-1) : "<unknown?>";
          
          if (qMsg->qm_ID == getop) printf("  %s\n",name);
          if (qMsg->qm_ID == pingop) retVal = TRUE;  /* we're done! */
        }
        FreeQMessage(session,qMsg);
      }
    }
    if (signals & SIGBREAKF_CTRL_C) retVal = FALSE;
  }
  printf("---------End of people list----------\n");
  return(retVal);
}


/* Main program--simply increments our counter whenever someone else increments theirs */
int main(int argc, char ** argv)
{
  char * connectTo, * username;
  int port = 2957;
  int clientOp, actionOp, talkOp;
  char buf[900];
  
  atexit(CleanExit);
    
  if (argc < 2) 
  {
    printf("Usage:  MiniIRC hostname [nickname]\n");
    exit(RETURN_WARN);
  }
  connectTo = argv[1] ? argv[1] : "localhost";
  username = argv[2] ? argv[2] : NULL;
  
  /* Try a few guesses here! */
  if (username == NULL) username = getenv("logname");
  if (username == NULL) username = getenv("user");
  if (username == NULL) username = getenv("username");
  if (username == NULL) username = "unknown";
  
  UNLESS(AMarqueeBase = OpenLibrary("amarquee.library",37L))
  {
    printf("Couldn't open amarquee.library v37!\n");
    exit(RETURN_ERROR);
  }
  printf("Connecting to %s:%i...\n",connectTo, port);
  sprintf(buf, "mini_irc_%s",username);
  UNLESS(session = QNewSession(connectTo, port, buf))
  {
    printf("Couldn't connect to server %s:%i\n",connectTo, port);
    CloseLibrary(AMarqueeBase);
    exit(RETURN_WARN);
  }
  
  printf("MiniIRC: connected to server %s:%i as %s.\n", connectTo, port, username);

  /* Setup--put in our interests!  */
  UNLESS((clientOp = QSubscribeOp(session, "/#?/mini_irc_#?",        0))   &&
         (actionOp = QSubscribeOp(session, "/#?/mini_irc_#?/action", 900)) &&
         (talkOp   = QSubscribeOp(session, "/#?/mini_irc_#?/talk",   900)) &&
         (QGo(session,0L)))
  {
    printf("-->error setting up!\n");
    exit(5);
  }
         
  printf("Press CTRL-D when you wish to do something, or\n");
  printf("Press CTRL-E to list the names of everyone in the room.\n");
  printf("Press CTRL-F when you wish to say something!\n");
  printf("Press CTRL-C to quit.\n");
  printf("==============================================\n");  
  
  Signal(FindTask(NULL), SIGBREAKF_CTRL_E);  /* cause an immediate listing of who is in the room */
  
  while(1)
  {
    struct QMessage * qMsg;
    ULONG signals = (1L << session->qMsgPort->mp_SigBit) | (SIGBREAKF_CTRL_C) | (SIGBREAKF_CTRL_D) | (SIGBREAKF_CTRL_E) | (SIGBREAKF_CTRL_F);

    /* Wait for next message from the server */
    signals = Wait(signals);
    
    if (signals & (1L << session->qMsgPort->mp_SigBit))
    {
      BOOL BDie = FALSE;
      
      while(qMsg = (struct QMessage *) GetMsg(session->qMsgPort))
      {
        if (qMsg->qm_Status != QERROR_NO_ERROR) 
        {
          printf("-->Error %i detected, exiting!\n", qMsg->qm_Status);
          BDie = TRUE;
        }
        else
        {
          char * name = qMsg->qm_Path ? (GetNthPart(qMsg->qm_Path, 2)+sizeof("mini_irc_")-1) : "<unknown?>";
          char * data = (char *) qMsg->qm_Data;
          int id      = qMsg->qm_ID;
                    
               if ((id == clientOp))         printf("%s has just %s the room.\n", name, qMsg->qm_Data?"entered":"left");
          else if ((id == actionOp)&&(data)) printf("%s %s.\n", name, data);
          else if ((id == talkOp)&&(data))   printf("%s: %s\n", name, data);
        }
        FreeQMessage(session,qMsg);
      }
      if (BDie) break;
    }
    if (signals & SIGBREAKF_CTRL_C) break;
    if (signals & SIGBREAKF_CTRL_D)
    {
      char buf[900];
        
      printf("==> Enter your action: "); fflush(stdout);
      gets(buf);
      UNLESS((QSetOp(session, "action", buf, strlen(buf)+1))&&(QGo(session, 0L)))
        printf("-->Error sending your action!\n");
    }
    if ((signals & SIGBREAKF_CTRL_E)&&(ListPeopleInRoom() == FALSE)) break;
    if (signals & SIGBREAKF_CTRL_F)
    {
      char buf[900];
        
      printf("==> Enter your message: "); fflush(stdout);
      gets(buf);
      UNLESS((QSetOp(session, "talk", buf, strlen(buf)+1))&&(QGo(session, 0L)))
        printf("-->Error sending your line!\n");
    }
  }
  
  /* Note: CleanExit() is called here, via the atexit() function! */
}