/*
 *  Routines for the purpose of X-DOS talking to a TSR as a client.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <i86.h>
#include "X.h"
#define NEED_EVENTS
#include "Xproto.h"
#include "misc.h"
#include "dixstruct.h"
#include "osdep.h"
#include "funcs.h"

#define FUNC_STARTUP	0x01
#define FUNC_SHUTDOWN	0x02
#define FUNC_XEVENT	0x03
#define FUNC_PROCESSED	0x04

struct client_buf {
    unsigned char type;
#define TYPE_FREE	0
#define TYPE_STARTUP	1
#define TYPE_XREQUEST	2
#define TYPE_XREPLY	3
#define TYPE_XERROR	4
    unsigned char pad;
    unsigned short length;	/* length of data in bytes */
    unsigned long data[];
};

struct client_startup {
	Window root;
};

static unsigned char to_tsr;
static int buf_size = 512;

static struct client_buf _far *client_buf = 0;
static xEvent _far *client_xe = 0;
static unsigned short client_seg = 0;
static char _far *client_out;

void
client_init(vec)
char *vec;
{
    char *cp;
    union REGS regs;

    to_tsr = (unsigned char)strtoul(vec, &cp, 0);

    if (!to_tsr)
	return;

    /* Allocate some DOS memory. */
    regs.w.ax = 0x100;
    regs.w.bx = (buf_size + 15)/16 + sizeof (xEvent) / 16;
    int386(0x31, &regs, &regs);
    if (regs.w.cflag) {
	printf("client_init: can't allocate buffer memory\n");
	return;
    }
    client_seg = regs.w.ax;
    client_buf = MK_FP(regs.w.dx, 0);
    client_xe = (xEvent _far *)((char _far *)client_buf + buf_size);
#ifdef notdef
printf("TSR started buf=%#x:%#x client_xe=%#x:%#x\n", FP_SEG(client_buf), FP_OFF(client_buf), FP_SEG(client_xe), FP_OFF(client_xe));
#endif
}

extern int (  * ProcVector[256]) (ClientPtr);

void
client_open(root)
Window root;
{
    struct client_startup _far *start;

    if (client_buf == 0)
	return;

    serverClient->sequence = 0;

    client_buf->type = TYPE_STARTUP;
    client_buf->length = buf_size - sizeof (*client_buf);
    start = (struct client_startup _far *)client_buf->data;
    start->root = root;
    client_send(FUNC_STARTUP << 8, client_buf, buf_size);
#ifdef notdef
fp = client_open;
printf("sent FUNC_STARTUP: client_open=%#x:%#x\n", FP_SEG(fp), FP_OFF(fp));
#endif
}

void
client_close()
{
    union REGS regs;

    if (!client_seg)
	return;
    client_send(FUNC_SHUTDOWN << 8, client_buf, buf_size);
    client_buf = 0;
    client_xe = 0;
    /* Free the DOS memory. */
    regs.w.ax = 0x101;
    regs.w.dx = client_seg;
    int386(0x31, &regs, &regs);
    client_seg = 0;
}

struct rminfo {
    long	edi, esi, ebp, res;
    long	ebx, edx, ecx, eax;
    unsigned short	flags;
    unsigned short	es, ds, fs, gs, ip, cs, sp, ss;
};

static void
client_send(func, buf, size)
int func;
void _far *buf;
int size;
{
    struct SREGS sregs;
    union REGS regs;
    struct rminfo rmi;

#ifdef notdef
printf("int TSR func=%#x, buf=%#x:%#x size=%d\n", func, FP_SEG(buf), FP_OFF(buf), size);
#endif
    memset(&rmi, 0, sizeof rmi);
    rmi.eax = func;
    rmi.ecx = size;
    rmi.es = buf ? client_seg : 0;
    rmi.edx = buf ? (char _far *)buf - (char _far *)client_buf : 0;
    regs.x.eax = 0x300;	/* simulate real-mode interrupt */
    regs.x.ebx = 0;
    regs.x.ecx = 0;
    regs.x.edx = 0;
    regs.h.bl = to_tsr;
    regs.h.bh = 0;
    segread(&sregs);
    sregs.es = FP_SEG(&rmi);
    regs.x.esi = 0;
    regs.x.edi = FP_OFF(&rmi);
#ifdef notdef
printf("call int386x ds=%#x es=%#x ss=%#x cs=%#x fs=%#x gs=%#x...\n", sregs.ds, sregs.es, sregs.ss, sregs.cs, sregs.fs, sregs.gs);
printf("edi=%#x esi=%#x, eax=%#x ebx=%#x ecx=%#x\n", regs.x.edi, regs.x.esi, regs.x.eax, regs.x.ebx, regs.x.ecx);
#endif

    int386x(0x31, &regs, &regs, &sregs);
#ifdef notdef
printf("client_send returns\n");
#endif
}

#define MAJOROP ((xReq _far *)client_buf->data)->reqType

void
client_poll()
{
    int result;
    char *buf;

    /* Sanity */
    if (!client_seg)
	return;
    if (client_buf->type != TYPE_XREQUEST)
	return;

    serverClient->sequence++;
    result = client_buf->length;
    buf = alloca(result);
    if (!buf) {
	serverClient->errorValue = result;
	result = BadAlloc;
    } else {
	client_out = (char _far *)client_buf->data;
	_fmemcpy(buf, client_buf->data, result);
	serverClient->requestBuffer = buf;
#ifdef notdef
printf("client request %d len %d\n", MAJOROP, result);
#endif

	result = (*ProcVector[MAJOROP])(serverClient);
    }

    if (result != Success) 
    {
	xError rep;

	if (serverClient->noClientException != Success) {
	    client_close();
	    return;
	}
	rep.type = X_Error;
	rep.sequenceNumber = serverClient->sequence;
	rep.errorCode = result;
	rep.majorCode = MAJOROP;
	rep.minorCode = 0;
	rep.resourceID = serverClient->errorValue;
#ifdef notdef
printf("errorCode=%d, resourceID=%#x\n", rep.errorCode, rep.resourceID);
#endif
	*(xError _far *)client_buf->data = rep;
	client_buf->type = TYPE_XERROR;
	client_buf->length = sizeof (xError);
	client_send(FUNC_PROCESSED << 8, client_buf->data, sizeof (xError));
	return;
    }
    /* Send stuff that may have been written. */
    client_buf->type = TYPE_FREE;
    client_buf->length = client_out - (char _far *)client_buf->data;
    client_send(FUNC_PROCESSED << 8, client_buf->length ? client_buf->data : 0,
	    client_buf->length);
    client_out = (char _far *)client_buf->data;
}

void
client_event(xEvent *xe)
{
#ifdef notdef
printf("client_event called, xe=%#x, client_xe=%#x:%#x\n", xe, FP_SEG(client_xe), FP_OFF(client_xe));
#endif
    if (client_xe == 0)
	return;
    *client_xe = *xe;
    client_send(FUNC_XEVENT << 8, client_xe, sizeof (xEvent));
#ifdef notdef
printf("FUNC_XEVENT sent\n");
#endif
}

int
client_write(count, buf)
int count;
void *buf;
{
#ifdef notdef
printf("send %d of bytes to TSR\n", count);
#endif
    _fmemcpy(client_out, buf, count);
    client_out += count;
    return count;
}
