/* AmiTrackShared.c -- Shared functions between client and server */

#define __DICE_C

#define __stdargs

#include "QAmiTrackShared.h"
#include "TrackRexx.h"

#include <devices/timer.h>

extern struct Library * IntuitionBase;

struct Library * TimerBase = NULL;

static ULONG trackFlags = 0L;

void TrackExit(char * szMessage, int nCode)
{
	if (nCode > 0) 
	{
	  char temp[300];
	  
	  sprintf(temp, "Exiting, code %i: [%s]",nCode, szMessage);
	  printf("%s\n",temp);
	  
	  if (IntuitionBase) MakeReq("QAmiTrack Exiting Due to Error", temp, "Okay");
	}
	exit(nCode);
}

void SetTrackFlag(ULONG flag)
{
  trackFlags |= flag;
}

BOOL CheckTrackFlag(ULONG flag)
{
  BOOL ret = ((trackFlags & flag) != 0L);
  trackFlags &= ~flag;
  return(ret);
}

BOOL TrackFlagsSet()
{
  return(trackFlags != 0L);
}


/* Wait for incoming packets or other relevant events */
/* Returns a chord of event codes.  May exit if a CTRL-C is detected. */
void TrackWait(struct WindowStuff * Window, struct QSession * session, struct RexxHost * host, struct CxStuff * cx, struct TimerStuff * ts)
{
	ULONG ulMask = 
	    (Window  ? (1L<<Window->win->UserPort->mp_SigBit) : 0L) | 
		(session ? (1L<<session->qMsgPort->mp_SigBit)     : 0L) |
		(host    ? (1L<<host->port->mp_SigBit)            : 0L) |
		(cx      ? (1L<<cx->port->mp_SigBit)              : 0L) |
        (ts      ? (1L<<ts->TimerMP->mp_SigBit)           : 0L) | 
		SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F;
		
	ulMask = Wait(ulMask);
	
	if (ulMask & SIGBREAKF_CTRL_C) SetTrackFlag(CODE_QUIT);
	if (ulMask & SIGBREAKF_CTRL_D) SetTrackFlag(CODE_TIMER);
	if (ulMask & SIGBREAKF_CTRL_E) SetTrackFlag(CODE_HIDE);	
	if (ulMask & SIGBREAKF_CTRL_F) SetTrackFlag(CODE_SHOW);	
	
    if ((ts)&&(ulMask & (1L<<ts->TimerMP->mp_SigBit))) SetTrackFlag(CODE_TIMER); 
	if ((Window)&&(ulMask & (1L<<Window->win->UserPort->mp_SigBit))) SetTrackFlag(CODE_WINDOW_EVENT);
	if ((session)&&(ulMask & (1L<<session->qMsgPort->mp_SigBit))) SetTrackFlag(CODE_QMESSAGE);
	if ((host)&&(ulMask & (1L<<host->port->mp_SigBit))) SetTrackFlag(CODE_AREXX);
	if ((cx)&&(ulMask & (1L << cx->port->mp_SigBit)))
	{
	  CxMsg * msg;
	  
	  while (msg = (CxMsg *) GetMsg(cx->port))
	  {
	    ULONG msgid   = CxMsgID(msg);
	    ULONG msgtype = CxMsgType(msg);
	    ReplyMsg((struct Message *) msg);
	    
	    if (msgtype == CXM_COMMAND)
	    {
	      switch(msgid)
	      {
	        case CXCMD_DISABLE:   SetTrackFlag(CODE_DISABLE); break;
	        case CXCMD_ENABLE:    SetTrackFlag(CODE_ENABLE);  break;
	        case CXCMD_DISAPPEAR: SetTrackFlag(CODE_HIDE);    break;
	        case CXCMD_UNIQUE:    /* drop through to... */
	        case CXCMD_APPEAR:    SetTrackFlag(CODE_SHOW);    break;
	        case CXCMD_KILL:      SetTrackFlag(CODE_QUIT);    break;
	      }
	    }
	    else if (msgtype == CXM_IEVENT)
	    {
          switch(msgid)
          {
            case EVT_HOTKEY:      SetTrackFlag(CODE_SHOW);    break;
            default: printf("Warning:  I'm getting unknown CxEvents!\n");
          }
	    }
	    else printf("warning: I'm getting uncalled for CxMessages!\n");
	  }
	}
}


/* if ts is NULL, allocates and returns all the TimerStuff you need (or NULL on failure) */
/* If ts is non-NULL, frees everything in ts, and returns NULL. */
struct TimerStuff * SetupTimer(struct TimerStuff * ts)
{
	#ifdef __DICE_C
	/* DICE seems to have a bug in it that makes it require this...
	   otherwise tv_secs and tv_micro aren't recognized!  :( */
	struct timeval {
		ULONG tv_secs;
		ULONG tv_micro;
	};
	#endif
		
	if (ts)
	{
		/* Deallocate everything! */
		if (ts->TimerIO)
		{
			if (ts->BDevOpen) 
			{
				if (!(CheckIO((struct IORequest *)ts->TimerIO)))
        			{
        				AbortIO((struct IORequest *)ts->TimerIO);   /* Ask device to abort any pending requests */
					WaitIO((struct IORequest *)ts->TimerIO);    /* proceed when ready */
				}
		        	CloseDevice((struct IORequest *) ts->TimerIO);
		        }
        		DeleteExtIO((struct IORequest *) ts->TimerIO);
        	}
	        if (ts->TimerMP) DeletePort(ts->TimerMP);
	        FreeMem(ts, sizeof(struct TimerStuff));
	        return(NULL);
	}
	else
	{
		/* Set up the timer.device */
		UNLESS(ts = AllocMem(sizeof(struct TimerStuff), MEMF_CLEAR)) return(NULL);
		UNLESS((ts->TimerMP   = CreatePort(0,0))
	            && (ts->TimerIO   = (struct timerequest *) CreateExtIO(ts->TimerMP, (sizeof (struct timerequest))))
	            && (ts->BDevOpen  = (0 == OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)ts->TimerIO,0))))
	            	return(SetupTimer(ts));
		
		TimerBase = (struct Library *) ts->TimerIO->tr_node.io_Device;
		ts->TimerIO->tr_node.io_Message.mn_ReplyPort = ts->TimerMP;
		ts->TimerIO->tr_node.io_Command  = TR_ADDREQUEST;
		ts->TimerIO->tr_node.io_Flags 	 = 0;
		ts->TimerIO->tr_node.io_Error 	 = 0;
		ts->TimerIO->tr_time.tv_secs  	 = 0;
		ts->TimerIO->tr_time.tv_micro 	 = 0; 	
		return(ts);
	}
}


int MakeReq(char *sTitle, char *sText, char *sGadgets)
{
	struct EasyStruct myreq;
	int nResult;

	UNLESS(sTitle)   sTitle   = "QAmiTrack Message";
	UNLESS(sText)    sText    = "Check this out!";
	UNLESS(sGadgets) sGadgets = "OK";

	myreq.es_TextFormat   = sText;
	myreq.es_Title        = sTitle;
	myreq.es_GadgetFormat = sGadgets;

	nResult = EasyRequest(NULL, &myreq, NULL, NULL, NULL);

	return(nResult);
}


/* Returns a pointer to the first non-space character in the string */
char * PastSpaces(char * pcString)
{
	while(1) 
	{
		if (*pcString == ' ') pcString++;
				 else return(pcString); 
	}
}


/* Chops off any trailing blanks and returns the string */
char * RemoveTrailingSpaces(char * pcString)
{
	char * pcTemp = strchr(pcString,'\0');
	
	pcTemp--;
	while((pcTemp > pcString)&&(*pcTemp == ' ')) pcTemp--;
	pcTemp++;
	
	*pcTemp = '\0';
	
	return(pcTemp);
}


/* Replaces all unprintable characters in pcString with ' ' */
/* Hopefully this will stop people from sending e.g. "talkbombs" */
/* Returns pcString. */
char * RemoveUnprintableChars(char * pcString)
{
	UBYTE * pcTemp = pcString;
	
	while(*pcTemp)
	{
		if (*pcTemp < ' ') *pcTemp = ' ';
		pcTemp++;
	}
	return(pcString);
}


/* Makes pcString lower case */
char * ToLower(char * pcString)
{
	char * pcTemp = pcString;
	
	while(*pcTemp) 
	{
		if ((*pcTemp >= 'A')&&(*pcTemp <= 'Z'))
			*pcTemp += 'a'-'A';
		pcTemp++;
	}
	return(pcString);
}

/* Deallocate the old string, allocate the new string! */
/* Give it a pointer to the pointer to the old string, and a pointer to the new string */
/* Can also server to just deallocate the old, if the new string is NULL */
void ReplaceAllocedString(char ** szOldString, char * szNewString)
{
	char * pcTemp = NULL;

	UNLESS(szOldString) return;
	if (szNewString)
	{
		UNLESS(pcTemp = AllocMem(strlen(szNewString)+1, MEMF_ANY)) return;
		strcpy(pcTemp, szNewString);
	}
	if (*szOldString) FreeMem(*szOldString, strlen(*szOldString)+1);
	*szOldString = pcTemp;
	return;
}


/* Set/Reset timer.device to signal us in nSecs seconds + nMicros microseconds */
void SetTimer(struct TimerStuff * ts, int nSecs, int nMicros)
{
  /* First make sure there is no previous timer pending */
  if (!(CheckIO((struct IORequest *) ts->TimerIO)))
  {
    return;  /* Just ignore new request then */
    /* This way seems bugged! */
    /* AbortIO((struct IORequest *) ts->TimerIO); */
    /* WaitIO((struct IORequest *) ts->TimerIO);  */
  }
               
  ts->TimerIO->tr_time.tv_secs  = nSecs;                                        
  ts->TimerIO->tr_time.tv_micro = nMicros;
        
  /* Start ze timer */
  if ((nSecs > 0)||(nMicros > 0)) SendIO((struct IORequest *)ts->TimerIO);
}
