/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>



#include <string.h>
#include <dx/dx.h>
#include "internals.h"

#define N       1024
#define WRAP(i) ((i)&(N-1))

char * _dxfstring(char *, int);
Object _dxfstringobject(char *, int);

#define DECLARE(x) char * _dxd_##x; Object _dxd_o_##x

DECLARE(back_colors);
DECLARE(binormals);
DECLARE(both_colors);
DECLARE(box);
DECLARE(colors);
DECLARE(color_map);
DECLARE(color_multiplier);
DECLARE(connections);
DECLARE(cubes);
DECLARE(data);
DECLARE(dep);
DECLARE(der);
DECLARE(element_type);
DECLARE(faces);
DECLARE(fb_image);
DECLARE(fontwidth);
DECLARE(front_colors);
DECLARE(image);
DECLARE(image_type);
DECLARE(inner);
DECLARE(invalid_positions);
DECLARE(invalid_connections);
DECLARE(lines);
DECLARE(neighbors);
DECLARE(normals);
DECLARE(opacities);
DECLARE(opacity_map);
DECLARE(opacity_multiplier);
DECLARE(points);
DECLARE(polylines);
DECLARE(positions);
DECLARE(quads);
DECLARE(ref);
DECLARE(surface);
DECLARE(tangents);
DECLARE(tetrahedra);
DECLARE(time);
DECLARE(tri);
DECLARE(triangles);
DECLARE(vbox);
DECLARE(vol);
DECLARE(x_image);
DECLARE(x_server);



static
struct table {
    lock_type DXlock;		/* for adding strings */
    struct hash {		/* string hash table */
	char *s;		/* allocated string */
	Object o;		/* String object */
    } hash[N];			/* N entries */
} *table;

#define DO_INIT(l, s) _dxd_##l = _dxfstring(s, 1); \
		      _dxd_o_##l = _dxfstringobject(_dxd_##l, 1);
Error
_dxf_initstringtable(void)
{
    table = (struct table *) DXAllocateZero(sizeof(struct table));
    if (!table)
	return NULL;
    DXcreate_lock(&table->DXlock, "string table");

    DO_INIT(back_colors, "back colors");
    DO_INIT(binormals, "binormals");
    DO_INIT(both_colors, "both colors");
    DO_INIT(box, "box");
    DO_INIT(colors, "colors");
    DO_INIT(color_map, "color map");
    DO_INIT(color_multiplier, "color multiplier");
    DO_INIT(connections, "connections");
    DO_INIT(cubes, "cubes");
    DO_INIT(data, "data");
    DO_INIT(dep, "dep");
    DO_INIT(der, "der");
    DO_INIT(element_type, "element type");
    DO_INIT(faces, "faces");
    DO_INIT(fb_image, "fb image");
    DO_INIT(fontwidth, "fontwidth");
    DO_INIT(front_colors, "front colors");
    DO_INIT(image, "image");
    DO_INIT(image_type, "image type");
    DO_INIT(inner, "inner");
    DO_INIT(invalid_positions, "invalid positions");
    DO_INIT(invalid_connections, "invalid connections");
    DO_INIT(lines, "lines");
    DO_INIT(neighbors, "neighbors");
    DO_INIT(normals, "normals");
    DO_INIT(opacities, "opacities");
    DO_INIT(opacity_map, "opacity map");
    DO_INIT(opacity_multiplier, "opacity multiplier");
    DO_INIT(points, "points");
    DO_INIT(polylines, "polylines");
    DO_INIT(positions, "positions");
    DO_INIT(quads, "quads");
    DO_INIT(ref, "ref");
    DO_INIT(surface, "surface");
    DO_INIT(tangents, "tangents");
    DO_INIT(tetrahedra, "tetrahedra");
    DO_INIT(time, "time");
    DO_INIT(tri, "tri");
    DO_INIT(triangles, "triangles");
    DO_INIT(vbox, "valid box");
    DO_INIT(vol, "vol");
    DO_INIT(x_image, "x image");
    DO_INIT(x_server, "x server");

    return OK;
}

static
ulong
_string(char *s, int add, int object)
{
    char *t, *ss;
    int h, c;
    struct hash *hash;

    /* initialization */
    if (!table)
	DXinitdx();
    if (!table)
	return NULL;
    hash = table->hash;

    /* calculate initial hash value h */
    for (ss=s, h=0; c=(unsigned char)*ss; ss++)	/* for each char c in s */
	h = WRAP(17*h + c);			/* update h */

    /* look for it (closed chaining) */
    for (h=h; t=hash[h].s; h=WRAP(h+1))		/* start with h; wrap around */
	if (strcmp(t,s)==0)			/* is t the string we want? */
	    break;				/* if so break */

    /* add it if not there and adding was requested */
    if (!t && add) {				/* t is NULL if not there */
	DXlock(&table->DXlock, 0);		/* one person at a time */
	for (h=h; t=hash[h].s; h=WRAP(h+1))	/* start where we left off */
	    if (strcmp(t,s)==0)			/* did anyone beat us to it? */
		break;				/* if so break */
	if (!t) {				/* if no one else added it */
	    Object o = (Object) DXNewString(s);	/* make a string object */
	    _dxf_SetPermanent(o);		/* avoid Ref bottlenecks */
	    if (o) {				/* if it succeeded */
		t = DXGetString((String)o);	/* the string */
		hash[h].o = o;			/* put object there first */
		hash[h].s = t;			/* do this last */
	    }
	}
	DXunlock(&table->DXlock, 0);		/* now unlock table */
    }

    return object? (t?(ulong)(hash[h].o):0) : (ulong)t;
}

char *
_dxfstring(char *s, int add)
{
    return (char *)_string(s, add, 0);
}

Object
_dxfstringobject(char *s, int add)
{
    return (Object)_string(s, add, 1);
}

