/*
 * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
 *
 * 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 (including the next
 * paragraph) 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 AUTHORS OR 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.
 */


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

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xmu/XmuSolaris.h>

#if defined(DEBUG)
#include <stdio.h>
#endif

#define INIT_LIST_SIZE 100

/*
 * Get's next pair of integers from a string
 */
static VisualID
getNextEntry(char **pp)
{
    char  *newP;
    VisualID	  entry;

    entry = strtoul(*pp, &newP, 0);
    if (newP == *pp) {
	return 0;
    }
    *pp = newP;

    return entry;
}

/*
 * Build a list of VisualIds that are equivalant to vidIn
 *
 * The format of the property string is a sequence of lists of
 * integers separated by a newline.
 * The first entry in each is the number of elements in the list.
 * The list of ids follows.
 */
static VisualID *
buildList(char *string, VisualID vidIn, VisualID *pOriginalList)
{
    VisualID  	*pList;
    char 	*p = string;
    int	 	num;

#ifdef DEBUG
    (void) memset(pOriginalList, 0, sizeof(VisualID)*INIT_LIST_SIZE);
#endif

    while (num = strtoul(p, &p, 0)) {
	int foundIt = 0;
	int i;
	if ((num + 1) > INIT_LIST_SIZE) {
	    pList = (VisualID *) malloc((num + 1) * sizeof(VisualID));
	    if (pList == NULL)
		return NULL;
	} else {
	    pList = pOriginalList;
	}
	for (i=0; i < num; i++) {
	    /* Build the list of VisualIDs equivalent to v */
	    VisualID vid;
	    if (vid = getNextEntry(&p)) {
		pList[i] = vid;
		if (vid == vidIn)
		    foundIt = 1;
	    } else {
	        /* string is formatted wrong */
#ifdef DEBUG
		fprintf(stderr, "property string is formatted wrong: %s\n",
			string);
#endif
	        break;
	    }
	}
#ifdef DEBUG
	if (*p != '\n')
	    fprintf(stderr, "property string is missing a newline: %s\n",
			string);
#endif
	if (foundIt) {
	    /* terminate the list */
	    pList[num] = 0;
	    break;
	}
	if (pList != pOriginalList)
	    free(pList);
	pList = NULL;
    }

    return pList;
}


static int
searchList(VisualID *pList, VisualID v)
{
	int i;
	for (i=0; pList[i] != 0; i++) {
	    if (pList[i] == v)
		return 1;
	}
	return 0;
}

static Bool
areEquiv(char *pPropString, VisualID v1, VisualID v2)
{
	VisualID list[INIT_LIST_SIZE];
	VisualID *pList;
	Bool foundMatch = False;

	/*
	 * Build a list of VisualIDS which are equivalent to v1
	 * using the array list if it fits.
	 */
	pList = buildList(pPropString, v1, list);
	if (pList == NULL)
	    return False;

	/* now see if v2 is in the list */
	if (searchList(pList, v2)) {
	    foundMatch  = True;
	}

	if (pList != list)
	    free(pList);

	return foundMatch;
}

#define SUN_CMAP_EQUIV_ATOM_NAME "_SUN_CMAP_EQUIV"

Bool
XSolarisCheckColormapEquivalence(Display *dpy,  int screen_number, 
				Visual *pVis1, Visual* pVis2)
{
	Atom theAtom;
	Atom actualType;
	int  actualFormat;
	unsigned long  nitems;
	unsigned long  bytesAfter;
	char  *prop;

	theAtom = XInternAtom(dpy, SUN_CMAP_EQUIV_ATOM_NAME, True);
	if (theAtom == None)
	    return False;

	if (!XGetWindowProperty(dpy, XRootWindow(dpy, screen_number), theAtom,
			    0, 8192, False, XA_STRING, &actualType,
			    &actualFormat, &nitems, &bytesAfter, 
			    (unsigned char **)&prop)) {
	     if (prop != NULL) {
		 Bool ret = areEquiv(prop, pVis1->visualid, pVis2->visualid);
		 XFree(prop);
		 return ret;
	     }
	}
	
	return False;
}