/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  Please
 * see the License for the specific language governing rights and
 * limitations under the License.
 *
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */
/*
	File:		AdminElementNode.cpp

	Contains:	Implements Admin Elements
					
	
	
*/


#ifndef __Win32__
	#include <unistd.h>		/* for getopt() et al */
#endif

#include <stdio.h>		/* for //printf */
#include <stdlib.h>		/* for getloadavg & other useful stuff */
#include <time.h>
#include "QTSS.h"
#include "QTSSAdminModule.h"
#include "OSArrayObjectDeleter.h"
#include "StringParser.h"
#include "StrPtrLen.h"
#include "QTSSModuleUtils.h"
#include "OSHashTable.h"
#include "OSMutex.h"
#include "StrPtrLen.h"
#include "OSRef.h"
#include "AdminElementNode.h"
#include "OSMemory.h"

static char* sParameterDelimeter = ";";
static char* sListDelimeter = ",";
static char* sAccess = "a=";
static char* sType = "t=";
static StrPtrLen sDoAllSPL("*");
static StrPtrLen sDoAllIndexIteratorSPL(":");

#define MEMORYDEBUGGING 0
#if MEMORYDEBUGGING
static SInt32 sMaxPtrs = 10000;
static void * sPtrArray[10000];
static char * sSourceArray[10000];
#endif

Bool16	ElementNode_DoAll(StrPtrLen* str)
{	
	Assert(str); 
	Bool16 isIterator = false;
	
	if ( str->Equal(sDoAllSPL) || str->Equal(sDoAllIndexIteratorSPL)) 
		isIterator = true;
		
	return isIterator;
}

void ElementNode_InitPtrArray()
{
#if MEMORYDEBUGGING
	memset(sPtrArray, 0, sizeof(sPtrArray));
	memset(sSourceArray, 0, sizeof(sSourceArray));
#endif
}

void ElementNode_InsertPtr(void *ptr, char * src)
{
#if MEMORYDEBUGGING
	if (ptr == NULL)
		return;

	for (SInt32 index = 0; index < sMaxPtrs; index ++)
	{
		if (sPtrArray[index] == NULL)
		{	sPtrArray[index] =ptr;
			sSourceArray[index] = src;
			//printf("%s INSERTED ptr=%lu countPtrs=%ld\n",src,(UInt32) ptr, ElementNode_CountPtrs());	
			return;
		}	
	}
	
	printf("ElementNode_InsertPtr no space in ptr array\n");
	Assert(0);
#endif
}

Bool16 ElementNode_FindPtr(void *ptr, char * src)
{	// use for validating duplicates at some point
#if MEMORYDEBUGGING
	if (ptr == NULL)
		return false;
		
	for (SInt32 index = 0; index < sMaxPtrs; index ++)
	{	if (sPtrArray[index] == ptr)
			return true;
	}
	
#endif
	return false;
}

void ElementNode_RemovePtr(void *ptr, char * src)
{	
#if MEMORYDEBUGGING
	if (ptr == NULL)
		return;
		
	SInt16 foundCount = 0;
	for (SInt32 index = 0; index < sMaxPtrs; index ++)
	{
		if (sPtrArray[index] == ptr)
		{	
			sPtrArray[index] = NULL;
			sSourceArray[index] = NULL;
			//printf("%s REMOVED ptr countPtrs=%ld\n",src,ElementNode_CountPtrs());
			foundCount ++; // use for validating duplicates at some point
			return;
		}	
	}
	
	if (foundCount == 0)
	{	printf("PTR NOT FOUND ElementNode_RemovePtr %s ptr=%ld countPtrs=%ld\n",src,(UInt32) ptr,ElementNode_CountPtrs());
		Assert(0);
	}
#endif
}

SInt32 ElementNode_CountPtrs()
{
#if MEMORYDEBUGGING
	SInt32 count = 0;
	for (SInt32 index = 0; index < sMaxPtrs; index ++)
	{
		if (sPtrArray[index] != NULL)
			count ++;
	}
	
	return count;
#else
	return 0;
#endif
}

void ElementNode_ShowPtrs()
{
#if MEMORYDEBUGGING
	for (SInt32 index = 0; index < sMaxPtrs; index ++)
	{
		if (sPtrArray[index] != NULL)
			printf("ShowPtrs ptr=%lu source=%s\n", (UInt32)sPtrArray[index],sSourceArray[index]); 
	}
#endif
}

void PRINT_STR(StrPtrLen *spl)
{
	
	if (spl && spl->Ptr && spl->Ptr[0] != 0)
	{	char buff[1024] = {0};
		memcpy (buff,spl->Ptr, spl->Len);
		printf("%s len=%lu\n",buff,spl->Len);
	}
	else
	{	printf("(null)\n");
	}
}

void COPYBUFFER(char *dest,char *src,SInt8 size)
{
	if ( (dest != NULL) && (src != NULL) && (size > 0) ) 
		memcpy (dest, src, size);
	else
		Assert(0);
};

char* NewCharArrayCopy(StrPtrLen *theStringPtr)
{
	char* newArray = NULL;
	if (theStringPtr != NULL)
	{
		newArray = NEW char[theStringPtr->Len + 1];  
		if (newArray != NULL) 
		{	memcpy(newArray, theStringPtr->Ptr,theStringPtr->Len);
			newArray[theStringPtr->Len] = 0;
		}
	}
	return newArray;
}



ElementNode::ElementNode()
{
	fDataSource		= NULL;
	fNumFields		= 0;
	fPathLen		= 0;
	fInitialized	= false;

	fFieldIDs		= NULL;
	fFieldDataPtrs	= NULL;
	fFieldOSRefPtrs = NULL;
	fParentNodePtr	= NULL;
 	fElementMap 	= NULL;
 	fSelfPtr		= NULL;
 	fPathBuffer[0]=0;
 	fPathSPL.Set(fPathBuffer,0);
 	fIsTop = false;
 	fDataFieldsType = eDynamic;

};

void ElementNode::Initialize(SInt32 index, ElementNode *parentPtr, QueryURI *queryPtr, StrPtrLen *currentSegmentPtr,QTSS_Initialize_Params *initParams,QTSS_Object nodeSource, DataFieldsType dataFieldsType)
{ 	
	//printf("------ ElementNode::Initialize ---------\n");
	
	if (!fInitialized)
	{
		SetParentNode(parentPtr);
		SetSource(nodeSource);
		
		SetNodeInfo(parentPtr->GetNodeInfoPtr(index));
		SetNodeName(parentPtr->GetName(index));
		SetMyElementDataPtr(parentPtr->GetElementDataPtr(index));

		fDataFieldsType = dataFieldsType;
		
		StrPtrLen nextSegment;
		StrPtrLen nextnextSegment;
		(void) queryPtr->NextSegment(currentSegmentPtr, &nextSegment);		
		(void) queryPtr->NextSegment(&nextSegment, &nextnextSegment);
		Bool16 forceAll = nextSegment.Equal(sDoAllIndexIteratorSPL) | nextnextSegment.Equal(sDoAllIndexIteratorSPL);
		
		if (GetFields() == NULL)
			InitializeAllFields(true, NULL, nodeSource,queryPtr,currentSegmentPtr,forceAll);
			
		fInitialized = true;
	}
	SetupNodes(queryPtr,currentSegmentPtr, initParams);
	
};


ElementNode::~ElementNode()
{
	
	//printf("ElementNode::~ElementNode delete %s Element Node # fields = %lu\n",GetNodeName(), fNumFields);
	
	for(SInt32 index = 0; !IsStopItem(index) ; index ++)
	{
		OSRef *theRefPtr = GetOSRef(index);
		if (theRefPtr != NULL )
		{
			//printf("deleting hash entry of %s \n", GetName(index));
			SetOSRef(index,NULL);
			(fElementMap->GetHashTable())->Remove(theRefPtr);
			delete (OSRef*) theRefPtr;  ElementNode_RemovePtr(theRefPtr,"ElementNode::~ElementNode OSRef *");
		}
		
		char *dataPtr = GetElementDataPtr(index);
		if (dataPtr != NULL)
		{
			SetElementDataPtr(index,NULL,IsNodeElement(index));
		}
	}
	
	delete fElementMap;  ElementNode_RemovePtr(fElementMap,"ElementNode::~ElementNode fElementMap");
	
	fElementMap = NULL;
	
	UInt32 i = 0;
	for (i = 0; i < GetNumFields(); i ++)
	{	SetElementDataPtr(i,NULL, IsNodeElement(i)) ;
		fFieldDataPtrs[i] = NULL;
	}
	delete fFieldDataPtrs; ElementNode_RemovePtr(fFieldDataPtrs,"ElementNode::~ElementNode fFieldDataPtrs");
	fFieldDataPtrs = NULL;
	
	for (i = 0; i < GetNumFields(); i ++)
	{	delete fFieldOSRefPtrs[i]; ElementNode_RemovePtr(fFieldOSRefPtrs[i],"ElementNode::~ElementNode fFieldOSRefPtrs");
		fFieldOSRefPtrs[i] = NULL;
	}
	delete fFieldOSRefPtrs;  ElementNode_RemovePtr(fFieldOSRefPtrs,"ElementNode::~ElementNode fFieldOSRefPtrs");
	fFieldOSRefPtrs = NULL;
			
	if (fDataFieldsType == eDynamic)
	{	delete fFieldIDs;  ElementNode_RemovePtr(fFieldIDs,"ElementNode::~ElementNode fFieldIDs");
		fFieldIDs = NULL;
	}
		
	SetNodeName(NULL);

};

QTSS_Error ElementNode::AllocateFields(UInt32 numFields)
{
	//printf("-------- ElementNode::AllocateFields ----------\n");
	//printf("ElementNode::AllocateFields numFields=%lu\n",numFields);
	
	QTSS_Error err = QTSS_NotEnoughSpace;
	
	Assert(GetNumFields() == 0);
	SetNumFields(numFields);

	if (numFields > 0) do
	{	
		Assert(fFieldIDs == NULL);
		fFieldIDs = NEW ElementNode::ElementDataFields[numFields]; ElementNode_InsertPtr(fFieldIDs,"ElementNode::AllocateFields fFieldIDs array");
		Assert(fFieldIDs != NULL);
		if (fFieldIDs == NULL) break;
		memset(fFieldIDs, 0, numFields * sizeof(ElementNode::ElementDataFields));
		
		Assert(fElementMap == NULL);
		fElementMap = NEW OSRefTable();  ElementNode_InsertPtr(fElementMap,"ElementNode::AllocateFields fElementMap OSRefTable");
		Assert(fElementMap != NULL);
		if (fElementMap == NULL) break;
		
		Assert(fFieldDataPtrs == NULL);
		fFieldDataPtrs = NEW char*[numFields]; ElementNode_InsertPtr(fFieldDataPtrs,"ElementNode::AllocateFields fFieldDataPtrs array");
		Assert(fFieldDataPtrs != NULL);
		if (fFieldDataPtrs == NULL) break;
		memset(fFieldDataPtrs, 0, numFields * sizeof(char*));
			
		Assert(fFieldOSRefPtrs == NULL);
		fFieldOSRefPtrs = NEW OSRef*[numFields];  ElementNode_InsertPtr(fFieldOSRefPtrs,"ElementNode::AllocateFields fFieldDataPtrs array");
		Assert(fFieldOSRefPtrs != NULL);
		if (fFieldOSRefPtrs == NULL) break;
		memset(fFieldOSRefPtrs, 0, numFields * sizeof(OSRef*));
		
		err = QTSS_NoErr;
	} while (false);
	
	return err;	
};




void ElementNode::SetFields(UInt32 i, QTSS_Object attrInfoObject)
{
	//printf("------- ElementNode::SetFields -------- \n");

	UInt32 ioLen = 0;
	QTSS_Error err = QTSS_NoErr;
	if(fFieldIDs[i].fFieldName[0] != 0)
		return;
		
	if(fFieldIDs[i].fFieldName[0] == 0)
	{
		fFieldIDs[i].fFieldLen = eMaxAttributeNameSize;
		err = QTSS_GetValue (attrInfoObject, qtssAttrName,0, &fFieldIDs[i].fFieldName,&fFieldIDs[i].fFieldLen);
		Assert(err == QTSS_NoErr);	
		if (fFieldIDs[i].fFieldName != NULL)
			fFieldIDs[i].fFieldName[fFieldIDs[i].fFieldLen] = 0;
	}
	
	ioLen = sizeof(fFieldIDs[i].fAPI_ID);
	err = QTSS_GetValue (attrInfoObject, qtssAttrID,0, &fFieldIDs[i].fAPI_ID, &ioLen);
	Assert(err == QTSS_NoErr);	
	
	ioLen = sizeof(fFieldIDs[i].fAPI_Type);
	err = QTSS_GetValue (attrInfoObject, qtssAttrDataType,0, &fFieldIDs[i].fAPI_Type, &ioLen);
	Assert(err == QTSS_NoErr);	
	if (fFieldIDs[i].fAPI_Type == 0 || err != QTSS_NoErr)
	{
		//printf("QTSS_GetValue err = %ld attrInfoObject=%lu qtssAttrDataType = %lu \n",err, (UInt32)  attrInfoObject, (UInt32) fFieldIDs[i].fAPI_Type);
	}
	
	if (fFieldIDs[i].fAPI_Type == qtssAttrDataTypeQTSS_Object)
		fFieldIDs[i].fFieldType = eNode;
		
	ioLen = sizeof(fFieldIDs[i].fAccessPermissions);
	err = QTSS_GetValue (attrInfoObject, qtssAttrPermissions,0, &fFieldIDs[i].fAccessPermissions, &ioLen);
	Assert(err == QTSS_NoErr);	
	
	fFieldIDs[i].fAccessData[0] = 0;
	if (fFieldIDs[i].fAccessPermissions & qtssAttrModeRead)
	{	strcat(fFieldIDs[i].fAccessData, "r");
	}
	
	if (fFieldIDs[i].fAccessPermissions & qtssAttrModeWrite && fFieldIDs[i].fAPI_Type != qtssAttrDataTypeQTSS_Object)
	{	strcat(fFieldIDs[i].fAccessData, "w");
	}
	
	if (fFieldIDs[i].fAccessPermissions & qtssAttrModeInstanceAttrAllowed && fFieldIDs[i].fAPI_Type == qtssAttrDataTypeQTSS_Object)
	{	strcat(fFieldIDs[i].fAccessData, "w");
	}

	if (fFieldIDs[i].fAccessPermissions & qtssAttrModePreempSafe)
	{	strcat(fFieldIDs[i].fAccessData, "p");
	}

	fFieldIDs[i].fAccessLen = strlen(fFieldIDs[i].fAccessData);
	
	//printf("ElementNode::SetFields name=%s api_id=%ld \n",fFieldIDs[i].fFieldName, fFieldIDs[i].fAPI_ID);
	//DebugShowFieldDataType(i);	
};


ElementNode* ElementNode::CreateArrayAttributeNode(UInt32 index, QTSS_Object source, QTSS_Object attributeInfo, UInt32 arraySize )
{
	//printf("------- ElementNode::CreateArrayAttributeNode --------\n");
	//printf("ElementNode::CreateArrayAttributeNode name = %s index = %lu arraySize =%lu \n",fFieldIDs[index].fFieldName, index,arraySize);

	ElementDataFields* fieldPtr = NULL;
	SetFields(index, attributeInfo);
	fFieldIDs[index].fFieldType = eArrayNode;
	
	ElementNode* nodePtr = NEW ElementNode(); ElementNode_InsertPtr(nodePtr,"ElementNode::CreateArrayAttributeNode ElementNode*");
	this->SetElementDataPtr(index,(char *) nodePtr, true);
	Assert(nodePtr!=NULL);
	if (NULL == nodePtr) return NULL;
	
	nodePtr->SetSource(source); // the node's API source
	nodePtr->AllocateFields(arraySize);	
	
	if (this->GetNodeInfoPtr(index) == NULL)
	{	//printf("ElementNode::CreateArrayAttributeNode index = %lu this->GetNodeInfoPtr(index) == NULL \n",index);
	}
	nodePtr->SetNodeInfo(this->GetNodeInfoPtr(index));
	
	for (UInt32 i = 0; !nodePtr->IsStopItem(i); i++)
	{	
		fieldPtr = nodePtr->GetElementFieldPtr(i);
		Assert(fieldPtr != NULL);
		
		nodePtr->SetFields(i, attributeInfo);
		
		fieldPtr->fIndex = i; // set the API attribute index

		// set the name of the field to the array index 
		fieldPtr->fFieldName[0]= 0; 
		sprintf(fieldPtr->fFieldName,"%lu",i);
		fieldPtr->fFieldLen = ::strlen(fieldPtr->fFieldName);
		
		if (fieldPtr->fAPI_Type != qtssAttrDataTypeQTSS_Object)
		{
			//printf("ElementNode::CreateArrayAttributeNode array field index = %lu name = %s api Source = %lu \n", (UInt32)  i,fieldPtr->fFieldName, (UInt32) source);
			fieldPtr->fAPISource = source; // the attribute's source is the same as node source
		}
		else 
		{	fieldPtr->fFieldType = eNode;
			// this is an array of objects so record each object as the source for a new node
			UInt32 sourceLen = sizeof(fieldPtr->fAPISource);
			QTSS_Error err = QTSS_GetValue (source,fieldPtr->fAPI_ID,fieldPtr->fIndex, &fieldPtr->fAPISource, &sourceLen);
			Warn(err == QTSS_NoErr);
			if (err != QTSS_NoErr)
			{	//printf("Error Getting Value for %s type = qtssAttrDataTypeQTSS_Object err = %lu\n", fieldPtr->fFieldName,err);
				fieldPtr->fAPISource = NULL;
			}
			
			QTSS_AttributeID id;
			Bool16 foundFilteredAttribute = GetFilteredAttributeID(GetMyName(),nodePtr->GetMyName(), &id);
			if (foundFilteredAttribute)
			{	GetFilteredAttributeName(fieldPtr,id);
			}

			//printf("ElementNode::CreateArrayAttributeNode array field index = %lu name = %s api Source = %lu \n", i,fieldPtr->fFieldName, (UInt32) fieldPtr->fAPISource);
		}

		nodePtr->fElementMap->Register(nodePtr->GetOSRef(i));
	}
	nodePtr->SetNodeName(GetName(index));
	nodePtr->SetParentNode(this);
	nodePtr->SetSource(source);
	nodePtr->fInitialized = true;
	
	return nodePtr;
	
}

void ElementNode::InitializeAllFields(Bool16 allocateFields, QTSS_Object defaultAttributeInfo, QTSS_Object source, QueryURI *queryPtr, StrPtrLen *currentSegmentPtr , Bool16 forceAll =false)
{
	//printf("------- ElementNode::InitializeAllFields -------- \n");
	
	QTSS_Error err = QTSS_NoErr;
	QTSS_Object theAttributeInfo;
	
	if (allocateFields)
	{			
		UInt32 numFields = this->CountAttributes(source);
		err = AllocateFields( numFields);
		//printf("ElementNode::InitializeAllFields AllocateFields numFields =  %lu error = %ld \n",numFields, err);
	}
	
	if (err == QTSS_NoErr)
	{	
		UInt32 numValues = 0;

		for (UInt32 i = 0; !IsStopItem(i); i++)
		{	
			if (defaultAttributeInfo == NULL)
			{	err = QTSS_GetAttrInfoByIndex(source, i, &theAttributeInfo);
				Assert(err == QTSS_NoErr);			
				if (err != QTSS_NoErr)
				{	//printf("QTSS_GetAttrInfoByIndex returned err = %lu \n",err);
				}
			}
			else
			{	theAttributeInfo = defaultAttributeInfo; 
			}
			
			SetFields(i, theAttributeInfo);			
			
			if ((SInt32) fFieldIDs[i].fAPI_ID < 0)
			{	//printf("ElementNode::InitializeAllFields name = %s index = %ld numValues =%lu \n",fFieldIDs[i].fFieldName, (SInt32) fFieldIDs[i].fAPI_ID,numValues);
			}
			numValues = this->CountValues(source, fFieldIDs[i].fAPI_ID);
			//printf("ElementNode::InitializeAllFields name = %s index = %lu numValues =%lu \n",fFieldIDs[i].fFieldName, fFieldIDs[i].fAPI_ID,numValues);

			QTSS_AttributeID id;
			Bool16 foundFilteredAttribute = GetFilteredAttributeID(GetMyName(),GetName(i), &id);
			
			StrPtrLen nextSegment;
			(void) queryPtr->NextSegment(currentSegmentPtr, &nextSegment);

			if (forceAll || nextSegment.Equal(sDoAllIndexIteratorSPL) || queryPtr->IndexParam() || numValues > 1 || foundFilteredAttribute)
			{		
				ElementNode *nodePtr = CreateArrayAttributeNode(i, source, theAttributeInfo,numValues);
				Assert(nodePtr != NULL);
				/*
				if (NULL == nodePtr) 
				{	//printf("ElementNode::InitializeAllFields(NULL == CreateArrayAttributeNode  nodePtr\n");
				}
				if (NULL == GetElementDataPtr(i)) 
				{	//printf("ElementNode::InitializeAllFields(NULL == GetElementDataPtr (i=%lu) nodePtr=%lu \n",i, (UInt32) nodePtr);
				}
				*/
					
			}
			else
			{
				//printf("ElementNode::InitializeAllFields field index = %lu name = %s api Source = %lu \n", i,fFieldIDs[i].fFieldName, (UInt32) source);
			}
			
			err = fElementMap->Register(GetOSRef(i));
			if (err != QTSS_NoErr)
			{	//printf("ElementNode::InitializeAllFields  Register returned err = %lu field = %s node=%s \n",err,GetName(i),GetMyName());
			}
			Assert(err == QTSS_NoErr);	
		}
	}
};


void ElementNode::SetNodeInfo(ElementDataFields *nodeInfoPtr)
{
	if (nodeInfoPtr == NULL)
	{
		//printf("---- SetNodeInfo nodeInfoPtr = NULL \n");
	}
	else
	{
		//printf("---- SetNodeInfo nodeInfoPtr name = %s \n",nodeInfoPtr->fFieldName);
		fSelfPtr = nodeInfoPtr;
	}
};


void ElementNode::SetNodeName(char *namePtr)
{
	if (namePtr == NULL)
	{	delete fNodeNameSPL.Ptr; ElementNode_RemovePtr(fNodeNameSPL.Ptr,"ElementNode::SetNodeName char* ");
		fNodeNameSPL.Set(NULL, 0);
		return;
	}
	
	if (fNodeNameSPL.Ptr != NULL) 
	{	delete fNodeNameSPL.Ptr; ElementNode_RemovePtr(fNodeNameSPL.Ptr,"ElementNode::SetNodeName char* ");
		fNodeNameSPL.Set(NULL, 0);
	}
	//printf(" ElementNode::SetNodeName new NodeName = %s \n",namePtr);
	int len = ::strlen(namePtr); 	
	fNodeNameSPL.Ptr = NEW char[len + 1]; ElementNode_InsertPtr(fNodeNameSPL.Ptr,"ElementNode::SetNodeName ElementNode* chars");
	fNodeNameSPL.Len = len; 
	memcpy(fNodeNameSPL.Ptr,namePtr,len);
	fNodeNameSPL.Ptr[len] = 0;
};

ElementNode::ElementDataFields *ElementNode::GetElementFieldPtr(SInt32 index) 
{ 
	ElementNode::ElementDataFields *resultPtr = NULL; 
	Assert (fFieldIDs != NULL);
	Assert ((index >= 0) && (index < (SInt32) fNumFields));
   	if ((index >= 0) && (index < (SInt32) fNumFields)) 
		resultPtr = &fFieldIDs[index]; 
	return resultPtr; 
}

char *ElementNode::GetElementDataPtr(SInt32 index) 
{ 
	char *resultPtr = NULL; 
	Assert((index >= 0) && (index < (SInt32) fNumFields));
	if (fInitialized && (fFieldDataPtrs != NULL) && (index >= 0) && (index < (SInt32) fNumFields)) 
	{	resultPtr = fFieldDataPtrs[index]; 
	}
	return resultPtr; 
}

void ElementNode::SetElementDataPtr(SInt32 index,char *data, Bool16 isNode) 
{ 
	//printf("------ElementNode::SetElementDataPtr----- \n");
	//printf("ElementNode::SetElementDataPtr index = %ld fNumFields = %ld \n", index,fNumFields);
	Assert	((index >= 0) && (index < (SInt32) fNumFields));
	if 		((index >= 0) && (index < (SInt32) fNumFields)) 
	{	//Assert(fFieldDataPtrs[index] == NULL);
		if (fDataFieldsType != eStatic)
		{	
			if (isNode)
			{	delete (ElementNode*) fFieldDataPtrs[index];ElementNode_RemovePtr(fFieldDataPtrs[index],"ElementNode::SetElementDataPtr ElementNode* fFieldDataPtrs");
			}
			else
			{	delete fFieldDataPtrs[index]; ElementNode_RemovePtr(fFieldDataPtrs[index],"ElementNode::SetElementDataPtr char* fFieldDataPtrs");
			}
		}
		fFieldDataPtrs[index] = data; 
		//printf("ElementNode::SetElementDataPtr index = %ld \n", index);
	}
}



inline void ElementNode::DebugShowFieldDataType(SInt32 /*index*/)
{
	//char field[100];
	//field[0] = ' ';
	//char* typeStringPtr = GetAPI_TypeStr(index);
	//printf("debug: %s=%s\n",GetName(index),typeStringPtr);
		
}

inline void ElementNode::DebugShowFieldValue(SInt32 /*index*/)
{
	//printf("debug: %s=%s\n",GetName(index),GetElementDataPtr(index));
}

ElementNode::ElementDataFields *ElementNode::GetNodeInfoPtr(SInt32 index) 
{ 
	ElementNode::ElementDataFields *resultPtr = GetElementFieldPtr(index);
	Assert (resultPtr != NULL);
	
	if ((resultPtr != NULL) && ((eNode != resultPtr->fFieldType) && (eArrayNode != resultPtr->fFieldType) )) 
	 	resultPtr = NULL; 
	return resultPtr; 
}		


void ElementNode::SetUpSingleNode(QueryURI *queryPtr,  StrPtrLen *currentSegmentPtr, StrPtrLen *nextSegmentPtr, SInt32 index, QTSS_Initialize_Params *initParams) 
{
	//printf("--------ElementNode::SetUpSingleNode ------------\n");
	if (queryPtr && currentSegmentPtr && nextSegmentPtr&& initParams) do
	{
		if (!queryPtr->RecurseParam() && (nextSegmentPtr->Len == 0) ) break;
	
		ElementNode::ElementDataFields *theNodePtr = GetNodeInfoPtr(index);	
		if (NULL == theNodePtr) 
		{
			//printf(" ElementNode::SetUpSingleNode (NULL == theNodePtr(%ld)) name=%s \n",index,GetName(index));
			break;
		}
		
		if (!IsNodeElement(index) ) 
		{
			//printf(" ElementNode::SetUpSingleNode (apiType != qtssAttrDataTypeQTSS_Object) \n");
			break;
		}
		
		// filter unnecessary nodes		
		char *nodeName = GetName(index); 
		if (nodeName != NULL)
		{	StrPtrLen nodeNameSPL(nodeName);
			if	(	(!nodeNameSPL.Equal(*nextSegmentPtr) && !ElementNode_DoAll(nextSegmentPtr))
					&&
					!(queryPtr->RecurseParam() && (nextSegmentPtr->Len == 0))
				)
			{
				//printf(" ElementNode::SetUpSingleNode SPL TEST SKIP NodeElement= %s\n",GetName(index));
				//printf("ElementNode::SetUpAllNodes skip nextSegmentPtr=");PRINT_STR(nextSegmentPtr);
				break;
			}
				
		}
		
		ElementNode *nodePtr = NULL;
		nodePtr = (ElementNode *) GetElementDataPtr(index);		
		if (nodePtr == NULL)
		{	
			//printf("ElementNode::SetUpSingleNode %s nodePtr == NULL make NEW nodePtr index = %ld\n", GetMyName(),index);
			nodePtr = NEW ElementNode(); ElementNode_InsertPtr(nodePtr,"ElementNode::SetUpSingleNode ElementNode* NEW ElementNode() ");		
			SetElementDataPtr(index,(char *) nodePtr, true); 
		}
		
		if (nodePtr != NULL)
		{
			StrPtrLen tempSegment;
			( void)queryPtr->NextSegment(nextSegmentPtr, &tempSegment);
			currentSegmentPtr = nextSegmentPtr;
			nextSegmentPtr = &tempSegment;
			

			if (!nodePtr->fInitialized)
			{
				//printf("ElementNode::SetUpSingleNode Node !fInitialized -- Initialize %s\n",GetName(index));
				//printf("ElementNode::SetUpSingleNode GetValue source = %lu name = %s id = %lu \n",(UInt32)  GetSource(),(UInt32)  GetName(index),(UInt32) GetAPI_ID(index));
				
				ElementDataFields* fieldPtr = GetElementFieldPtr(index);
				if (fieldPtr != NULL && fieldPtr->fAPI_Type == qtssAttrDataTypeQTSS_Object)
				{	UInt32 sourceLen = sizeof(fieldPtr->fAPISource);
					(void) QTSS_GetValue (GetSource(),fieldPtr->fAPI_ID,fieldPtr->fIndex, &fieldPtr->fAPISource, &sourceLen);
				}
			
				QTSS_Object theSourceObject = GetAPISource(index);
				//Warn(theSourceObject != NULL);

				nodePtr->Initialize(index, this, queryPtr,nextSegmentPtr,initParams, theSourceObject, eDynamic);
				nodePtr->SetUpAllElements(queryPtr, currentSegmentPtr,nextSegmentPtr, initParams);
				fInitialized = true;
	
				break;

			}
			else
			{
				nodePtr->SetUpAllElements(queryPtr, currentSegmentPtr,nextSegmentPtr, initParams);		
			}
		}
		
	} while (false);
	
	return;
}

Bool16 ElementNode::SetUpOneDataField( UInt32 index)
{
	//printf("----ElementNode::SetUpOneDataField----\n");		
	//printf(" ElementNode::SetUpOneDataField parent = %s field name=%s\n",GetNodeName(), GetName(index));	
	
	QTSS_AttributeID inID = GetAPI_ID(index); 
	Bool16 isNodeResult = IsNodeElement(index);
	char *testPtr =  GetElementDataPtr(index);
	//Warn(NULL == testPtr);
	if (NULL != testPtr) 
	{	//printf(" ElementNode::SetUpOneDataField skip field already setup parent = %s field name=%s\n",GetNodeName(), GetName(index));	
		return isNodeResult;
	}
	
	if (!isNodeResult)
	{
		//printf("ElementNode::SetUpOneDataField %s Source=%lu Field index=%lu API_ID=%lu value index=%lu\n",GetName(index),GetSource(), index,inID,GetAttributeIndex(index));	
		SetElementDataPtr(index, NewIndexElement (GetSource() , inID, GetAttributeIndex(index)), false);
	}
	else
	{
		//printf("ElementNode::SetUpOneDataField %s Source=%lu Field index=%lu API_ID=%lu value index=%lu\n",GetName(index),(UInt32) GetSource(),(UInt32)  index,(UInt32) inID,(UInt32) GetAttributeIndex(index));	
		//printf("ElementNode::SetUpOneDataField %s IsNodeElement index = %lu\n",GetName(index),(UInt32)  index);	
		//DebugShowFieldDataType(index);
	}

	DebugShowFieldValue( index);

	return isNodeResult;
}

void ElementNode::SetUpAllElements(QueryURI *queryPtr, StrPtrLen *currentSegmentPtr,StrPtrLen *nextSegmentPtr,  QTSS_Initialize_Params *initParams) 
{
	//printf("---------ElementNode::SetUpAllElements------- \n");

	for(SInt32 index = 0; !IsStopItem(index); index ++)
	{
		SetUpSingleElement(queryPtr, currentSegmentPtr,nextSegmentPtr, index,initParams);
	}
}




void ElementNode::SetUpSingleElement(QueryURI *queryPtr, StrPtrLen *currentSegmentPtr,StrPtrLen *nextSegmentPtr, SInt32 index, QTSS_Initialize_Params *initParams) 
{
	//printf("---------ElementNode::SetUpSingleElement------- \n");
	StrPtrLen indexNodeNameSPL;
	GetNameSPL(index,&indexNodeNameSPL);
	if 	(	(queryPtr->RecurseParam() && (nextSegmentPtr->Len == 0))
			|| 
			(indexNodeNameSPL.Equal(*nextSegmentPtr) || ElementNode_DoAll(nextSegmentPtr)) 
		) // filter unnecessary elements		
	{
	
		Bool16 isNode = SetUpOneDataField((UInt32) index);		
		if (isNode)
		{
			//printf("ElementNode::SetUpSingleElement isNode=true calling SetUpSingleNode \n");
			SetUpSingleNode(queryPtr,currentSegmentPtr, nextSegmentPtr, index, initParams);
		}
	}
	else
	{	//printf("ElementNode::SetUpSingleElement filter element=%s\n",GetName(index));
	}
}


void ElementNode::SetUpAllNodes(QueryURI *queryPtr, StrPtrLen *currentSegmentPtr, StrPtrLen *nextSegmentPtr, QTSS_Initialize_Params *initParams) 
{
	//printf("--------ElementNode::SetUpAllNodes------- \n");
	for(SInt32 index = 0; !IsStopItem(index); index ++)
	{
		if (!queryPtr->RecurseParam() && (nextSegmentPtr->Len == 0) ) break;
		
		//printf("ElementNode::SetUpAllNodes index = %ld nextSegmentPtr=", index);PRINT_STR(nextSegmentPtr);
		StrPtrLen indexNodeNameSPL;
		GetNameSPL(index,&indexNodeNameSPL);
		if 	(	IsNodeElement(index) 
				&&
				(	(queryPtr->RecurseParam() && (nextSegmentPtr->Len == 0))
					|| 
					(indexNodeNameSPL.Equal(*nextSegmentPtr) || ElementNode_DoAll(nextSegmentPtr)) 
				)
			) // filter unnecessary nodes		
			SetUpSingleNode(queryPtr, currentSegmentPtr, nextSegmentPtr, index, initParams);
		else
		{
			//printf("ElementNode::SetUpAllNodes skip index = %ld indexNodeName=", index);PRINT_STR(&indexNodeNameSPL);
			//printf("ElementNode::SetUpAllNodes skip nextSegmentPtr=");PRINT_STR(nextSegmentPtr);
		}
	}
}

QTSS_Error ElementNode::GetAttributeSize (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex, UInt32* outLenPtr)
{
	return QTSS_GetValue (inObject, inID, inIndex, NULL, outLenPtr);
}

char *ElementNode::NewIndexElement (QTSS_Object inObject, QTSS_AttributeID inID, UInt32 inIndex)
{	
	QTSS_Error err = QTSS_NoErr;
	char *resultPtr = NULL;

	Assert(inObject != NULL);
	
	if (inObject != NULL)
	{	err = QTSS_GetValueAsString (inObject, inID, inIndex, &resultPtr); ElementNode_InsertPtr(resultPtr,"ElementNode::NewIndexElement QTSS_GetValueAsString ");
		if (err != QTSS_NoErr)
		{	//printf("ElementNode::NewIndexElement QTSS_GetValueAsString object= %lu id=%lu index=%lu err= %ld \n",inObject,inID, inIndex, err);
		}
	}
	return resultPtr;
}


inline	SInt32 ElementNode::ResolveSPLKeyToIndex(StrPtrLen *keyPtr)
{ 	
	SInt32 index = -1; 
	OSRef* osrefptr = NULL; 
			
	if (fElementMap != NULL && keyPtr != NULL && keyPtr->Len > 0) 
	{	osrefptr = fElementMap->Resolve(keyPtr);
		if (osrefptr != NULL) 
			index = (SInt32) osrefptr->GetObject();
	}

	return index;	
}


UInt32 ElementNode::CountAttributes(QTSS_Object source)
{
	//printf("------ElementNode::CountAttributes-------\n");
	//printf("ElementNode::CountAttributes SOURCE = %lu \n", (UInt32) source);

	UInt32 numFields = 0;

	(void) QTSS_GetNumAttributes (source, &numFields);
	
	//printf("ElementNode::CountAttributes %s = %lu \n",GetNodeName() ,numFields);

	return numFields;
}

UInt32 ElementNode::CountValues(QTSS_Object source, UInt32 apiID)
{
	//printf("------ElementNode::CountValues-------\n");
	UInt32 numFields = 0;
	
	(void) QTSS_GetNumValues (source, apiID, &numFields);

	//printf("ElementNode::CountValues %s = %lu \n",GetNodeName() ,numFields);

	return numFields;
}



OSRef* ElementNode::GetOSRef(SInt32 index)
{	
	StrPtrLen 	theName;
	OSRef* 		resultPtr = NULL;
	
	resultPtr = fFieldOSRefPtrs[index];
//		Assert(resultPtr != NULL);
	if (resultPtr == NULL)
	{	
		fFieldOSRefPtrs[index] = NEW OSRef(); Assert(fFieldOSRefPtrs[index] != NULL); ElementNode_InsertPtr(fFieldOSRefPtrs[index],"ElementNode::GetOSRef NEW OSRef() fFieldOSRefPtrs ");	
		GetNameSPL(index,&theName); Assert(theName.Len != 0);
		//printf("ElementNode::GetOSRef index = %ld name = %s \n", index, theName.Ptr);
		fFieldOSRefPtrs[index]->Set(theName,(void *) index);
		resultPtr = fFieldOSRefPtrs[index];
	}

	
	return resultPtr;
}

void ElementNode::SetOSRef(SInt32 index, OSRef* refPtr)
{
	Assert	((index >= 0) && (index < (SInt32) fNumFields));
	if 		(fInitialized && (index >= 0) && (index < (SInt32) fNumFields)) 
		fFieldOSRefPtrs[index] = refPtr; 
}

void ElementNode::GetFullPath(StrPtrLen *resultPtr)
{
	//printf("ElementNode::GetFullPath this node name %s \n",GetNodeName());

	Assert(fPathSPL.Ptr != NULL);	
	
	if (fPathSPL.Len != 0)
	{	
		resultPtr->Set(fPathSPL.Ptr,fPathSPL.Len);
		//printf("ElementNode::GetFullPath has path=%s\n",resultPtr->Ptr);
		return;
	}	
	
	ElementNode *parentPtr = GetParentNode();
	if (parentPtr != NULL)
	{
		StrPtrLen parentPath;
		parentPtr->GetFullPath(&parentPath);
		memcpy(fPathSPL.Ptr,parentPath.Ptr,parentPath.Len);
		fPathSPL.Ptr[parentPath.Len] = 0;
		fPathSPL.Len = parentPath.Len;
	}
	
	UInt32 nodeNameLen = GetNodeNameLen();
	if (nodeNameLen > 0)
	{
		fPathSPL.Len += nodeNameLen + 1;
		Assert(fPathSPL.Len < kmaxPathlen);
		if (fPathSPL.Len < kmaxPathlen)
		{	strcat(fPathSPL.Ptr, GetNodeName());
			strcat(fPathSPL.Ptr,"/"); 
			fPathSPL.Len = strlen(fPathSPL.Ptr);
		}
	 }

	resultPtr->Set(fPathSPL.Ptr,fPathSPL.Len);
	//printf("ElementNode::GetFullPath element=%s received full path=%s \n",GetMyName(),resultPtr->Ptr);
}

void ElementNode::RespondWithSelfAdd(QTSS_StreamRef inStream, QueryURI *queryPtr)
{
	static char *nullErr = "(null)";
	Bool16 nullData = false;
	QTSS_Error err = QTSS_NoErr;
	char messageBuffer[1024] = "";
	StrPtrLen bufferSPL(messageBuffer);
	
	//printf("ElementNode::RespondWithSelfAdd NODE = %s index = %ld \n",GetNodeName(), (SInt32) index);
	
	if (!fInitialized) 
	{	//printf("ElementNode::RespondWithSelfAdd not Initialized EXIT\n");
		return;
	}
	if (NULL == queryPtr) 
	{	//printf("ElementNode::RespondWithSelfAdd NULL == queryPtr EXIT\n");
		return;
	}
	
	if (NULL == inStream) 
	{	//printf("ElementNode::RespondWithSelfAdd NULL == inStream EXIT\n");
		return;
	}
	
	char *dataPtr = GetMyElementDataPtr();
	if (NULL == dataPtr) 
	{	//printf("ElementNode::RespondWithSelfAdd NULL == dataPtr EXIT\n");
		dataPtr = nullErr;
		nullData = true;
	}
	
	queryPtr->SetQueryHasResponse();	



#if CHECKACCESS
/*
	StrPtrLen *accessParamsPtr=queryPtr->GetAccess();
	if (accessParamsPtr == NULL)
	{
			UInt32 result = 400;
			sprintf(messageBuffer,  "Attribute Access is required");
			(void) queryPtr->EvalQuery(&result, messageBuffer);
			return;
	}	
	
	accessFlags = queryPtr->GetAccessFlags();	
	if (0 == (accessFlags & qtssAttrModeWrite)) 
	{
			UInt32 result = 400;
			sprintf(messageBuffer,  "Attribute must have write access");
			(void) queryPtr->EvalQuery(&result, messageBuffer);
			return;
	}	
*/
#endif


	StrPtrLen* valuePtr = queryPtr->GetValue();
	OSCharArrayDeleter value(NewCharArrayCopy(valuePtr));
	if (!valuePtr || !valuePtr->Ptr)
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "Attribute value is required");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}	


	StrPtrLen *typePtr = queryPtr->GetType();
	OSCharArrayDeleter dataType(NewCharArrayCopy(typePtr));
	if (!typePtr || !typePtr->Ptr)
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "Attribute type is required");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}	

	QTSS_AttrDataType attrDataType = qtssAttrDataTypeUnknown;
	if (typePtr && typePtr->Len > 0)
	{	
		err = QTSS_TypeStringToType(dataType.GetObject(), &attrDataType);
		Assert(err == QTSS_NoErr);	
		//printf("ElementNode::RespondWithSelfAdd theType=%s typeID=%lu \n",dataType.GetObject(), attrDataType);
	}

	//printf("ElementNode::RespondWithSelfAdd theValue= %s theType=%s typeID=%lu \n",value.GetObject(), typePtr->Ptr, attrDataType);
	char valueBuff[2048] = "";
	UInt32 len = 2048;
	err = QTSS_StringToValue(value.GetObject(),attrDataType, valueBuff, &len);
	if (err) 
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "QTSS_Error=%ld from ElementNode::RespondWithSelfAdd QTSS_ConvertStringToType",err);
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}

	if (GetMyFieldType() != eNode)
	{	UInt32 result = 500;
		sprintf(messageBuffer,  "Internal error");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}

	StrPtrLen *namePtr = queryPtr->GetName();
	OSCharArrayDeleter nameDeleter(NewCharArrayCopy(namePtr));
	if (!namePtr || !namePtr->Ptr || namePtr->Len == 0)
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "Missing name for attribute");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}	
	
	err = QTSS_AddInstanceAttribute(GetSource(),nameDeleter.GetObject(), NULL, attrDataType);
	//printf("QTSS_AddInstanceAttribute(source=%lu, name=%s, NULL, %d, %lu)\n",GetSource(),nameDeleter.GetObject(),attrDataType,accessFlags);
	if (err) 
	{	UInt32 result = 400;
		if (err == QTSS_AttrNameExists)
		{	sprintf(messageBuffer,  "The name %s already exists QTSS_Error=%ld from QTSS_AddInstanceAttribute",nameDeleter.GetObject(),err);
		}
		else
		{	sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_AddInstanceAttribute",err);
		}
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}
	QTSS_Object attrInfoObject;
	err = QTSS_GetAttrInfoByName(GetSource(), nameDeleter.GetObject(), &attrInfoObject);
	if (err) 
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_GetAttrInfoByName",err);
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}
	QTSS_AttributeID attributeID = 0;
	UInt32 attributeLen = sizeof(attributeID);
	err = QTSS_GetValue (attrInfoObject, qtssAttrID,0, &attributeID, &attributeLen);
	if (err) 
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_GetValue",err);
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}
	
	err = QTSS_SetValue (GetSource(), attributeID, 0, valueBuff, len);
	if (err) 
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_SetValue",err);
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}
	
}

void ElementNode::RespondWithSelf(QTSS_StreamRef inStream, QueryURI *queryPtr)
{
	//printf("ElementNode::RespondWithSelf = %s \n",GetNodeName());

	static char *nullErr = "(null)";
	if (QueryURI::kADDCommand == queryPtr->GetCommandID())
	{
		if (GetMyFieldType() == eArrayNode)
		{ 	RespondToAdd(inStream, 0,queryPtr);
		}
		else
		{	RespondWithSelfAdd(inStream,queryPtr);
		}
		
		return;
		
	}
	
	if (QueryURI::kDELCommand == queryPtr->GetCommandID())
	{	RespondToDel(inStream, GetMyKey(),queryPtr,true);
		return;	
	}
	
		
	if (GetNodeName() == NULL) 
	{	//printf("ElementNode::RespondWithSelf Node = %s is Uninitialized no name so LEAVE\n",GetNodeName() );
		return;
	}
	
	if (!fInitialized) 
	{	//printf("ElementNode::RespondWithSelf not Initialized EXIT\n");
		return;
	}
	
	if (NULL == queryPtr) 
	{	//printf("ElementNode::RespondWithSelf NULL == queryPtr EXIT\n");
		return;
	}

	if (queryPtr->fNumFilters > 0)
	{			
		Bool16 foundFilter = false;
		StrPtrLen*	theFilterPtr;
		for (SInt32 count = 0; count < queryPtr->fNumFilters; count ++)
		{
			theFilterPtr = queryPtr->GetFilter(count);
			if (theFilterPtr && theFilterPtr->Equal(StrPtrLen(GetMyName())) ) 
			{	foundFilter = true;
				//printf("ElementNode::RespondWithSelf found filter = ");PRINT_STR(theFilterPtr);
				break;
			}
		}
		if (!foundFilter) return;
	}
		
	StrPtrLen bufferSPL;

	UInt32 parameters = queryPtr->GetParamBits();
	parameters &= ~QueryURI::kRecurseParam; // clear recurse flag
	parameters &= ~QueryURI::kDebugParam; // clear verbose flag
	parameters &= ~QueryURI::kIndexParam; // clear index flag
	
	
	Bool16 isVerbosePath = 0 != (parameters & QueryURI::kVerboseParam);
	if (isVerbosePath) 
	{	
		parameters &= ~QueryURI::kVerboseParam; // clear verbose flag
		GetFullPath(&bufferSPL);
		(void)QTSS_Write(inStream, bufferSPL.Ptr, ::strlen(bufferSPL.Ptr), NULL, 0);
		//printf("ElementNode::RespondWithSelf Path=%s \n",bufferSPL.Ptr);
	}
	
	if (IsNodeElement())
	{	if (!isVerbosePath) // this node name already in path
		{
			(void)QTSS_Write(inStream, GetNodeName(), GetNodeNameLen(), NULL, 0);
			(void)QTSS_Write(inStream, "/", 1, NULL, 0);
			//printf("ElementNode::RespondWithSelf %s/ \n",GetNodeName());
		}
	}
	else
	{	//printf(" ****** ElementNode::RespondWithSelf NOT a node **** \n");
		(void)QTSS_Write(inStream, GetNodeName(), GetNodeNameLen(), NULL, 0);
		(void)QTSS_Write(inStream, "=", 1, NULL, 0);
		//printf(" %s=",GetNodeName());
			
		char *dataPtr = GetMyElementDataPtr();
		if (dataPtr == NULL)
		{
			(void)QTSS_Write(inStream, nullErr, ::strlen(nullErr), NULL, 0);
		}
		else
		{
			(void)QTSS_Write(inStream, dataPtr, ::strlen(dataPtr), NULL, 0);
		}
		//printf(" %s",buffer);
	
	}
	
	if (parameters)
	{	(void)QTSS_Write(inStream, sParameterDelimeter, 1, NULL, 0);
		//printf(" %s",sParameterDelimeter);
	}
	
	if (parameters & QueryURI::kAccessParam)
	{	
		(void)QTSS_Write(inStream, sAccess, 2, NULL, 0);
		//printf(" %s",sAccess);
		(void)QTSS_Write(inStream, GetMyAccessData(),  GetMyAccessLen(), NULL, 0);
		//printf("%s",GetMyAccessData());
		parameters &= ~QueryURI::kAccessParam; // clear access flag
		
		if (parameters)
		{	(void)QTSS_Write(inStream, sListDelimeter, 1, NULL, 0);
			//printf("%s",sListDelimeter);
		}
	}
	
	if (parameters & QueryURI::kTypeParam)
	{	
		(void)QTSS_Write(inStream, sType, 2, NULL, 0);
		//printf(" %s",sType);
		char *theTypeString = GetMyAPI_TypeStr();
		if (theTypeString == NULL)
		{
			(void)QTSS_Write(inStream, nullErr, ::strlen(nullErr), NULL, 0);
		}
		else
		{
			(void)QTSS_Write(inStream,theTypeString,strlen(theTypeString), NULL, 0);
			//printf("%s",theTypeString);
		}
		
		parameters &= ~QueryURI::kTypeParam; // clear type flag
		
		if (parameters)
		{	(void)QTSS_Write(inStream, sListDelimeter, 1, NULL, 0);
			//printf("%s",sListDelimeter);
		}
	}
	queryPtr->SetQueryHasResponse();
	(void)QTSS_Write(inStream, "\n", 1, NULL, 0);
	//printf("\n");
	
}

void 	ElementNode::RespondToAdd(QTSS_StreamRef inStream, SInt32 index,QueryURI *queryPtr)
{
	char messageBuffer[1024] = "";

	//printf("ElementNode::RespondToAdd NODE = %s index = %ld \n",GetNodeName(), (SInt32) index);
	if (GetNumFields() == 0) 
	{
		UInt32 result = 405;
		sprintf(messageBuffer,  "Attribute does not allow adding. Action not allowed");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		//printf("ElementNode::RespondToAdd error = %s \n",messageBuffer);
		return;
	}	
	
	if (GetFieldType(index) == eNode)
	{	RespondWithSelfAdd(inStream, queryPtr);
		return;
	}
		
	static char *nullErr = "(null)";
	Bool16 nullData = false;
	QTSS_Error err = QTSS_NoErr;
	StrPtrLen bufferSPL(messageBuffer);
	
	
	if (!fInitialized) 
	{	//printf("ElementNode::RespondToAdd not Initialized EXIT\n");
		return;
	}
	if (NULL == queryPtr) 
	{	//printf("ElementNode::RespondToAdd NULL == queryPtr EXIT\n");
		return;
	}
	
	if (NULL == inStream) 
	{	//printf("ElementNode::RespondToAdd NULL == inStream EXIT\n");
		return;
	}
	
	char *dataPtr = GetElementDataPtr(index);
	if (NULL == dataPtr) 
	{	//printf("ElementNode::RespondToAdd NULL == dataPtr EXIT\n");
		//	return;
		dataPtr = nullErr;
		nullData = true;
	}
	
	queryPtr->SetQueryHasResponse();	

	
	UInt32 accessFlags = 0;
	StrPtrLen *accessParamsPtr=queryPtr->GetAccess();
	if (accessParamsPtr != NULL)
		accessFlags = queryPtr->GetAccessFlags();
	else
		accessFlags = GetAccessPermissions(index);
	
	
	
	StrPtrLen* valuePtr = queryPtr->GetValue();
	OSCharArrayDeleter value(NewCharArrayCopy(valuePtr));
	if (!valuePtr || !valuePtr->Ptr)
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "No value found");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}	

	//printf("ElementNode::RespondToAdd theValue= %s theType=%s typeID=%lu \n",value.GetObject(), GetAPI_TypeStr(index), GetAPI_Type(index));
	char valueBuff[2048] = "";
	UInt32 len = 2048;
	err = QTSS_StringToValue(value.GetObject(),GetAPI_Type(index), valueBuff, &len);
	if (err) 
	{	UInt32 result = 400;
		sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_ConvertStringToType",err);
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}

	if (GetFieldType(index) != eNode)
	{	
		OSCharArrayDeleter typeDeleter(NewCharArrayCopy(queryPtr->GetType()));
		StrPtrLen theQueryType(typeDeleter.GetObject());

		if (typeDeleter.GetObject())
		{
			StrPtrLen attributeString(GetAPI_TypeStr(index));
			if (!attributeString.Equal(theQueryType))
			{	UInt32 result = 400;
				sprintf(messageBuffer,  "Type %s does not match attribute type %s",typeDeleter.GetObject(), attributeString.Ptr);
				(void) queryPtr->EvalQuery(&result, messageBuffer);
				return;
			}	
		}
		
		QTSS_Object source = GetSource();

		UInt32 tempBuff;
		UInt32 attributeLen = sizeof(tempBuff);
		(void) QTSS_GetValue (source, GetAPI_ID(index), 0, &tempBuff, &attributeLen);
		if (attributeLen != len)
		{	UInt32 result = 400;
			sprintf(messageBuffer,  "Data length %lu does not match attribute len %lu",len, attributeLen);
			(void) queryPtr->EvalQuery(&result, messageBuffer);
			return;
		}

		
		UInt32 numValues = 0;
		err = QTSS_GetNumValues (source,  GetAPI_ID(index), &numValues);
		if (err) 
		{	UInt32 result = 400;
			sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_GetNumValues",err);
			(void) queryPtr->EvalQuery(&result, messageBuffer);
			return;
		}
		
		//printf("ElementNode::RespondToAdd QTSS_SetValue object=%lu attrID=%lu, index = %lu valuePtr=%lu valuelen =%lu \n",GetSource(),GetAPI_ID(index), GetAttributeIndex(index), valueBuff,len);
		err = QTSS_SetValue (source, GetAPI_ID(index), numValues, valueBuff, len);
		if (err) 
		{	UInt32 result = 400;
			sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_SetValue",err);
			(void) queryPtr->EvalQuery(&result, messageBuffer);
			return;
		}

	}
	
}

void 	ElementNode::RespondToSet(QTSS_StreamRef inStream, SInt32 index,QueryURI *queryPtr)
{
	static char *nullErr = "(null)";
	Bool16 nullData = false;
	QTSS_Error err = QTSS_NoErr;
	char messageBuffer[1024] = "";
	StrPtrLen bufferSPL(messageBuffer);
	
	//printf("ElementNode::RespondToSet NODE = %s index = %ld \n",GetNodeName(), (SInt32) index);
	
	if (!fInitialized) 
	{	//printf("ElementNode::RespondToSet not Initialized EXIT\n");
		return;
	}
	if (NULL == queryPtr) 
	{	//printf("ElementNode::RespondToSet NULL == queryPtr EXIT\n");
		return;
	}
	
	if (NULL == inStream) 
	{	//printf("ElementNode::RespondToSet NULL == inStream EXIT\n");
		return;
	}
	
	char *dataPtr = GetElementDataPtr(index);
	if (NULL == dataPtr) 
	{	//printf("ElementNode::RespondToSet NULL == dataPtr EXIT\n");
		//	return;
		dataPtr = nullErr;
		nullData = true;
	}
	
	queryPtr->SetQueryHasResponse();	

	OSCharArrayDeleter typeDeleter(NewCharArrayCopy(queryPtr->GetType()));
	StrPtrLen theQueryType(typeDeleter.GetObject());

	if (theQueryType.Len > 0)
	{	StrPtrLen attributeString(GetAPI_TypeStr(index));
		if (!attributeString.Equal(theQueryType))
		{	UInt32 result = 400;
			sprintf(messageBuffer,  "Type %s does not match attribute type %s",typeDeleter.GetObject(), attributeString.Ptr);
			(void) queryPtr->EvalQuery(&result, messageBuffer);
			return;
		}	
	}

	if (0 == (GetAccessPermissions(index) & qtssAttrModeWrite)) 
	{
		UInt32 result = 400;
		sprintf(messageBuffer,  "Attribute is read only. Action not allowed");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}	

	if (GetFieldType(index) == eNode)
	{	
		UInt32 result = 400;
		sprintf(messageBuffer,  "Set of type %s not allowed",typeDeleter.GetObject());
		//printf("ElementNode::RespondToSet (GetFieldType(index) == eNode) %s\n",messageBuffer);
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		return;
	}
	else do 
	{	
		
		StrPtrLen* valuePtr = queryPtr->GetValue();
		if (!valuePtr || !valuePtr->Ptr) break;
	
		char valueBuff[2048] = "";
		UInt32 len = 2048;
		OSCharArrayDeleter value(NewCharArrayCopy(valuePtr));
		
		//printf("ElementNode::RespondToSet valuePtr->Ptr= %s\n",value.GetObject());
		
		err = QTSS_StringToValue(value.GetObject(),GetAPI_Type(index), valueBuff, &len);
		if (err) 
		{	sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_ConvertStringToType",err);
			break;
		}
		
		//printf("ElementNode::RespondToSet QTSS_SetValue object=%lu attrID=%lu, index = %lu valuePtr=%lu valuelen =%lu \n",GetSource(),GetAPI_ID(index), GetAttributeIndex(index), valueBuff,len);
		err = QTSS_SetValue (GetSource(), GetAPI_ID(index), GetAttributeIndex(index), valueBuff, len);
		if (err) 
		{	sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_SetValue",err);
			break;
		}	
			
	} while (false);
	
	if (err != QTSS_NoErr)
	{	UInt32 result = 400;
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		//printf("ElementNode::RespondToSet %s len = %lu ",messageBuffer, result);
		return;
	}
	
}

void 	ElementNode::RespondToDel(QTSS_StreamRef inStream, SInt32 index,QueryURI *queryPtr,Bool16 delAttribute)
{
	static char *nullErr = "(null)";
	Bool16 nullData = false;
	QTSS_Error err = QTSS_NoErr;
	char messageBuffer[1024] = "";
	StrPtrLen bufferSPL(messageBuffer);
	
	//printf("ElementNode::RespondToDel NODE = %s index = %ld \n",GetNodeName(), (SInt32) index);
	
	if (!fInitialized) 
	{	//printf("ElementNode::RespondToDel not Initialized EXIT\n");
		return;
	}
	if (NULL == queryPtr) 
	{	//printf("ElementNode::RespondToDel NULL == queryPtr EXIT\n");
		return;
	}
	
	if (NULL == inStream) 
	{	//printf("ElementNode::RespondToDel NULL == inStream EXIT\n");
		return;
	}

	//printf("ElementNode::RespondToAdd NODE = %s index = %ld \n",GetNodeName(), (SInt32) index);
	if (GetNumFields() == 0) 
	{
		UInt32 result = 405;
		sprintf(messageBuffer,  "Attribute does not allow deleting. Action not allowed");
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		//printf("ElementNode::RespondToAdd error = %s \n",messageBuffer);
		return;
	}	
	
	
	char *dataPtr = GetElementDataPtr(index);
	if (NULL == dataPtr) 
	{	//printf("ElementNode::RespondToDel NULL == dataPtr EXIT\n");
		//	return;
		dataPtr = nullErr;
		nullData = true;
	}
	
	queryPtr->SetQueryHasResponse();	

	// DMS - Removeable is no longer a permission bit
	//
	//if (GetMyFieldType() != eArrayNode && 0 == (GetAccessPermissions(index) & qtssAttrModeRemoveable)) 
	//{
	//	UInt32 result = 405;
	//	sprintf(messageBuffer,  "Attribute is not removable. Action not allowed");
	//	(void) queryPtr->EvalQuery(&result, messageBuffer);
	//	return;
	//}	
	
	if (GetMyFieldType() == eArrayNode && !delAttribute)
	{	
		UInt32 result = 500;
		err = QTSS_RemoveValue (GetSource(),GetAPI_ID(index), GetAttributeIndex(index));
		sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_RemoveValue", err);
		//printf("ElementNode::RespondToDel QTSS_RemoveValue object=%lu attrID=%lu index=%lu %s\n",GetSource(),GetAPI_ID(index),GetAttributeIndex(index),messageBuffer);
		if (err) 
		{	(void) queryPtr->EvalQuery(&result, messageBuffer);
		}	
	}
	else  
	{	
		//printf("ElementNode::RespondToDel QTSS_RemoveInstanceAttribute object=%lu attrID=%lu \n",GetSource(),GetAPI_ID(index));
		err = QTSS_RemoveInstanceAttribute(GetSource(),GetAPI_ID(index));		
		if (err) 
		{
			sprintf(messageBuffer,  "QTSS_Error=%ld from QTSS_RemoveInstanceAttribute",err);
		}	
			
	} 
	
	if (err != QTSS_NoErr)
	{	UInt32 result = 400;
		(void) queryPtr->EvalQuery(&result, messageBuffer);
		//printf("ElementNode::RespondToDel %s len = %lu ",messageBuffer, result);
		return;
	}
	
}

Bool16 ElementNode::IsFiltered(SInt32 index,QueryURI *queryPtr)
{
	Bool16 foundFilter = false;
	StrPtrLen*	theFilterPtr;
	for (SInt32 count = 0; count < queryPtr->fNumFilters; count ++)
	{
		theFilterPtr = queryPtr->GetFilter(count);
		if (theFilterPtr && theFilterPtr->Equal(StrPtrLen(GetName(index))) ) 
		{	foundFilter = true;
			break;
		}
	}
	return foundFilter;
}
	
void ElementNode::RespondToGet(QTSS_StreamRef inStream, SInt32 index,QueryURI *queryPtr)
{
	static char *nullErr = "(null)";
	Bool16 nullData = false;
	
	//printf("ElementNode::RespondToGet NODE = %s index = %ld \n",GetNodeName(), (SInt32) index);
	
	if (!fInitialized) 
	{	//printf("ElementNode::RespondToGet not Initialized EXIT\n");
		return;
	}
	if (NULL == queryPtr) 
	{	//printf("ElementNode::RespondToGet NULL == queryPtr EXIT\n");
		return;
	}
	
	if (NULL == inStream) 
	{	//printf("ElementNode::RespondToGet NULL == inStream EXIT\n");
		return;
	}
	
	char *dataPtr = GetElementDataPtr(index);
	if (NULL == dataPtr) 
	{	//printf("ElementNode::RespondToGet NULL == dataPtr EXIT\n");
		//	return;
		dataPtr = nullErr;
		nullData = true;
	}
	
	StrPtrLen bufferSPL;
	
	UInt32 parameters = queryPtr->GetParamBits();
	parameters &= ~QueryURI::kRecurseParam; // clear verbose flag
	parameters &= ~QueryURI::kDebugParam; // clear debug flag
	parameters &= ~QueryURI::kIndexParam; // clear index flag
	
	//printf("ElementNode::RespondToGet QTSS_SetValue object=%lu attrID=%lu, index = %lu \n",GetSource(),GetAPI_ID(index), GetAttributeIndex(index));


	if ((parameters & QueryURI::kVerboseParam) ) 
	{	
		parameters &= ~QueryURI::kVerboseParam; // clear verbose flag
		GetFullPath(&bufferSPL);
		(void)QTSS_Write(inStream, bufferSPL.Ptr, ::strlen(bufferSPL.Ptr), NULL, 0);
		//printf("ElementNode::RespondToGet Path=%s \n",bufferSPL.Ptr);
	}
	

	(void)QTSS_Write(inStream, GetName(index), GetNameLen(index), NULL, 0);
	//printf("ElementNode::RespondToGet %s:len = %lu",GetName(index),(UInt32) GetNameLen(index));
		
	if (IsNodeElement(index))
	{
		(void)QTSS_Write(inStream, "/\"", 1, NULL, 0);
		//printf(" %s/\"",GetNodeName());
	}
	else
	{
		if (nullData)
		{
			(void)QTSS_Write(inStream, "=", 1, NULL, 0);
			(void)QTSS_Write(inStream, dataPtr, ::strlen(dataPtr), NULL, 0);
		}
		else
		{
			(void)QTSS_Write(inStream, "=\"", 2, NULL, 0);
			(void)QTSS_Write(inStream, dataPtr, ::strlen(dataPtr), NULL, 0);
			(void)QTSS_Write(inStream, "\"", 1, NULL, 0);
		}
	}
	
	//printf(" %s len = %d ",buffer, ::strlen(buffer));
	//DebugShowFieldDataType(index);
	
	if (parameters)
	{	(void)QTSS_Write(inStream, sParameterDelimeter, 1, NULL, 0);
		//printf(" %s",sParameterDelimeter);
	}
	
	if (parameters & QueryURI::kAccessParam)
	{	
		(void)QTSS_Write(inStream, sAccess, 2, NULL, 0);
		//printf(" %s",sAccess);
		(void)QTSS_Write(inStream, GetAccessData(index),  GetAccessLen(index), NULL, 0);
		//printf("%s",GetAccessData(index));
		parameters &= ~QueryURI::kAccessParam; // clear access flag
		
		if (parameters)
		{	(void)QTSS_Write(inStream, sListDelimeter, 1, NULL, 0);
			//printf("%s",sListDelimeter);
		}
	}
	
	if (parameters & QueryURI::kTypeParam)
	{	
		(void)QTSS_Write(inStream, sType, 2, NULL, 0);
		//printf(" %s",sType);
		char* typeStringPtr = GetAPI_TypeStr(index);
		if (typeStringPtr == NULL)
		{
			//printf("ElementNode::RespondToGet typeStringPtr is NULL for type = %s \n", typeStringPtr);
			(void)QTSS_Write(inStream, nullErr, ::strlen(nullErr), NULL, 0);
		}
		else
		{
			//printf("ElementNode::RespondToGet type = %s \n", typeStringPtr);
			(void)QTSS_Write(inStream,typeStringPtr,strlen(typeStringPtr), NULL, 0);
		}

		parameters &= ~QueryURI::kTypeParam; // clear type flag
		
		if (parameters)
		{	(void)QTSS_Write(inStream, sListDelimeter, 1, NULL, 0);
			//printf("%s",sListDelimeter);
		}
	}
	
	
	(void)QTSS_Write(inStream, "\n", 1, NULL, 0);
	//printf(" %s","\n");
	
	queryPtr->SetQueryHasResponse();

}

void 	ElementNode::RespondToKey(QTSS_StreamRef inStream, SInt32 index,QueryURI *queryPtr)
{
	SInt32 command = queryPtr->GetCommandID();
	//printf("ElementNode::RespondToKey command = %ld node =%s index=%ld\n",command, GetNodeName(),index);
	
	switch (command)
	{
		case QueryURI::kGETCommand: RespondToGet(inStream,index,queryPtr);
		break;
		
		case QueryURI::kSETCommand:	RespondToSet(inStream,index,queryPtr);
		break;
		
		case QueryURI::kADDCommand:	RespondToAdd(inStream,index,queryPtr);
		break;
		
		case QueryURI::kDELCommand:	RespondToDel(inStream,index,queryPtr,false);
		break;
	}
		
}

void ElementNode::RespondWithNodeName(QTSS_StreamRef inStream, QueryURI */*queryPtr*/)
{
	
	//printf("ElementNode::RespondWithNodeName NODE = %s \n",GetNodeName());
	
	if (!fInitialized) 
	{	 //printf("ElementNode::RespondWithNodeName not Initialized EXIT\n");
		 return;
	}
		
	StrPtrLen fullPathSPL;
	GetFullPath(&fullPathSPL);
	
	(void)QTSS_Write(inStream, "Container=\"/", ::strlen("Container=\"/"), NULL, 0);
	
	(void)QTSS_Write(inStream, fPathSPL.Ptr, ::strlen(fPathSPL.Ptr), NULL, 0);
	//printf("ElementNode::RespondWithNodeName Path=%s \n",fPathSPL.Ptr);
	
	(void)QTSS_Write(inStream, "\"", 1, NULL, 0);
	//printf("\"");		
	
	(void)QTSS_Write(inStream, "\n", 1, NULL, 0);
	//printf("\n");
	
}
	
void ElementNode::RespondWithSingleElement(QTSS_StreamRef inStream, QueryURI *queryPtr, StrPtrLen *currentSegmentPtr) 
{
		
	//printf("ElementNode::RespondWithSingleElement Current Node = %s\n",GetNodeName() );
	
	if (!fInitialized) 
	{	
		//printf("ElementNode::RespondWithSingleElement failed Not Initialized %s\n",GetNodeName() );
		return;
	}

	if (GetNodeName() == NULL) 
	{	
		//printf("ElementNode::RespondWithSingleElement Node = %s is Uninitialized LEAVE\n",GetNodeName() );
		return;
	}

	Assert(queryPtr != NULL);
	Assert(currentSegmentPtr != NULL);
	Assert(currentSegmentPtr->Ptr != 0);
	Assert(currentSegmentPtr->Len != 0);
	
	SInt32 key = ResolveSPLKeyToIndex(currentSegmentPtr);
	//printf("ElementNode::RespondWithSingleElement key = %ld\n",key);
	//printf("currentSegmentPtr="); PRINT_STR(currentSegmentPtr);
	
	if (key < 0) 
	{
		//printf("ElementNode::RespondWithSingleElement key = %ld NOT FOUND no ELEMENT\n",key);
		return;
	}
	
	if ((queryPtr == NULL) || (currentSegmentPtr == NULL) || (currentSegmentPtr->Ptr == NULL) || (currentSegmentPtr->Len == 0))
	{
		//printf("ElementNode::RespondWithSingleElement currentSegmentPtr || queryPtr = NULL\n");
		return;
	}
	
	//add here
	
	StrPtrLen nextSegment;
	( void)queryPtr->NextSegment(currentSegmentPtr, &nextSegment);

	if ( (nextSegment.Len == 0)  && !queryPtr->RecurseParam() )	// only respond if we are at the end of the path
	{
		//printf("currentSegmentPtr="); PRINT_STR(currentSegmentPtr);
		//printf("nextSegment="); PRINT_STR(&nextSegment);
		//printf("ElementNode::RespondWithSingleElement Current Node = %s Call RespondWithNodeName\n",GetNodeName() );
		if (QueryURI::kGETCommand == queryPtr->GetCommandID())
			RespondWithNodeName( inStream,queryPtr);
	}
			
	if (IsNodeElement(key))
	{
		ElementNode *theNodePtr = (ElementNode *)GetElementDataPtr(key);
		if (theNodePtr) 
		{	
			//printf("ElementNode::RespondWithSingleElement Current Node = %s Call RespondToQuery\n",GetNodeName() );
			theNodePtr->RespondToQuery(inStream, queryPtr,currentSegmentPtr);
		}
	}
	else
	{
		//printf("ElementNode::RespondWithSingleElement call RespondToKey\n");
		if ( (queryPtr->fNumFilters > 0) && (QueryURI::kGETCommand == queryPtr->GetCommandID()) )
		{
			StrPtrLen*	theFilterPtr;
			SInt32 index;
			for (SInt32 count = 0; count < queryPtr->fNumFilters; count ++)
			{
				theFilterPtr = queryPtr->GetFilter(count);
				index = ResolveSPLKeyToIndex(theFilterPtr);
				if (index < 0) continue;
				RespondToKey(inStream, index, queryPtr);
				//printf("ElementNode::RespondWithSingleElement found filter = ");PRINT_STR(theFilterPtr);
				break;
			}
			//printf("ElementNode::RespondWithSingleElement found filter = ?");PRINT_STR(theFilterPtr);
		}
		else
		{	RespondToKey(inStream, key, queryPtr);
		}
	}
	
}


void ElementNode::RespondWithAllElements(QTSS_StreamRef inStream, QueryURI *queryPtr, StrPtrLen *currentSegmentPtr)
{
	//printf("ElementNode::RespondWithAllElements %s\n",GetNodeName());
	//printf("ElementNode::RespondWithAllElements fDataFieldsStop = %d \n",fDataFieldsStop);
	
	if (GetNodeName() == NULL) 
	{	//printf("ElementNode::RespondWithAllElements %s is Uninitialized LEAVE\n",GetNodeName());
		return;
	}

	if (!fInitialized) 
	{	//printf("ElementNode::RespondWithAllElements %s is Uninitialized LEAVE\n",GetNodeName());
		return;
	}
	
	StrPtrLen nextSegment;
	( void)queryPtr->NextSegment(currentSegmentPtr, &nextSegment);

	if ( (nextSegment.Len == 0 || nextSegment.Ptr == 0)  )	// only respond if we are at the end of the path
		if (QueryURI::kGETCommand == queryPtr->GetCommandID())
			RespondWithNodeName( inStream,queryPtr);
		
	if ( (queryPtr->fNumFilters > 0) && (QueryURI::kGETCommand == queryPtr->GetCommandID()) )
	{
		StrPtrLen*	theFilterPtr;
		SInt32 index;
		for (SInt32 count = 0; count < queryPtr->fNumFilters; count ++)
		{
			theFilterPtr = queryPtr->GetFilter(count);
			index = ResolveSPLKeyToIndex(theFilterPtr);
			if (index < 0) continue;
						
			if ( (nextSegment.Len == 0 || nextSegment.Ptr == 0) )
			{	if ( (!IsNodeElement(index)) || (IsNodeElement(index) && queryPtr->RecurseParam() )) 	// only respond if we are at the end of the path 
					RespondToKey(inStream, index, queryPtr);	
			}

			//printf("ElementNode::RespondWithAllElements found filter = ");PRINT_STR(theFilterPtr);
		}
	}
	else
	{
		UInt32 index = 0;
		for ( index = 0; !IsStopItem(index) ;index++)
		{
			//printf("RespondWithAllElements = %d \n",index);
			//printf("ElementNode::RespondWithAllElements nextSegment="); PRINT_STR(&nextSegment);
			
			if ( (nextSegment.Len == 0 || nextSegment.Ptr == 0) )
			{	if ( (!IsNodeElement(index)) || (IsNodeElement(index) && queryPtr->RecurseParam() ) )	// only respond if we are at the end of the path
					RespondToKey(inStream, index, queryPtr);	
			}
	
		}
	}	
	
	UInt32 index = 0;
	for ( index = 0; !IsStopItem(index);index++)
	{
		
		if 	(IsNodeElement(index)) 
		{	
			//printf("ElementNode::RespondWithAllElements FoundNode\n");
			//printf("ElementNode::RespondWithAllElements currentSegmentPtr="); PRINT_STR(currentSegmentPtr);
			//printf("ElementNode::RespondWithAllElements nextSegment="); PRINT_STR(&nextSegment);
			ElementNode *theNodePtr = (ElementNode *)GetElementDataPtr(index);
			
			if (theNodePtr ) 
			{	
				//printf("ElementNode::RespondWithAllElements Current Node = %s Call RespondToQuery\n",GetNodeName() );
				theNodePtr->RespondToQuery(inStream, queryPtr,&nextSegment);
			}
			else
			{
				//printf("ElementNode::RespondWithAllElements Current Node index= %lu NULL = %s\n",index,GetName(index));
			
			}			
		}
	}
}



void ElementNode::RespondWithAllNodes(QTSS_StreamRef inStream, QueryURI *queryPtr, StrPtrLen *currentSegmentPtr) 
{
	
	//printf("ElementNode::RespondWithAllNodes %s\n",GetNodeName());

	if (!fInitialized) 
	{	//printf("ElementNode::RespondWithAllNodes %s is Uninitialized LEAVE\n",GetNodeName());
		return;
	}
	
	if (GetNodeName() == NULL) 
	{	//printf("ElementNode::RespondWithAllNodes %s is Uninitialized LEAVE\n",GetNodeName());
		return;
	}
	
	StrPtrLen nextSegment;
	( void)queryPtr->NextSegment(currentSegmentPtr, &nextSegment);	
	
	for(SInt32 index = 0; !IsStopItem(index); index ++)
	{
		if (!queryPtr->RecurseParam() && (currentSegmentPtr->Len == 0) ) 
		{	Assert(0);
			break;
		}
		

		if 	(IsNodeElement(index)) 
		{	
			//printf("ElementNode::RespondWithAllNodes FoundNode\n");
			//printf("ElementNode::RespondWithAllNodes currentSegmentPtr="); PRINT_STR(currentSegmentPtr);
			ElementNode *theNodePtr = (ElementNode *)GetElementDataPtr(index);
			//printf("ElementNode::RespondWithAllNodes nextSegment="); PRINT_STR(&nextSegment);
			if (theNodePtr) 
			{	
				//printf("ElementNode::RespondWithAllNodes Current Node = %s Call RespondToQuery\n",GetNodeName() );
				theNodePtr->RespondToQuery(inStream, queryPtr,currentSegmentPtr);			
			}
		}
	}
}

void ElementNode::RespondToQuery(QTSS_StreamRef inStream, QueryURI *queryPtr,StrPtrLen *currentPathPtr)
{
	//printf("----- ElementNode::RespondToQuery ------\n");
	//printf("ElementNode::RespondToQuery NODE = %s\n",GetNodeName());

	Assert(NULL != queryPtr);
	Assert(NULL != currentPathPtr);

	if (!fInitialized) 
	{	//printf("ElementNode::RespondToQuery %s is Uninitialized LEAVE\n",GetNodeName());
		return;
	
	}
		
	if (GetNodeName() == NULL) 
	{	//printf("ElementNode::RespondToQuery %s is Uninitialized LEAVE\n",GetNodeName());
		return;
	}
		
	
	Bool16 recurse = queryPtr->RecurseParam() ;
	Bool16 doAllNext = false;
	Bool16 doAllNextNext = false;
	StrPtrLen nextSegment;
	StrPtrLen nextnextSegment;
	StrPtrLen nextnextnextSegment;
	
	
	if (queryPtr && currentPathPtr) do
	{	
		( void)queryPtr->NextSegment(currentPathPtr, &nextSegment);
		( void)queryPtr->NextSegment(&nextSegment, &nextnextSegment);
		( void)queryPtr->NextSegment(&nextnextSegment, &nextnextnextSegment);
			
		//printf("ElementNode::RespondToQuery currentPathPtr="); PRINT_STR( currentPathPtr);
		//printf("ElementNode::RespondToQuery nextSegment="); PRINT_STR( &nextSegment);
		//printf("ElementNode::RespondToQuery nextnextSegment="); PRINT_STR( &nextnextSegment);

		 // recurse param is set and this is the end of the path
		if  (recurse && ( (0 == currentPathPtr->Len) || (0 == nextSegment.Len) ) )
		{	// admin 
			//printf("ElementNode::RespondToQuery 1)RespondToQuery -> RespondWithAllElements ") ;PRINT_STR( GetNodeNameSPL());
			RespondWithAllElements(inStream, queryPtr, &nextSegment); 
			break;							
		}

		 // recurse param is not set and this is the end of the path
		if  ( (!recurse && ( (0 == currentPathPtr->Len) || (0 == nextSegment.Len) ) )
			)
		{	// admin 
			//printf("ElementNode::RespondToQuery 2)RespondToQuery -> RespondWithSelf ") ;PRINT_STR( GetNodeNameSPL());
			if (fIsTop)
				(void)QTSS_Write(inStream, "Container=\"/\"\n", ::strlen("Container=\"/\"\n"), NULL, 0);

			RespondWithSelf(inStream, queryPtr);
			break;							
		}


		doAllNext = ElementNode_DoAll(&nextSegment);	
		doAllNextNext = ElementNode_DoAll(&nextnextSegment);	
		
		if  (	doAllNext && (0 == nextnextSegment.Len) )
		{	// admin/*
			//printf("ElementNode::RespondToQuery 3)RespondToQuery -> RespondWithAllElements ");PRINT_STR( &nextSegment);
			RespondWithAllElements(inStream, queryPtr, &nextSegment); 		
			break;							
		}
		
		if  (	doAllNext && doAllNextNext) 
		{	// admin/*/*
			//printf("ElementNode::RespondToQuery 4)RespondToQuery -> RespondWithAllNodes ");PRINT_STR( currentPathPtr);
			RespondWithAllNodes(inStream, queryPtr, &nextSegment); 
			break;							
		}
				

		if  (	doAllNext && (nextnextSegment.Len > 0) )
		{	// admin/*/attribute
			//printf("ElementNode::RespondToQuery 5)RespondToQuery -> RespondWithAllNodes  ");PRINT_STR( &nextSegment);
			RespondWithAllNodes(inStream, queryPtr, &nextSegment); 
			break;							
		}
		
		// admin/attribute
		//printf("ElementNode::RespondToQuery 6)RespondToQuery -> RespondWithSingleElement ");PRINT_STR( &nextSegment);
		RespondWithSingleElement(inStream, queryPtr,&nextSegment);

	} while (false);

	if (QueryURI::kGETCommand != queryPtr->GetCommandID() && (!queryPtr->fIsPref))
	{	queryPtr->fIsPref = IsPreferenceContainer(GetMyName(),NULL);
	}
	//printf("ElementNode::RespondToQuery LEAVE\n");
}


void ElementNode::SetupNodes(QueryURI *queryPtr,StrPtrLen *currentPathPtr,QTSS_Initialize_Params *initParams)
{
	//printf("----- ElementNode::SetupNodes ------ NODE = %s\n", GetNodeName()); 
	//printf("ElementNode::SetupNodes currentPathPtr ="); PRINT_STR(currentPathPtr);
	if (fSelfPtr == NULL) 
	{	//printf("******* ElementNode::SetupNodes (fSelfPtr == NULLL) \n");
	}
	Assert(NULL != queryPtr);
	Assert(NULL != currentPathPtr);
	
	if (queryPtr && currentPathPtr) do
	{	
		Bool16 doAll = false;
		StrPtrLen nextSegment;

		( void)queryPtr->NextSegment(currentPathPtr, &nextSegment);
		doAll = ElementNode_DoAll(&nextSegment);
		
		StrPtrLen *thisNamePtr = GetNodeNameSPL();
		//printf("ElementNode::SetupNodes thisNamePtr="); PRINT_STR(thisNamePtr);

		if (	( (doAll) && (currentPathPtr->Equal(*thisNamePtr) || ElementNode_DoAll(currentPathPtr)) )
			 || (queryPtr->RecurseParam())
			)
		{
			SetUpAllElements(queryPtr,currentPathPtr, &nextSegment, initParams);
			break;
		}
				 
		SInt32 index = ResolveSPLKeyToIndex(&nextSegment);
		if (index < 0) 
		{	
			//printf("ElementNode::SetupNodes FAILURE ResolveSPLKeyToIndex = %d NODE = %s\n", index, GetNodeName());
			break;
		}

		SetUpAllNodes(queryPtr, currentPathPtr, &nextSegment, initParams); 
	
		if (NULL == GetElementDataPtr(index))
		{ 	//printf("ElementNode::SetupNodes call SetUpSingleElement index=%lu nextSegment=");PRINT_STR( &nextSegment);
			SetUpSingleElement(queryPtr,currentPathPtr, &nextSegment, index, initParams);
		}
		
		
	} while (false);

}

void ElementNode::GetFilteredAttributeName(ElementDataFields* fieldPtr, QTSS_AttributeID theID)
{	
	fieldPtr->fFieldLen = 0;
	char *theName = NULL;
	(void) QTSS_GetValueAsString (fieldPtr->fAPISource, theID,0, &theName);
	OSCharArrayDeleter nameDeleter(theName); 
	if (theName != NULL )
	{	UInt32 len = strlen(theName);
		if (len < eMaxAttributeNameSize)
		{	memcpy(fieldPtr->fFieldName, theName, len); 
			fieldPtr->fFieldName[len] = 0;
			fieldPtr->fFieldLen = len;
		}
	}
}

Bool16 ElementNode::GetFilteredAttributeID(char *parentName, char *nodeName, QTSS_AttributeID* foundID)
{
	Bool16 found = false;
	
	if (0 == strcmp("server", parentName))
	{
		if (0 == strcmp("qtssSvrClientSessions", nodeName) )
		{	if (foundID)
				*foundID = qtssCliSesCounterID;
			found = true;
		}
		
		if (0 == strcmp("qtssSvrModuleObjects", nodeName))
		{	if (foundID) 
				*foundID = qtssModName;
			found = true;
		}
	}			
	return found;
};

Bool16 ElementNode::IsPreferenceContainer(char *nodeName, QTSS_AttributeID* foundID)
{
	 Bool16 found = false;
	if (foundID) *foundID = 0;
	//printf(" ElementNode::IsPreferenceContainer name = %s \n",nodeName);
	if (0 == strcmp("qtssSvrPreferences", nodeName) )
	{	if (foundID) *foundID = qtssCliSesCounterID;
		found = true;
	}
	
	if (0 == strcmp("qtssModPrefs", nodeName))
	{	if (foundID) *foundID = qtssModName;
		found = true;
	}
		
	return found;
};

ElementNode::ElementDataFields AdminClass::sAdminSelf[] = // special case of top of tree
{   // key, API_ID,		fIndex, 	Name, 		Name_Len, 		fAccessPermissions,	Access, access_Len, fAPI_Type, fFieldType ,fAPISource
	{0,		0, 			0, 			"admin",	strlen("admin"),	qtssAttrModeRead, "r", strlen("r"),0,	ElementNode::eNode, NULL	}
};

ElementNode::ElementDataFields AdminClass::sAdminFieldIDs[] = 
{   // key, API_ID,		fIndex, 	Name, 		Name_Len, 		fAccessPermissions,	Access, access_Len, fAPI_Type, fFieldType ,fAPISource
	{0,		0, 			0, 			"server",	strlen("server"),qtssAttrModeRead,	"r", strlen("r"),qtssAttrDataTypeQTSS_Object,	ElementNode::eNode, NULL	}
};



void AdminClass::Initialize(QTSS_Initialize_Params *initParams, QueryURI *queryPtr) 
{	

	//printf("----- Initialize AdminClass ------\n");
	
	SetParentNode(NULL);
	SetNodeInfo(&sAdminSelf[0]);// special case of this node as top of tree so it sets self
	Assert(NULL != GetMyName());
	SetNodeName(GetMyName());
	SetSource(NULL);
	StrPtrLen *currentPathPtr = queryPtr->GetRootID();
	UInt32 numFields = 1;
	SetNumFields(numFields);
	fFieldIDs = sAdminFieldIDs;
	fDataFieldsType = eStatic;
 	fPathBuffer[0]=0;
	fPathSPL.Set(fPathBuffer,0);
	fIsTop = true;
	fInitialized = true;
	do
	{	
		Assert(fElementMap == NULL);
		fElementMap = NEW OSRefTable();  ElementNode_InsertPtr(fElementMap,"AdminClass::Initialize ElementNode* fElementMap ");
		Assert(fElementMap != NULL);
		if (fElementMap == NULL) break;
		
		Assert(fFieldDataPtrs == NULL);
		fFieldDataPtrs = NEW char*[numFields];  ElementNode_InsertPtr(fFieldDataPtrs,"AdminClass::Initialize ElementNode* fFieldDataPtrs array ");
		Assert(fFieldDataPtrs != NULL);
		if (fFieldDataPtrs == NULL) break;
		memset(fFieldDataPtrs, 0, numFields * sizeof(char*));
			
		Assert(fFieldOSRefPtrs == NULL);
		fFieldOSRefPtrs = NEW OSRef *[numFields]; ElementNode_InsertPtr(fFieldOSRefPtrs,"AdminClass::Initialize ElementNode* fFieldOSRefPtrs array ");
		Assert(fFieldOSRefPtrs != NULL);
		if (fFieldOSRefPtrs == NULL) break;
		memset(fFieldOSRefPtrs, 0, numFields * sizeof(OSRef*));
		
		QTSS_Error err = fElementMap->Register(GetOSRef(0));		
		Assert(err == QTSS_NoErr);
	} while (false);
	
	if (queryPtr && currentPathPtr) do
	{	
		StrPtrLen nextSegment;
		if (!queryPtr->NextSegment(currentPathPtr, &nextSegment)) break;

		SetupNodes(queryPtr,currentPathPtr,initParams);
	} while(false);


};

void AdminClass::SetUpSingleNode(QueryURI *queryPtr,  StrPtrLen *currentSegmentPtr, StrPtrLen *nextSegmentPtr, SInt32 index, QTSS_Initialize_Params *initParams) 
{
	//printf("-------- AdminClass::SetUpSingleNode ---------- \n");
	switch (index)
	{
		case eServer:
			//printf("AdminClass::SetUpSingleNode case eServer\n");
			fNodePtr =  NEW ElementNode();  ElementNode_InsertPtr(fNodePtr, "AdminClass::SetUpSingleNode ElementNode * NEW ElementNode()");
			SetElementDataPtr(index,(char *) fNodePtr, true); 
			if (fNodePtr)
			{	fNodePtr->Initialize(index, this, queryPtr,nextSegmentPtr,initParams, initParams->inServer, eDynamic);
			}
		break;
	};
	
}
void AdminClass::SetUpSingleElement(QueryURI *queryPtr, StrPtrLen *currentSegmentPtr,StrPtrLen *nextSegmentPtr, SInt32 index, QTSS_Initialize_Params *initParams) 
{
	//printf("---------AdminClass::SetUpSingleElement------- \n");
	SetUpSingleNode(queryPtr,currentSegmentPtr, nextSegmentPtr, index, initParams);
}

AdminClass::~AdminClass() 
{	//printf("AdminClass::~AdminClass() \n");
	delete (ElementNode*) fNodePtr;ElementNode_RemovePtr(fNodePtr,"AdminClass::~AdminClass ElementNode* fNodePtr");
	fNodePtr = NULL;
}

