#import "Eval.h"


@implementation Eval(PostScript)

+ ps: (char *) format, ... ;
{ // Format (as in printf) and send to windowserver.
  // Done in a separate context to provide good
  // error handling and recovery.  The idea is stolen
  // from Yap.
  NXStream *dataStream, *errorStream ;
  char *dataBuffer ;
  va_list argList ;
  int len, maxLen ;
  NXHandler exception;
  static DPSContext EvalContext = NULL; // The second context
  id graphicsView = [NXApp transcriptGraphics]  ;
  DPSContext curContext = DPSGetCurrentContext();

  [[graphicsView image] lockFocus] ;
  if(!EvalContext) // create the second context
  { const char *app = [NXApp appName];
    EvalContext = DPSCreateContext(NXGetDefaultValue(app, "NXHost"),
        NXGetDefaultValue(app, "NXPSName"), NULL, NULL);
    DPSSetContext(curContext);
  }
  dataStream = NXOpenMemory(NULL, 0, NX_READWRITE) ;
  va_start(argList, format) ;
  NXVPrintf(dataStream, format, argList) ;
  NXPutc(dataStream,'\n') ;
  NXGetMemoryBuffer(dataStream, &dataBuffer, &len, &maxLen);
  SwitchContextsWithFocus(EvalContext);
  exception.code = 0 ;
  NX_DURING
    DPSWriteData(EvalContext,dataBuffer,len) ;
    NXPing() ;
  NX_HANDLER
    if(NXLocalHandler.code != dps_err_ps)
      NX_RERAISE() ;  
    else  // handle postscript errors locally 
      exception = NXLocalHandler ;
  NX_ENDHANDLER
  DPSSetContext(curContext);
  NXCloseMemory(dataStream,NX_FREEBUFFER) ;
  [[graphicsView image] unlockFocus] ;
  if(exception.code)
  { errorStream = NXOpenMemory(NULL,0,NX_WRITEONLY);
    DPSPrintErrorToStream(errorStream,
       (DPSBinObjSeq) exception.data2);
    NXPrintf(errorStream,"\n%c",0) ;
    NXFlush(errorStream);
    NXGetMemoryBuffer(errorStream, &dataBuffer, &len, &maxLen);
    [Eval printf: "%s\n", dataBuffer] ;
    NXCloseMemory(errorStream, NX_FREEBUFFER);
    DPSDestroyContext(EvalContext);
    EvalContext = NULL;
    NXRunAlertPanel("Eval","Postcript errors in message\n"
     "to [ps...] : see transcript",NULL,NULL,NULL) ;
  }
  else
  { [graphicsView display] ;
    [[graphicsView window] orderFront: self] ;
  }
  return self;
}


+ startPS ;
{ // lock focus on graphics image
  [[[NXApp transcriptGraphics] image] lockFocus] ;
  return self ;
}

+ stopPS ;
{ // unlock focus on graphics image ; display the graphics
  id graphicsView = [NXApp transcriptGraphics] ;
  [[graphicsView image] unlockFocus] ;
  [graphicsView display] ;
  [[graphicsView window] orderFront: self] ;
  return self ;
}

- evalPs: (id) pboard userData: (const char *) uBuf error: (char **) msg ;
{ // evaluate postscript from pasteboard
  // fetch the data from pasteboard
  const char *const *types ;
  char *text, *buf ;
  int textLen, i ;
  BOOL found = NO ;
  types = [pboard types] ;
  for(i = 0 ; types[i]; i++)
  { if(!strcmp(types[i], NXAsciiPboardType))
    { found = YES ;
      break ;
    }
  }
  if(!found) // no ascii found...
    return self ;
  [pboard readType:NXAsciiPboardType data:&text length:&textLen];
  if(!text || !textLen)
    return self ;
  // change text into a null-terminated string 
  buf = alloca(textLen + 1) ;
  strncpy(buf,text,textLen) ;
  buf[textLen] = '\0' ;
  [self message: "Evaluating Postscript..."] ;
  [Eval ps: buf] ;
  [self message: ""] ;
  [pboard  deallocatePasteboardData:text length:textLen];
  return self ;
}

- evalPsHelpPanel: sender ;
{ // evaluate  selection in help panel
  NXSelPt start, end ;
  int textLen ;
  char *textBuf ;
  if(!helpText)
    [self helpText: sender] ;
  [helpText getSel:&start :&end] ;
  textLen = end.cp - start.cp ;
  textBuf = malloc(textLen + 1) ;
  if(textBuf)
  { [helpText getSubstring:textBuf start:start.cp length:textLen] ;
    textBuf[textLen] = '\0' ;
    [Eval ps: textBuf] ;
  }
  return self ;
}

@end
