/*****************************************************************************
*   Routines to handle I/O of objects through Exec message ports             *
*   Server side.                                                             *
*                                                                            *
* Written by:  Kriton Kyrimis                                                *
*        and   Gershon Elber                        Ver 0.2, December 1993.  *
*****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <dos/dostags.h>

#ifdef __SASC
#include <dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#endif

#ifdef __GNUC__
#include <dos/dos.h>
#include <dos/var.h>
#include <inline/dos.h>
#include <inline/exec.h>
#endif

#include "irit_sm.h"
#include "irit_soc.h"

#include "amiga.h"

static struct MsgPort *port = NULL;
static struct MsgPort *replyport = NULL;
static int Active = FALSE;
static int GlblBinaryIPC = FALSE;

/*****************************************************************************
*  Sets up the port. Returns TRUE if successful.                             *
*****************************************************************************/
int SocServerCreateSocket(void)
{
    char *name;

    GlblBinaryIPC = getenv("IRIT_BIN_IPC") != NULL;

    name = getenv("IRIT_SERVER_PORT");
    if (!name) {
	name = IRIT_SERVER_PORT;
    }
    port = CreateMsgPort();
    if (port) {
	port->mp_Node.ln_Name = name;
	port->mp_Node.ln_Pri = 0;
	AddPort(port);
	replyport = CreateMsgPort();
	if (!replyport) {
	    RemPort(port);
	    DeleteMsgPort(port);
	    port = NULL;
	    return FALSE;
	}else{
	    return TRUE;
	}
    }else{
	return FALSE;
    }
}

/*****************************************************************************
*  Returns TRUE if connection is active.                                     *
*****************************************************************************/
int SocServerActive(void)
{
  return (Active);
}

/*****************************************************************************
*  Close the port.                                                           *
*****************************************************************************/
void SocServerCloseSocket(void)
{
    if (port) {
	RemPort(port);
	DeleteMsgPort(port);
	port = NULL;
	if (replyport) {
	    DeletePort(replyport);
	}
    }
    Active = FALSE;
}

/*****************************************************************************
* Block until the client program starts.                                     *
*****************************************************************************/
void SocServerAcceptConnection(void)
{
    int len = -1;
    char buf[4];

    buf[0] = '\0';
    while (len < 0) {
	len = GetVar(CLIENT_VAR, buf, sizeof(buf), GVF_GLOBAL_ONLY);
        if (len < 0) {
#ifdef __SASC
	    chkabort();
#endif
	    Delay(50L);
        }
    }
    DeleteVar(CLIENT_VAR, GVF_GLOBAL_ONLY);
}

/****************************************************************************
* Attempt to write an object to the pipe.                                   *
****************************************************************************/
void SocServerWriteOneObject(IPObjectStruct *PObj)
{
    char *DisplayProg, *ErrorMsg;
    BPTR f;
    char buf[4];

    if (!Active) {
        int HaveDisplay;

	SetVar(SERVER_VAR, buf, -1, GVF_GLOBAL_ONLY);

        /* Needs to start up the client display - it is not up yet */
        DisplayProg = getenv("IRIT_DISPLAY");
        if (DisplayProg == NULL) {
            DisplayProg = "amidrvs -s-";
        }
	f = Open("*", MODE_OLDFILE);
	HaveDisplay = !SystemTags(DisplayProg, SYS_Input,  NULL,
					       SYS_Output, f,
					       SYS_Asynch, TRUE,
					       TAG_END);
	/* SystemTags will always return success for programs run
	   asynchronously, so wait a bit and then check if the synchronization
	   environment variable created by the client exists. If not, we
	   probably failed to start the program.
	*/
	Delay(50L);
	if (GetVar(CLIENT_VAR, buf, sizeof(buf), GVF_GLOBAL_ONLY) < 0) {
	    HaveDisplay = FALSE;
	}
	if (!HaveDisplay) {
	    fprintf(stderr,
		    "Irit: Startup your display device - I am waiting...\n");
	}
	SocServerAcceptConnection();
	fprintf(stderr, "Irit: Connection with client established.\n");
	Active = TRUE;
    }

    IritPrsrWriteSocket(TRUE);
    if (GlblBinaryIPC) {
        IritPrsrPutBinObject(NULL, PObj);
    }
    else {
	IritPrsrPutObject(NULL, PObj);
    }
    IritPrsrWriteSocket(FALSE);

    if (IritPrsrParseError(&ErrorMsg)) {
        fprintf(stderr, "Socket: %s\n", ErrorMsg);
    }
}

/*****************************************************************************
*  Write a single line of line length characters.                            *
*****************************************************************************/
void SocServerWriteLine(char *Line, int LineLen)
{
    struct IritMessage msg;

    msg.msg.mn_Node.ln_Type = NT_MESSAGE;
    msg.msg.mn_ReplyPort = replyport;
    for (; LineLen>0; LineLen-=msg.nbytes, Line+=msg.nbytes) {
	msg.nbytes = (LineLen > MSGSIZE) ? MSGSIZE : LineLen;
	memcpy(msg.txt, Line, msg.nbytes);
	msg.msg.mn_Length = sizeof(struct IritMessage) - MSGSIZE + msg.nbytes;
	PutMsg(port, (struct Message *)&msg);
	WaitPort(replyport), (void)GetMsg(replyport);
    }
}
