/**
 ** PSCPriv
 ** Implements a private postscript instruction
 ** cache.  The instructions are kept in the
 ** string "cache".  Memory for the cache is
 ** malloced to a "best length" 
 **/


#import "PSCPriv.h"
#import "Nutation.h"
#import <strings.h>
#import <stdlib.h>
#import <dpsclient/psops.h>
#import <stdarg.h>

extern id Nu ;
extern char bigBuf[] ; // a "big" buffer for general use
#define aString bigBuf

// Superclass file goes on next line:
#pragma .h #import "Glyph.h"

// here are the "good" malloc lengths. 
int goodLengths[] = {32, 128, 252, 508, 1020, 2044, 4088} ;
// these are the "goodLengths" accoring to malloc's man page
/* int goodLengths[] = {16, 32, 64, 128, 176,
     252, 340, 508, 680, 1020, 1360, 2044, 2724, 4088} ; */


int bestLength(int len)
{ // return the "best" malloc size, given length
  // of a string (len should include space for
  // the null terminator).
  int theLen, i ;
  if(len <= 4088)
  { i = 0 ;
    while(goodLengths[i] < len)
	i++ ;
    return goodLengths[i] ;
  }
  else
  { i = 1 ;
    while((theLen = (i * 8192)) < len)
      i++ ;
    return theLen ;
  }
}


@implementation PSCPriv:Glyph
{  char *cache ;
   unsigned capacity ;
}

- cache: (char *) format, ... ;
{ // Create a string by formating as in
  // printf with "format" the format string.
  // Concatenate this string to the existing cache,
  // allocating memory as necessary. 
  int neededLength, cacheLen, len, maxLen ;
  va_list argList ;
  NXStream *aStream = NULL ;
  va_start(argList, format) ;
  vsprintf(aString, format, argList) ;
  va_end(argList) ; 
  len = strlen(aString) ; 
  // put it into the cache
  if(!cache)
  { // no cache...create one
    cacheLen = 0 ;
    neededLength = len + 1 ;
    capacity = bestLength(neededLength) ;
    cache = (char *) malloc(capacity) ;
  }
  else
  { // have a cache already...concatenate, growing if necessary
    cacheLen = strlen(cache) ;
    neededLength =  cacheLen + len + 1 ;
    if(neededLength > capacity) // then grow...
    { char *newString ;
      capacity = bestLength(neededLength) ;
      newString = (char *) malloc(capacity) ;
      bcopy(cache, newString, cacheLen) ;
      free(cache) ;
      cache = newString ;
    }
  }
  bcopy(aString, &cache[cacheLen], len) ;
  cache[cacheLen + len] = '\0' ;
//  NXCloseMemory(aStream,NX_TRUNCATEBUFFER) ;
  return self ;
}   

- copy ;
{ id aCopy = [super copy] ;
  aCopy->cache = malloc(capacity) ;
  strcpy(aCopy->cache,cache) ;
  return aCopy ;
}
  
- didResize: sender ;
{ // I have been resized.  recalculate
  // my cache
  [self emptyCache] ;
  return [self makeCache] ;
}

- drawSelf: (NXPoint *) scale ;
{ if(cache)
    [Nu ps: cache] ;
  return self ;
}

- emptyCache ;
{ // free the existing cache
  if(cache)
  { free(cache) ;
  }
  cache = nil ;
  return self ;
}

- free ;
{ [self emptyCache] ;
  return [super free] ;
}

- init: (float) width :(float) height ;
{ [super init:width :height] ;
  cache = nil ;
  return [self makeCache] ;
}

- makeCache ;
{ return self ;
}

-read: (NXTypedStream *) stream ;
{ [super read: stream] ;
  NXReadType(stream, "*", &cache) ;
  capacity = strlen(cache) ;
  return self ;
}

-write: (NXTypedStream *) stream ;
{ // we only archive the "used" portion of
  // the cache
  [super write: stream] ;
  NXWriteType(stream, "*", &cache)  ;
  return self ;
}
@end

