/* PSAction Object -- copyright 1993, 1994 by C.D.Lane */

#import <appkit/appkit.h>
#import <dpsclient/dpsops.h>

#import "PSAction.h"
#import "PSActionWrap.h"

#define CONTEXT DPSGetCurrentContext()

@implementation PSAction

- init
{
	contents = NULL;

	target = view = script = view = errors = cache = nil;

	[[[self setEnabled:YES] setCacheCleared:YES] setErrorReported:YES];

	return self;
}

- free
{
	if (cache != nil) [cache free];

	if (contents != NULL) NX_FREE(contents);

	return [super free];
}

- (BOOL) isEnabled { return(!flags.disabled); }
- setEnabled:(BOOL) flag { flags.disabled = !flag; return self; }

- (BOOL) isCacheCleared { return(!flags.dontClearCache); }
- setCacheCleared:(BOOL) flag { flags.dontClearCache = !flag; return self; }

- (BOOL) isErrorReported { return(!flags.dontReportError); }
- setErrorReported:(BOOL) flag { flags.dontReportError = !flag; return self; }

- script { return script; }
- setScript:anObject { script = anObject; return self; }

- target { return target; }
- setTarget:anObject { target = anObject; return self; }

- errors { return errors; }
- setErrors:anObject { errors = anObject; return self; }

- view
{
	if (view == nil) {
		NXRect rect = {{0.0, 0.0}, {NX_TOKENWIDTH, NX_TOKENHEIGHT}};
		cache = [[Window alloc] initContent:&rect style:NX_PLAINSTYLE backing:NX_RETAINED buttonMask:0 defer:NO];
		[self setView:[cache contentView]];
		}

	return view;
}

- setView:anObject
{
	[(view = anObject) getBounds:&bounds];

	return self;
}

- (int) intValue { return atoi(contents); }
- takeIntValueFrom:sender { return[self setIntValue:[sender intValue]]; }

- setIntValue:(int) anInt
{
	if (![self isEnabled]) return self;

	[[self view] lockFocus]; {
		DPSsendint(CONTEXT, anInt);
		} [view unlockFocus];

	return [self executeScript];
}

- integertype
{
	int number;
	char buffer[BUFSIZ];

	[[self view] lockFocus]; {
		DPSgetint(CONTEXT, &number);
		} [view unlockFocus];

	(void) sprintf(buffer, "%d", number);

	if (contents != NULL) NX_FREE(contents);
	contents = NXCopyStringBuffer(buffer);

	if (target != nil && [target respondsTo:@selector(takeIntValueFrom:)]) [target takeIntValueFrom:self];

	return self;
}

- booleantype
{
	int number;
	char buffer[BUFSIZ];

	[[self view] lockFocus]; {
		DPSgetboolean(CONTEXT, &number);
		} [view unlockFocus];

	(void) sprintf(buffer, "%d", number);

	if (contents != NULL) NX_FREE(contents);
	contents = NXCopyStringBuffer(buffer);

	if (target != nil && [target respondsTo:@selector(takeIntValueFrom:)]) [target takeIntValueFrom:self];

	return self;
}

- (float) floatValue { return atof(contents); }
- takeFloatValueFrom:sender { return[self setFloatValue:[sender floatValue]]; }

- setFloatValue:(float) aFloat
{
	if (![self isEnabled]) return self;

	[[self view] lockFocus]; {
		DPSsendfloat(CONTEXT, aFloat);
		} [view unlockFocus];

	return [self executeScript];
}

- realtype
{
	float number;
	char buffer[BUFSIZ];

	[[self view] lockFocus]; {
		DPSgetfloat(CONTEXT, &number);
		} [view unlockFocus];

	(void) sprintf(buffer, "%f", number);

	if (contents != NULL) NX_FREE(contents);
	contents = NXCopyStringBuffer(buffer);

	if (target != nil && [target respondsTo:@selector(takeFloatValueFrom:)]) [target takeFloatValueFrom:self];

	return self;
}

- (double) doubleValue { return atof(contents); }
- takeDoubleValueFrom:sender { return[self setDoubleValue:[sender doubleValue]]; }

- setDoubleValue:(double) aDouble
{
	if (![self isEnabled]) return self;

	[[self view] lockFocus]; {
		DPSsendfloat(CONTEXT, aDouble);
		} [view unlockFocus];

	return [self executeScript];
}

- (const char *) stringValue { return contents; }
- takeStringValueFrom:sender { return[self setStringValue:[sender stringValue]]; }

- setStringValue:(const char *) aString
{
	if (![self isEnabled]) return self;

	[[self view] lockFocus]; {
		DPSsendstring(CONTEXT, aString);
		} [view unlockFocus];

	return [self executeScript];
}

- stringtype
{
	char buffer[BUFSIZ];

	[[self view] lockFocus]; {
		DPSgetstring(CONTEXT, buffer);
		} [view unlockFocus];

	if (contents != NULL) NX_FREE(contents);
	contents = NXCopyStringBuffer(buffer);

	if (target != nil && [target respondsTo:@selector(takeStringValueFrom:)]) [target takeStringValueFrom:self];

	return self;
}

- nametype
{
	char buffer[BUFSIZ];

	[[self view] lockFocus]; {
		DPSgetname(CONTEXT, buffer);
		} [view unlockFocus];

	if (contents != NULL) NX_FREE(contents);
	contents = NXCopyStringBuffer(buffer);

	if (target != nil && [target respondsTo:@selector(takeStringValueFrom:)]) [target takeStringValueFrom:self];

	return self;
}

- read:(NXTypedStream *) stream;
{
	[super read:stream];

	NXReadType(stream, "{i}", &flags);

	return self;
}

- write:(NXTypedStream *) stream
{
	[super write:stream];

	NXWriteType(stream, "{i}", &flags);

	return self;
}

- (NXImage *) getIBImage { return([NXImage findImageNamed:"PSActionPalette"]); }

- (const char *) getInspectorClassName { return "PSActionInspector"; }

- printf:(const char *) format, ...
{
	int length;
	va_list	ap;
	char buffer[BUFSIZ];

	if (![self isErrorReported]) return nil;

	va_start(ap, format); {
		if (errors == nil) (void) vfprintf(stderr, format, ap);
		else {
			(void) vsprintf(buffer, format, ap);
			length = [errors textLength];
			[[[[errors setSel:length :length] replaceSel:buffer] scrollSelToVisible] display];
			}
		} va_end(ap);

	return nil; /* return nil so it can be used as an error return */
}

- scriptError:(NXHandler *) error
{
	char *address;
	NXStream *stream;
	int length, maximum;

	if (error->code == dps_err_ps) {
		if ((stream = NXOpenMemory(NULL, 0, NX_WRITEONLY)) != NULL) {
			DPSPrintErrorToStream(stream, (DPSBinObjSeq) (error->data2));
			NXFlush(stream);
			NXGetMemoryBuffer(stream, &address, &length, &maximum);
			[self printf:address];
			NXCloseMemory(stream, NX_FREEBUFFER);
			}
		else [self printf:"Unable to open memory stream to process PostScript error code.\n"];
		}
	else [self printf:"Unknown PostScript error occured.\n"];

	return self;
}

- executeScript
{
	SEL action;
	NXHandler error;
	NXStream *stream;
	int length, maximum;
	char *address, buffer[BUFSIZ];
	float gray = [[[self view] window] backgroundGray];

	if ((stream = NXOpenMemory(NULL, 0, NX_WRITEONLY)) == NULL) return [self printf:"NXOpenMemory() error.\n"];

	if (script != nil) {
		if ([script isKindOf:[Control class]]) NXPrintf(stream, "%s\n", [script stringValue]);
		else if ([script isKindOf:[Text class]]) [script writeText:stream];
		}

	NXPrintf(stream, "\n");
	NXFlush(stream);

	NXGetMemoryBuffer(stream, &address, &length, &maximum);

	error.code = 0;

	saveState(CONTEXT); {
		[[self view] lockFocus]; {
			if ([self isCacheCleared]) eraseRect(CONTEXT, gray);
			NX_DURING {
				DPSWriteData(CONTEXT, address, length);
				getType(CONTEXT, buffer);
				} NX_HANDLER {
					error = NXLocalHandler;
					} NX_ENDHANDLER
			} [view unlockFocus];

		if (error.code != 0) [self scriptError:&error];
		else {
			action = sel_getUid(buffer);
			if ([self respondsTo:action]) [self perform:action];
			else [self printf:"Can't handle PostScript type \"%s\"!\n", buffer];
			}
		} restoreState(CONTEXT);

 	 NXCloseMemory(stream, NX_FREEBUFFER);

	return self;
}

@end