/***********************************************************************/
/* 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>


/*
 * Header: /usr/people/gresh/code/svs/src/dxmods/RCS/_grow.c,v 5.0 92/11/12 09:12:57 svs Exp Locker: gresh 
 *
 * 
 */

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <dx/dx.h>

static int  IsRegular(Object);
static Object GrowObject(Object, int, Pointer, Array);

extern Object _dxfRegGrow(Object, int, Pointer, Array);
extern Object _dxfIrregGrow(Object, int, Array);

extern Object _dxfRegInvalidateDupBoundary(Object);
extern Object _dxfIrregInvalidateDupBoundary(Object);

extern Object _dxfRegShrink(Object);
extern Object _dxfIrregShrink(Object);

       Array  _dxfReRef(Array, int);

#define IS_REGULAR		0
#define IS_NOT_REGULAR		1
#define IS_REGULAR_ERROR	2

Object
DXGrowV(Object object, int rings, Pointer fill, char **componentNames)
{
    int i;
    Array components = NULL;

    if (rings < 1)
	return object;

    if (componentNames && componentNames[0] != NULL)
    {
	for (i = 0; componentNames[i]; i++);
	components = DXMakeStringListV(i, componentNames);
	if (! components)
	    return NULL;
    }
    else
	componentNames = NULL;

    if (! GrowObject(object, rings, fill, components))
	goto error;
    
    if (components)
	DXFree((Object)components);

    return object;

error:
    if (components)
	DXFree((Object)components);

    return NULL;
}

Object
DXGrow(Object object, int rings, Pointer fill, ...)
{
    char *components[100];
    int i;
    va_list arg;

    va_start(arg,fill);
    for (i = 0; i < 100; i++)
	if (NULL == (components[i] = va_arg(arg, char *)))
	    break;
    va_end(arg);

    return DXGrowV(object, rings, fill, components);
}

static Object
GrowObject(Object object, int rings, Pointer fill, Array components)
{

    switch(DXGetObjectClass(object))
    {
	case CLASS_FIELD:
	{
	    break;
	}
	
	case CLASS_GROUP:
	{
	    if (DXGetGroupClass((Group)object) == CLASS_COMPOSITEFIELD)
	    {
		int regularity = IsRegular(object);

	        if (regularity == IS_REGULAR)
		{
		    if (!_dxfRegGrow(object, rings, fill, components))
			goto error;
		}
		else if (regularity == IS_NOT_REGULAR)
		{
		    if (! _dxfIrregGrow(object, rings, components))
			goto error;
		}
	    }
	    else
	    {
		Object c;
		Group g = (Group)object;
		int i;
	    
		for (i=0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++)
		    if (! GrowObject(c, rings, fill, components))
			return NULL;
	    }
	    break;
	}

	case CLASS_XFORM:
	{
	    Object x;
		
	    if (! DXGetXformInfo((Xform)object, &x, NULL))
		goto error;
	    
	    if (! GrowObject(x, rings, fill, components))
		goto error;
	}
	    
	case CLASS_CLIPPED:
	{
	    Object x;
		
	    if (! DXGetClippedInfo((Clipped)object, &x, NULL))
		goto error;
	    
	    if (! GrowObject(x, rings, fill, components))
		goto error;
	}

	default:
	    return NULL;
    }

    return object;

error:
    return NULL;
}

Object
DXShrink(Object object)
{
    switch(DXGetObjectClass(object))
    {
	case CLASS_FIELD:
	{
	    break;
	}
	
	case CLASS_GROUP:
	{
	    if (DXGetGroupClass((Group)object) == CLASS_COMPOSITEFIELD)
	    {
		int regularity = IsRegular(object);

	        if (regularity == IS_REGULAR)
		{
		    if (!_dxfRegShrink(object))
			goto error;
		}
		else if (regularity == IS_NOT_REGULAR)
		{
		    if (! _dxfIrregShrink(object))
			goto error;
		}
	    }
	    else
	    {
		Object c;
		Group g = (Group)object;
		int i;
	    
		for (i=0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++)
		    if (! DXShrink(c))
			return NULL;
	    }
	    break;
	}

	case CLASS_XFORM:
	{
	    Object x;
		
	    if (! DXGetXformInfo((Xform)object, &x, NULL))
		goto error;
	    
	    if (! DXShrink(x))
		goto error;
	}
	    
	case CLASS_CLIPPED:
	{
	    Object x;
		
	    if (! DXGetClippedInfo((Clipped)object, &x, NULL))
		goto error;
	    
	    if (! DXShrink(x))
		goto error;
	}

	default:
	    return NULL;
    }

    return object;

error:
    return NULL;
}

Object
DXInvalidateDupBoundary(Object object)
{
    switch(DXGetObjectClass(object))
    {
	case CLASS_FIELD:
	{
	    Object a = DXGetComponentValue((Field)object, "invalid positions");
	    if (a)
		if (! DXSetComponentValue((Field)object, "saved invalid positions", a))
		    goto error;
	    
	    break;
	}
	
	case CLASS_GROUP:
	{
	    if (DXGetGroupClass((Group)object) == CLASS_COMPOSITEFIELD)
	    {
		int regularity = IsRegular(object);

	        if (regularity == IS_REGULAR)
		{
		    if (!_dxfRegInvalidateDupBoundary(object))
			goto error;
		}
		else if (regularity == IS_NOT_REGULAR)
		{
		    if (! _dxfIrregInvalidateDupBoundary(object))
			goto error;
		}
	    }
	    else
	    {
		Object c;
		Group g = (Group)object;
		int i;
	    
		for (i=0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++)
		    if (! DXInvalidateDupBoundary(c))
			return NULL;
	    }
	    break;
	}

	case CLASS_XFORM:
	{
	    Object x;
		
	    if (! DXGetXformInfo((Xform)object, &x, NULL))
		goto error;
	    
	    if (! DXInvalidateDupBoundary(x))
		goto error;
	    
	    break;
	}
	    
	case CLASS_CLIPPED:
	{
	    Object x;
		
	    if (! DXGetClippedInfo((Clipped)object, &x, NULL))
		goto error;
	    
	    if (! DXInvalidateDupBoundary(x))
		goto error;
	    
	    break;
	}

	default:
	    return object;
    }

    return object;

error:
    return NULL;
}

Object
DXRestoreDupBoundary(Object object)
{
    switch(DXGetObjectClass(object))
    {
	case CLASS_FIELD:
	{
	    Array a = (Array)DXGetComponentValue((Field)object, "saved invalid positions");
	    if (a)
	    {
		if (DXGetComponentValue((Field)object, "invalid positions"))
		    DXDeleteComponent((Field)object, "invalid positions");

		if (! DXSetComponentValue((Field)object, 
				    "invalid positions", (Object)a))
		    goto error;

		DXDeleteComponent((Field)object, "saved invalid positions");
	    }
	    else
		DXDeleteComponent((Field)object, "invalid positions");

	    break;
	}
	
	case CLASS_GROUP:
	{
	    Object c;
	    Group g = (Group)object;
	    int i;
	
	    for (i=0; NULL != (c = DXGetEnumeratedMember(g, i, NULL)); i++)
		if (! DXRestoreDupBoundary(c))
		    return NULL;

	    break;
	}

	case CLASS_XFORM:
	{
	    Object x;
		
	    if (! DXGetXformInfo((Xform)object, &x, NULL))
		goto error;
	    
	    if (! DXRestoreDupBoundary(x))
		goto error;
	    
	    break;
	}
	    
	case CLASS_CLIPPED:
	{
	    Object x;
		
	    if (! DXGetClippedInfo((Clipped)object, &x, NULL))
		goto error;
	    
	    if (! DXRestoreDupBoundary(x))
		goto error;
	    
	    break;
	}

	default:
	    return object;
    }

    return object;

error:
    return NULL;
}

static int
IsRegular(Object in)
{
    int    i;
    Array  array;
    Object child;
    int    result;

    switch(DXGetObjectClass(in))
    {
	case CLASS_GROUP:

	    i = 0;
	    while (NULL != (child = DXGetEnumeratedMember((Group)in, i++, NULL)))
	    {
		result = IsRegular(child);
		if (result == IS_NOT_REGULAR)
		    return result;
	    }

	    return result;

        case CLASS_FIELD:

	    if (DXEmptyField((Field)in))
		return IS_REGULAR_ERROR;
		
	    array = (Array)DXGetComponentValue((Field)in, "connections");
	    if (! array)
		return IS_REGULAR_ERROR;

	    if (DXQueryGridConnections(array, NULL, NULL))
		return IS_REGULAR;
	    else
		return IS_NOT_REGULAR;

        default:

	    DXSetError(ERROR_INVALID_DATA, "IsRegular: data not group or field");
	    return IS_REGULAR_ERROR;
    }
}

static char **
makeGlobalStrings(char **locPtrs)
{
    int i, j, k;
    char **l, **g, **gblPtrs;

    if (! locPtrs)
	return NULL;
    
    if (! *locPtrs)
	return NULL;

    for (i = 0, l = locPtrs; *l; l++, i++);

    gblPtrs = (char **)DXAllocate((i+1) * sizeof(char *));

    for (j = 0, l = locPtrs, g = gblPtrs; j <= i; j++, l++, g++)
    {
	if (! *l)
	    *g = NULL;
	else
	{
	    k = strlen(*l) + 1;
	    *g = DXAllocate(k * sizeof(char));
	    if (! *g)
	    {
		while (--j >= 0)
		    DXFree((Pointer)gblPtrs[j]);
		DXFree((Pointer)gblPtrs);
		return NULL;
	    }

	    strcpy(*g, *l);
	}
    }

    return gblPtrs;
}

static void
freeGlobalStrings(char **gblPtrs)
{
    char **g;

    if (gblPtrs)
    {
	for (g = gblPtrs; *g; g++)
	    DXFree((Pointer)*g);
	DXFree((Pointer)gblPtrs);
    }
}

Field
DXQueryOriginalSizes(Field partition, int *positions, int *connections)
{
    Array cArray, pArray;

    pArray = (Array)DXGetComponentValue(partition, "original positions");
    cArray = (Array)DXGetComponentValue(partition, "original connections");

    if (! pArray || ! cArray)
	return NULL;

    if (positions)
	DXGetArrayInfo(pArray, positions, NULL, NULL, NULL, NULL);

    if (connections)
	DXGetArrayInfo(cArray, connections, NULL, NULL, NULL, NULL);

    return partition;
}

Array
_dxfReRef(Array array, int n)
{
    Type     type;
    Category cat;
    int      rank, shape[32];
    int      nItems, nReferences;
    int      *ptr, i;

    DXGetArrayInfo(array, &nItems, &type, &cat, &rank, shape);

    if (type != TYPE_INT || cat != CATEGORY_REAL)
    {
	DXSetError(ERROR_INVALID_DATA, "referencing array must be INT/REAL");
	return NULL;
    }

    nReferences = nItems;
    for (i = 0; i < rank; i++)
	nReferences *= shape[i];
    
    ptr = (int *)DXGetArrayData(array);
    for (i = 0; i < nReferences; i++, ptr++)
	if (*ptr >= n)
	    *ptr = -1;

    return array;
}

#define TYPE int
#define LT(a,b) ((*(a))<(*(b)))
#define GT(a,b) ((*(a))>(*(b)))
#define QUICKSORT refsort

#include "qsort.c"

#define SetOrigName(buf, name)  sprintf((buf), "original %s", (name))

Error
_dxf_RemoveDupReferences(Field field)
{
    Array    iA, oA = NULL;
    Object   attr;
    int      i, n, nIn, nOut, r, s[64], nref, dup;
    char     *name, origName[256];
    int      *sPtr, *dPtr, *p0, *p1;
    Type     t;
    Category c;

    n = 0;
    while (NULL != (iA=(Array)DXGetEnumeratedComponentValue(field, n++, &name)))
    {
	SetOrigName(origName, name);

	if (! DXGetComponentValue(field, origName))
	    continue;

	if (DXGetComponentAttribute(field, name, "dep"))
	    continue;
	
	if (NULL == (attr = DXGetComponentAttribute(field, name, "ref")))
	    continue;
	
	if (! strcmp(name, "connections"))
	    continue;
	
	/*
	 * Remember: only single references are allowed
	 */
	DXGetArrayInfo(iA, &nIn, &t, &c, &r, s);

	if (nIn == 0)
	    continue;

	if (t != TYPE_INT ||
	    c != CATEGORY_REAL)
	{
	    DXSetError(ERROR_INVALID_DATA, 
			"invalid referential component: %s", name);
	    goto error;
	}

	nref = DXGetItemSize(iA) / sizeof(int);
	if (nref != 1)
	    continue;

	sPtr = (int *)DXGetArrayData(iA);

	refsort(sPtr, nIn);

	p0 = sPtr;
	p1 = sPtr+1;
	nOut = 1;
	for (i = 1; i < nIn; i++, p1++)
	    if (*p0 != *p1)
	    {
		p0 = p1;
		nOut++;
	    }
	
	if (nIn != nOut)
	{
	    oA = DXNewArrayV(t, c, r, s);
	    if (! oA)
		goto error;
	    
	    if (! DXAddArrayData(oA, 0, nOut, NULL))
		goto error;
	    
	    dPtr = (int *)DXGetArrayData(oA);

	    *dPtr = *sPtr++;
	    for (i = 1; i < nIn; i++, sPtr++)
		if (*dPtr != *sPtr)
		{
		    dPtr++;
		    *dPtr = *sPtr;
		}
	    
	    if (! DXSetComponentValue(field, name, (Object)oA))
		goto error;
	    oA = NULL;
	}
    }

    return OK;

error:
    DXDelete((Object)oA);
    return ERROR;
}
	
