/***********************************************************************/
/* 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 "hwDeclarations.h"
#include "hwList.h"
#include "hwClipped.h"
#include "hwMatrix.h"
#include "hwMemory.h"
#include "hwPortLayer.h"
#include "hwWindow.h"
#include "hwXfield.h"
#include "hwObjectHash.h"

/**************************************************************************************
 *
 * Two forms of object hashing.  We hash objects by object tag to cache triangle
 * strips and texture display lists.  We also hash objects by object tag, approximation 
 * type and density to cache geometry display lists.
 *
 **************************************************************************************/

typedef struct
{
    Key		key;
    int    	hit;
    dxObject 	obj;
} *OHashP, OHashS;

HashTable
_dxf_InitObjectHash()
{
    HashTable ht = DXCreateHash(sizeof(OHashS), NULL, NULL);
    return ht;
}

void
_dxf_ResetObjectHash(HashTable ht)
{
    OHashP ptr;

    if (ht)
    {
	DXInitGetNextHashElement(ht);
	while (NULL != (ptr = (OHashP)DXGetNextHashElement(ht)))
	    ptr->hit = 0;
    }
}
       

dxObject
_dxf_QueryObject(HashTable ht, dxObject keyO)
{
    Key key;
    OHashP ptr;

    if (! ht)
        return NULL;

    key = (Key)DXGetObjectTag(keyO);
    ptr = (OHashP)DXQueryHashElement(ht, (Pointer)&key);
    if (ptr)
    {
        ptr->hit++;
	return ptr->obj;
    }
    else
        return NULL;
}

void
_dxf_InsertObject(HashTable ht, dxObject keyO, dxObject obj)
{
    OHashS str;
    Key key;
    OHashP ptr;

    if (! ht)
        return;

    key = (Key)DXGetObjectTag(keyO);
    ptr = (OHashP)DXQueryHashElement(ht, (Pointer)&key);
    if (ptr)
    {
        if (ptr->obj != obj)
		{
			if (ptr->obj)
				DXDelete(ptr->obj);
	        ptr->obj = DXReference(obj);
		}
    }
    else
    {
	str.key   = key;
	str.hit   = 1;
	str.obj   = DXReference(obj);

	if (! DXInsertHashElement(ht, (Element)&str))
	    DXDelete(obj);
    }
}

void
_dxf_DeleteObjectHash(HashTable ht)
{
    OHashP ptr;

    if (ht)
    {
	DXInitGetNextHashElement(ht);
	while (NULL != (ptr = (OHashP)DXGetNextHashElement(ht)))
	{
	    if (ptr->obj)
		DXDelete(ptr->obj);
	}

	DXDestroyHash(ht);
    }
}

extern void _dxf_deleteHashElt(HashTable h, Element e);

HashTable 
_dxf_CullObjectHash(HashTable ht)
{
    HashTable new = NULL;

    if (! ht)
    {
	return NULL;
    }
    else
    {
	OHashP ptr;
	new = DXCreateHash(sizeof(OHashS), NULL, NULL);

	DXInitGetNextHashElement(ht);
	while (NULL != (ptr = (OHashP)DXGetNextHashElement(ht)))
	{
	    if (ptr->hit)
	    {
		OHashS str;
		str.key = ptr->key;
		str.hit = 0;
		str.obj = DXReference(ptr->obj);
		if (! DXInsertHashElement(new, (Element)&str))
		    DXDelete(ptr->obj);
	    }

	    if (ptr->obj)
		DXDelete(ptr->obj);

	}

	DXDestroyHash(ht);
	return new;
    }

error:
    
    if (new)
        DXDestroyHash(new);

    return NULL;
}

/**************************************************************************************
 *
 * Here is the second form.  We need to use hash and compare functions.
 *
 **************************************************************************************/


typedef struct
{
    int		 tag;
    int 	 approx;
    int 	 density;
    float 	 linewidth;
    int 	 aalines;
} *DLKeyP, DLKeyS;

typedef struct
{
    DLKeyS	 key;
    int    	 hit;
    dxObject 	 obj;
} *DLHashP, DLHashS;

static PseudoKey
dlhash(Key key)
{
    DLKeyP dlkey = (DLKeyP)key;
    int a;
    long l;

    switch(dlkey->approx)
    {
	case approx_none:  a = 0; break;
	case approx_flat:  a = 1; break;
	case approx_lines: a = 2; break;
	case approx_dots:  a = 3; break;
	default:           a = 4; break;
    }

    l = (((dlkey->tag ^ a) ^ dlkey->density) ^
			(*(int *)&dlkey->linewidth)) ^ (dlkey->aalines*29);

    return (PseudoKey)l;
}

static int
dlcmp(Key k0, Key k1)
{
    DLKeyP dlkey0 = (DLKeyP)k0;
    DLKeyP dlkey1 = (DLKeyP)k1;

    if ((dlkey0->tag        != dlkey1->tag)       ||
        (dlkey0->approx     != dlkey1->approx)    ||
        (dlkey0->linewidth  != dlkey1->linewidth) ||
        (dlkey0->aalines    != dlkey1->aalines)   ||
        (dlkey0->density    != dlkey1->density))
	return 1;
    else
	return 0;
}
    
HashTable
_dxf_InitDisplayListHash()
{
    HashTable ht = DXCreateHash(sizeof(DLHashS), dlhash, dlcmp);
    return ht;
}

void
_dxf_ResetDisplayListHash(HashTable ht)
{
    DLHashP ptr;

    if (ht)
    {
	DXInitGetNextHashElement(ht);
	while (NULL != (ptr = (DLHashP)DXGetNextHashElement(ht)))
	    ptr->hit = 0;
    }
}
       
dxObject
_dxf_QueryDisplayList(HashTable ht, xfieldP xf, int buttonUp)
{
    DLKeyS key;
    DLHashP ptr;

    if (! ht)
        return NULL;

    key.tag       = DXGetObjectTag((dxObject)xf->field);
    key.approx    = buttonUp ?
			xf->attributes.buttonUp.approx :
			xf->attributes.buttonDown.approx;
    key.density   = buttonUp ?
			xf->attributes.buttonUp.density :
			xf->attributes.buttonDown.density;
    key.linewidth = xf->attributes.linewidth;
    key.aalines   = xf->attributes.aalines;

    ptr = (DLHashP)DXQueryHashElement(ht, (Pointer)&key);
    if (ptr)
    {
        ptr->hit++;
	return ptr->obj;
    }
    else
        return NULL;
}

void
_dxf_InsertDisplayList(HashTable ht, xfieldP xf, int buttonUp, dxObject obj)
{
    DLHashS str;
    DLHashP ptr;

    if (! ht)
        return;

    str.key.tag       = DXGetObjectTag((dxObject)xf->field);
    str.key.approx    = buttonUp ?
			xf->attributes.buttonUp.approx :
			xf->attributes.buttonDown.approx;
    str.key.density   = buttonUp ?
			xf->attributes.buttonUp.density :
			xf->attributes.buttonDown.density;
    str.key.linewidth = xf->attributes.linewidth;
    str.key.aalines   = xf->attributes.aalines;

    ptr = (DLHashP)DXQueryHashElement(ht, (Pointer)&str.key);
    if (ptr)
    {
        if (ptr->obj != obj)
	{
	    if (ptr->obj) DXDelete(ptr->obj);
	    ptr->obj = DXReference(obj);
	}
    }
    else
    {
	str.hit   = 1;
	str.obj   = DXReference(obj);

	if (! DXInsertHashElement(ht, (Element)&str))
	    DXDelete(obj);
    }
}

void
_dxf_DeleteDisplayListHash(HashTable ht)
{
    DLHashP ptr;

    if (ht)
    {
	DXInitGetNextHashElement(ht);
	while (NULL != (ptr = (DLHashP)DXGetNextHashElement(ht)))
	{
	    if (ptr->obj)
		DXDelete(ptr->obj);
	}

	DXDestroyHash(ht);
    }
}

extern void _dxf_deleteHashElt(HashTable h, Element e);

HashTable 
_dxf_CullDisplayListHash(HashTable ht)
{
    HashTable new = NULL;

    if (! ht)
    {
	return NULL;
    }
    else
    {
	DLHashP ptr;
	new = DXCreateHash(sizeof(DLHashS), dlhash, dlcmp);

	DXInitGetNextHashElement(ht);
	while (NULL != (ptr = (DLHashP)DXGetNextHashElement(ht)))
	{
	    if (ptr->hit)
	    {
		DLHashS str;
		str.key = ptr->key;
		str.hit = 0;
		str.obj = DXReference(ptr->obj);
		if (! DXInsertHashElement(new, (Element)&str))
		    DXDelete(ptr->obj);
	    }

	    if (ptr->obj)
		DXDelete(ptr->obj);

	}

	DXDestroyHash(ht);
	return new;
    }

error:
    
    if (new)
        DXDestroyHash(new);

    return NULL;
}
