#import <objc/objc.h>
#import <libc.h>
#import <dpsclient/dpsclient.h>

static char *responseBuffer = NULL;    /* Pointer to character buffer */
static int   responseBufCount = 0;	/* Number of bytes in buffer, currently */
static int   responseBufSize = 0;	/* Total size of buffer */
#define MINRESPBUFSIZE 100

/* Implementation of myTextProc.  All that myTextProc does
   is accumulate all the text that comes in on the context while
   it's active into responseBuffer, resizing it when
   necessary.   */

static void myTextProc(DPSContext context, char *buf, unsigned long count)
{
    /* Expand the buffer if necessary */

    while(((int)count + responseBufCount + 1) > responseBufSize)
    {	/* Must expand buffer */
	if (responseBuffer == NULL)
	{
	    responseBuffer=NXZoneMalloc(NXDefaultMallocZone(),MINRESPBUFSIZE);
	    responseBufSize = MINRESPBUFSIZE;
	}
	else
	{
	    responseBuffer = NXZoneRealloc(NXDefaultMallocZone(), 
					   responseBuffer,responseBufSize*2);
	    responseBufSize *= 2;
	}
    }

    /* Put the new data in the buffer and update the count */

    bcopy(buf,responseBuffer+responseBufCount,count);
    responseBufCount += count;

    /* And null-terminate the buffer (this is used by the main procedure) */

    *(responseBuffer+responseBufCount) = 0;
}

/* Note that because the output of the dumpwindow/dumpwindows operators are not defined, this routine might fail under a future release of NeXTSTEP. It's OK to use this code in little test apps like this, but please don't rely on these operators for commercial applications.
*/
BOOL getWindowBytes (int windowNum, int *bytes, int *type)
{
    DPSTextProc oldTextProc;

    /* Reset the character buffer variables */
    responseBufCount = 0;

    DPSWaitContext(DPSGetCurrentContext());

    /* Now install our text proc.  We're about to call the
	dumpwindows operator, which will write out a whole bunch of
	stuff on the output stream back to us.  We need to install
	our text proc before we do that, so that when the output
	comes out we will catch it.  Also, we remember the old text
	proc so we can put it back afterwards. */

    oldTextProc = DPSGetCurrentContext()->textProc;
    DPSSetTextProc(DPSGetCurrentContext(),myTextProc);

    /* Now call the dumpwindows operator, and our text proc
	catches all the responses and puts them in the
	reponseBuffer. */

    DPSPrintf(DPSGetCurrentContext()," 0 %d dumpwindow flush\n", windowNum);

    /* Call DPSWaitContext to be sure we)re really done, and all
	of the responses are really in the responseBuffer. */

    DPSWaitContext(DPSGetCurrentContext());

    /* OK, now we've got all the text in responseBuffer.  We can
	take our text proc back out. */

    DPSSetTextProc(DPSGetCurrentContext(),oldTextProc);

    /* The real work.  We get a line at a time out of
	reponseBuffer, and look at it to see if it looks like a
	line generated by the dumpwindows operator.  If so, we
	parse the memory usage number out of it; if not, we pass it
	to the old text proc for whatever normal processing
	occurs. */

    if (responseBuffer)
    {
	char *newBuf, *buf = responseBuffer;

	/* Find a line & Null-terminate it. We need the newline */
	newBuf = index(buf,'\n');
	if (newBuf) *newBuf = 0;
	/* Parse the line. dumpwindows returns lines that look like:
	    *
	    * Buffered: (0,448),(672,832) 129024+ bytes (131072)
	    *
	    * where the "+" is optional.
	    */
	if ((newBuf = index(buf, ':')) &&
	    (sscanf(newBuf+1," (%*d,%*d),(%*d,%*d) %d%*c%*s (%*d)",  bytes) == 1)) {
	    *newBuf = 0;		    
	    if (!strcmp(buf,"Nonretained")) *type = NX_NONRETAINED;
	    else if (!strcmp(buf,"Retained")) *type = NX_RETAINED;
	    else if (!strcmp(buf,"Buffered")) *type = NX_BUFFERED;
	    else *type = -1;
	} else {
	    (*oldTextProc)(DPSGetCurrentContext(),buf,strlen(buf));
	    return NO;
	}
    }
    return YES;
}

