/******************************************************************************
 ******************************************************************************
 **
 ** (c) Copyright 1996 Hewlett-Packard Company
 ** (c) Copyright 1996 International Business Machines Corp.
 ** (c) Copyright 1996, Oracle and/or its affiliates. All rights reserved.
 ** (c) Copyright 1996 Novell, Inc.
 ** (c) Copyright 1996 Digital Equipment Corp.
 ** (c) Copyright 1996 Fujitsu Limited
 ** (c) Copyright 1996 Hitachi, Ltd.
 **
 ** Permission is hereby granted, free of charge, to any person obtaining a copy
 ** of this software and associated documentation files (the "Software"), to deal
 ** in the Software without restriction, including without limitation the rights
 ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 ** copies of the Software, and to permit persons to whom the Software is
 ** furnished to do so, subject to the following conditions:
 **
 ** The above copyright notice and this permission notice shall be included in
 ** all copies or substantial portions of the Software.
 **
 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 ** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 ** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 **
 ** Except as contained in this notice, the names of the copyright holders shall
 ** not be used in advertising or otherwise to promote the sale, use or other
 ** dealings in this Software without prior written authorization from said
 ** copyright holders.
 **
 ******************************************************************************
 *****************************************************************************/

#define NEED_EVENTS
#define NEED_REPLIES
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <X11/extensions/Printstr.h>
#include <X11/Xlibint.h>
#include "XpExtUtil.h"
#include <X11/Xos.h>

#define ENQUEUE_EVENT   True
#define DONT_ENQUEUE    False

static XExtensionInfo     xp_info_data;
static XExtensionInfo     *xp_info = &xp_info_data;
static const char         *xp_extension_name = XP_PRINTNAME;

static int    XpClose(Display *, XExtCodes *);
static char   *XpError(Display *, int, XExtCodes *, char *, int);
static Bool   XpWireToEvent(Display *, XEvent *, xEvent *);
static Status XpEventToWire(Display *, XEvent *, xEvent *);

#define XpCheckExtension(dpy,i,val) \
  XextCheckExtension (dpy, i, xp_extension_name, val)

static /* const */ XExtensionHooks xpprint_extension_hooks = {
    NULL,			/* create_gc */
    NULL,			/* copy_gc */
    NULL,			/* flush_gc */
    NULL,			/* free_gc */
    NULL,			/* create_font */
    NULL,			/* free_font */
    XpClose,			/* close_display */
    XpWireToEvent,		/* wire_to_event */
    XpEventToWire,		/* event_to_wire */
    NULL,			/* error */
    XpError,			/* error_string */
};

typedef struct {
    int     present;
    short   major_version;
    short   minor_version;
} XPrintLocalExtensionVersion;

typedef struct _xpPrintData {
    XEvent              data;
    XPrintLocalExtensionVersion   *vers;
} xpPrintData;

static const char *XpErrorList[ /* XP_ERRORS */ ] = {
	"XPBadContext",
	"XPBadSequence",
	"XPBadResourceID"
};

XEXT_GENERATE_FIND_DISPLAY (xp_find_display, xp_info,
	xp_extension_name, &xpprint_extension_hooks, XP_EVENTS, NULL)

static XEXT_GENERATE_ERROR_STRING (XpError, xp_extension_name,
				   XP_ERRORS, XpErrorList)

/*******************************************************************
 *
 * XP Print extension versions.
 */

static XPrintLocalExtensionVersion xpprintversions[] = {{XP_ABSENT,0,0},
	{XP_PRESENT, XP_PROTO_MAJOR, XP_PROTO_MINOR}};


/***********************************************************************
 *
 * Check to see if the Xp Print extension is installed in the server.
 * Also check to see if the version is >= the requested version.
 *
 * xpprintversions[] shows all revisions of this library, past to present.
 * xpprintversions[version_index] shows which version *this* library is.
 */

int XpCheckExtInitUnlocked(Display *dpy, int version_index)
{
    XExtDisplayInfo 	*info = xp_find_display (dpy);

    XpCheckExtension (dpy, info, -1);


    /*
     * Check for broken condition - a partial info world.
     */
    if (info->data) {
	if (!(((xpPrintData *) info->data)->vers)) {
	    return (-1);
	}
    }

    if (info->data == NULL) {
	/*
	 * Hang a Xp private data struct.   Use it for version
	 * information.
	 */
	info->data = (XPointer) Xmalloc (sizeof (xpPrintData));
	if (!info->data) {
	    return (-1);
	}

	((xpPrintData *) info->data)->vers =
	    (XPrintLocalExtensionVersion *) Xmalloc(sizeof(XPrintLocalExtensionVersion));
	if (!(((xpPrintData *) info->data)->vers)) {
	    return (-1);
	}

	/*
	 * Set present to false so that XpQueryVersion will fill
	 * it in vs using its own cache which now contains garbage.
	 */
	((xpPrintData *) info->data)->vers->present = False;

	((xpPrintData *) info->data)->vers->present = XpQueryVersion(dpy,
	    &(((xpPrintData *) info->data)->vers->major_version),
	    &(((xpPrintData *) info->data)->vers->minor_version) );
    }
    if (xpprintversions[version_index].major_version > XP_DONT_CHECK) {
	if ( ( ((xpPrintData *) info->data)->vers->major_version
		< xpprintversions[version_index].major_version) ||
	     ( (((xpPrintData *) info->data)->vers->major_version
		== xpprintversions[version_index].major_version) &&
	     (((xpPrintData *) info->data)->vers->minor_version
		< xpprintversions[version_index].minor_version))) {
	    return (-1);
	}
    }

    return (0);
}

int XpCheckExtInit(Display *dpy, int version_index)
{
    int retval;

    _XLockMutex(_Xglobal_lock);

    retval = XpCheckExtInitUnlocked(dpy, version_index);

    _XUnlockMutex(_Xglobal_lock);

    return retval;
}

/***********************************************************************
 *
 * Close display routine.
 *
 */

static int
XpClose (Display *dpy, XExtCodes *codes)
    {
    XExtDisplayInfo 	*info = xp_find_display (dpy);

    _XLockMutex(_Xglobal_lock);
    if ( ((xpPrintData *) info->data)) {
	if (((xpPrintData *) info->data)->vers) {
	    XFree((char *)((xpPrintData *) info->data)->vers);
	}
	XFree((char *)info->data);
	info->data = (char *) NULL;	/* NULL since tests are run on */
    }
    _XUnlockMutex(_Xglobal_lock);

    return XextRemoveDisplay (xp_info, dpy);
    }


/******************************************************************************
 *
 * Handle extension events.
 */

/********************************************************************
 *
 * Reformat a wire event into an XEvent structure of the right type.
 */
static Bool
XpWireToEvent (Display *dpy, XEvent *re, xEvent *event)
{
    XExtDisplayInfo *info = xp_find_display (dpy);


    /*
     * type, serial, send_event, display are common to all events.
     */
    re->type = event->u.u.type & 0x7f;
    ((XAnyEvent *)re)->serial = _XSetLastRequestRead(dpy,
                                     (xGenericReply *)event);
    ((XAnyEvent *)re)->send_event = ((event->u.u.type & 0x80) != 0);
    ((XAnyEvent *)re)->display = dpy;


    switch (re->type - info->codes->first_event)
	{

	case XPPrintNotify:
	    {
	    register XPPrintEvent  *ev = (XPPrintEvent *)     re;
	    xPrintPrintEvent      *ev2 = (xPrintPrintEvent *) event;

	    /* type, serial, send_event, *display */

	    ev->context		= (XPContext) ev2->printContext;
	    ev->cancel		= (Bool) ev2->cancel;
	    ev->detail		= (int) ev2->detail;

	    return (ENQUEUE_EVENT);
	    break;
	    }

	case XPAttributeNotify:
	    {
	    register XPAttributeEvent  *ev = (XPAttributeEvent *)     re;
	    xPrintAttributeEvent       *ev2 = (xPrintAttributeEvent *) event;

	    /* type, serial, send_event, *display */

	    ev->context		= (XPContext) ev2->printContext;
	    ev->detail		= (int) ev2->detail;

	    return (ENQUEUE_EVENT);
	    break;
	    }

	default:
	    printf ("XpWireToEvent: UNKNOWN WIRE EVENT! type=%d\n",re->type);
	    break;
	}

    return (DONT_ENQUEUE);
}

/********************************************************************
 *
 * Reformat an XEvent into a wire event.
 */
static Status
XpEventToWire(
    Display *dpy,      /* pointer to display structure */
    XEvent *re,        /* pointer to client event */
    xEvent *event)     /* wire protocol event */
{
    XExtDisplayInfo *info = (XExtDisplayInfo *) xp_find_display (dpy);

    switch ((re->type & 0x7f) - info->codes->first_event)
        {
#ifdef PRINT_SomeEventExample2
        case PRINT_SomeEventExample:
            {
            register XDeviceKeyEvent *ev = (XDeviceKeyEvent*) re;
            register deviceKeyButtonPointer *kev;
            register deviceValuator *vev;
	    int i;

            *count = 2;
            kev = (deviceKeyButtonPointer *) Xmalloc (*count * sizeof (xEvent));
            if (!kev)
                return(_XUnknownNativeEvent(dpy, re, event));
            *event = (xEvent *) kev;

            kev->type           = ev->type;
            kev->root           = ev->root;
            kev->event          = ev->window;
            kev->child          = ev->subwindow;
            kev->time           = ev->time;
            kev->event_x        = ev->x ;
            kev->event_y        = ev->y ;
            kev->root_x         = ev->x_root;
            kev->root_y         = ev->y_root;
            kev->state          = ev->state;
            kev->same_screen    = ev->same_screen;
            kev->detail         = ev->keycode;
            kev->deviceid       = ev->deviceid | MORE_EVENTS;

            vev = (deviceValuator *) ++kev;
            vev->type = info->codes->first_event + XI_DeviceValuator;
            vev->deviceid = ev->deviceid;
            vev->device_state = ev->device_state;
            vev->first_valuator = ev->first_axis;
            vev->num_valuators = ev->axes_count;
            i = vev->num_valuators;
            if (i > 6) i = 6;
            switch (i)
                {
                case 6: vev->valuator5 = ev->axis_data[5];
                case 5: vev->valuator4 = ev->axis_data[4];
                case 4: vev->valuator3 = ev->axis_data[3];
                case 3: vev->valuator2 = ev->axis_data[2];
                case 2: vev->valuator1 = ev->axis_data[1];
                case 1: vev->valuator0 = ev->axis_data[0];
                }
            break;
            }
#endif /* PRINT_SomeEventExample2 */

        default:
            return(_XUnknownNativeEvent(dpy, re, event));
        }
}
