#import "Image.h"
#import "GraphicView.h"
#import <appkit/NXImage.h>
#import <appkit/Panel.h>
#import <dpsclient/wraps.h>
#import <mach.h>

/* Optimally viewed in a wide window.  Make your window big enough so that this comment fits on one line without wrapping. */

@implementation Image : Graphic
/*
 * Image is a simple graphic which takes PostScript or
 * TIFF images and draws them in a bounding box (it scales
 * the image if the bounding box is changed).  It is
 * implemented using the NXImage class.  Using NXImage
 * here is especially nice since it images its PostScript
 * in a separate context (thus, any errors that PostScript
 * generates will not affect our main drawing context).
 */

/* Set the class version */

+ initialize
{
    [self setVersion:2];
    return self;
}

/* Creation methods */

- initFromStream:(NXStream *)stream allowAlpha:(BOOL)isAlphaOk
/*
 * Creates a new NXImage and sets it to be scalable and to retain
 * its data (which means that when we archive it, it will actually
 * write the TIFF or PostScript data into the stream).
 */
{
    [super init];
    if (image = [[NXImage allocFromZone:[self zone]] initFromStream:stream]) {
	[image getSize:&originalSize];
	[image setScalable:YES];
	[image setDataRetained:YES];
	alphaOk = isAlphaOk;
	bounds.size = originalSize;
    } else {
	[self free];
	self = nil;
    }
    return self;
}

- free
{
    [image free];
    return [super free];
}

/* Methods overridden from superclass */

- (BOOL)isOpaque
{
    return alphaOk ? NO : YES;
}

- (float)naturalAspectRatio
{
    if (!originalSize.height) return 0.0;
    return originalSize.width / originalSize.height;
}

- draw
/*
 * If we are resizing, we just draw a gray box.
 * If not, then we simply see if our bounds have changed
 * and update the NXImage object if they have.  Then,
 * if we do not allow alpha (i.e. this is a TIFF image),
 * we paint a white background square (we don't allow
 * alpha in our TIFF images since it won't print and
 * Draw is WYSIWYG).  Finally, we SOVER the image.
 * If we are not keeping the cache around, we tell
 * NXImage to toss its cached version of the image
 * via the message recache.
 */
{
    NXSize currentSize;

    if (bounds.size.width < 1.0 || bounds.size.height < 1.0) return self;

    if (DrawStatus == Resizing) {
	PSsetgray(NX_DKGRAY);
	PSsetlinewidth(0.0);
	PSrectstroke(bounds.origin.x, bounds.origin.y,
		     bounds.size.width, bounds.size.height);
    } else if (image) {
	[image getSize:&currentSize];
	if (currentSize.width != bounds.size.width || currentSize.height != bounds.size.height) [image setSize:&bounds.size];
	if (!alphaOk) {
	    PSsetgray(NX_WHITE);
	    NXRectFill(&bounds);
	}
	[image composite:NX_SOVER toPoint:&bounds.origin];
	if (dontCache && NXDrawingStatus == NX_DRAWING) [image recache];
    }

    return self;
}

- setCacheable:(BOOL)flag
{
    dontCache = flag ? NO : YES;
    return self;
}

- (BOOL)isCacheable
{
    return !dontCache;
}

- write:(NXTypedStream *)stream
/*
 * All that is needed to archive the NXImage.
 */
{
    [super write:stream];
    NXWriteObject(stream, image);
    NXWriteSize(stream, &originalSize);
    NXWriteTypes(stream, "c", &alphaOk);
    return self;
}

- read:(NXTypedStream *)stream
{
    [super read:stream];
    image = NXReadObject(stream);
    NXReadSize(stream, &originalSize);
    if (NXTypedStreamClassVersion(stream, "Image") > 1) {
	NXReadTypes(stream, "c", &alphaOk);
    }
    return self;
}

@end
