#import "ToyWinEPS.h"
#import <appkit/TextField.h>
#import <appkit/NXImage.h>
#import <appkit/Window.h>
#import <appkit/NXEPSImageRep.h>
#import <appkit/NXBitmapImageRep.h>
#import <appkit/tiff.h>
#import <stdio.h>
#import <libc.h>
#import <string.h>
#import <math.h>
#import "ToyView.h"
#import "common.h"
#import "strfunc.h"

@implementation ToyWinEPS


/*
    EPSをTIFFに変換するため、imageをいったんstreamに書き出して、
    新しいNXImageのオブジェクトにスクリーンに依存しない色の表現が可能な
    設定を行ってから新たに読み込み、さらに tiffイメージでstreamに書き出す。
    一般に用いられている Sharon Zakhour の "TIFFandEPS" の方法、即ち、
	[epsimg lockFocus];
	tifrep = [[NXBitmapImageRep alloc] initData: NULL fromRect: &rect];
	[epsimg unlockFocus];
	[tifrep getDataPlanes: map];
    では、画面に表示されている色表現のまま書き出されてしまうので、カラー
    EPSをモノクロ画面で扱った場合にはtiffがモノクロになってしまう。
*/

- (NXStream *)openTiffStream:(BOOL)compress
{
	NXStream *stream, *epsst;
	NXImage	*img;
	NXSize	cSize;
	BOOL	freeflag = NO;

	img = [[self toyView] image];
	[img getSize: &cSize];
	if ((cSize.width >= MAXWidth)
	|| (stream = NXOpenMemory(NULL, 0, NX_READWRITE)) == NULL)
		return NULL;
	if ([Window defaultDepthLimit] != NX_TwentyFourBitRGBDepth) {
		/* Need to open EPS stream */
		if ((epsst = [self openEPSStream]) == NULL)
			return NULL;
		img = [NXImage alloc];
		freeflag = YES;
		[img setScalable: YES];
		[img setCacheDepthBounded: NO];
		[img useCacheWithDepth: NX_TwentyFourBitRGBDepth];
		[img loadFromStream: epsst];
		[img setSize: &cSize];	// This order is important.
		NXCloseMemory(epsst, NX_FREEBUFFER);
	}
	[img writeTIFF:stream allRepresentations:NO
		usingCompression:(compress ? NX_TIFF_COMPRESSION_LZW
			: NX_TIFF_COMPRESSION_NONE) andFactor:0.0];
    	NXFlush(stream);   
	NXSeek(stream, 0L, NX_FROMSTART);
	if (freeflag) [img free];
	return stream;
}


static NXBitmapImageRep *tiffrep = nil;

/* Overload */
- (int)getBitmap:(unsigned char **)map info:(commonInfo **)infp
{
	NXStream *stream;
	static commonInfo info;

	if ((stream = [self openTiffStream:NO]) == NULL)
		return Err_MEMORY;
	tiffrep = [[NXBitmapImageRep alloc] initFromStream: stream];
	NXCloseMemory(stream, NX_FREEBUFFER);
	[tiffrep getDataPlanes: map];

	info.width	= [tiffrep pixelsWide];
	info.height	= [tiffrep pixelsHigh];
	info.xbytes	= [tiffrep bytesPerRow];
	info.type	= Type_tiff;
	info.bits	= [tiffrep bitsPerSample];
	info.numcolors	= [tiffrep numColors]; /* without alpha */
	info.alpha	= [tiffrep hasAlpha];
	info.isplanar	= [tiffrep isPlanar];
	info.cspace	= [tiffrep colorSpace];
	info.palette	= NULL;
	info.palsteps	= 0;
	info.memo[0]	= 0;
	*infp = &info;
	return 0;
}

/* Overload */
- freeTempBitmap	/* must be called after getBitmap:info: */
{
	if (tiffrep != nil) {
		[tiffrep free];
		tiffrep = nil;
	}
	return self;
}


/* Overload */
- (NXStream *)openEPSStream
{
	NXStream *stream;
	NXEPSImageRep *rep;
	char	*eps;
	int i, n;

	stream = NXOpenMemory(NULL, 0, NX_READWRITE);
	if (stream == NULL)
		return NULL;
	rep = (NXEPSImageRep *)[[[self toyView] image] bestRepresentation];
	[rep getEPS:&eps length:&n];
	for (i = 0; i < n; i++)
		NXPutc(stream, *eps++);
	NXFlush(stream);
	NXSeek(stream, 0L, NX_FROMSTART);
	return stream;
}


/* New */
- (NXStream *)rotateEPS:(int)op to:(int)angle width:(int)lx height:(int)ly
	name: (const char *)fname error: (int *)err
{
	NXStream *stream;
	NXEPSImageRep *rep;
	NXRect	rect;
	char	*eps;
	int	i, n, dx, dy;

	*err = 0;
	rep = (NXEPSImageRep *)[[[self toyView] image] bestRepresentation];
	[rep getEPS:&eps length:&n];
	[rep getBoundingBox:&rect];
	stream = NXOpenMemory(NULL, 0, NX_READWRITE);
	if (stream == NULL) {
		*err = Err_MEMORY;
		return NULL;
	}
	dx = -(rect.origin.x + rect.size.width);
	dy = -(rect.origin.y + rect.size.height);
	if (op == Horizontal) {
		dy = -rect.origin.y;
	}else if (op == Vertical) {
		dx = -rect.origin.x;
	}else if (angle == 90) {
		dx = -rect.origin.x;
	}else if (angle == 270) {
		dy = -rect.origin.y;
	}else if (angle != 180) {
		commonInfo *cinf;
		double r, s, c;
		double th = ((double)angle * 3.14159265) / 180.0;
		cinf = [[self toyView] commonInfo];
		if (angle > 270) {
			r = cinf->width * (s = sin(th));
			dx = -r * s;
			dy = -r * cos(th);
		}else if (angle > 180) {
			r = cinf->height * (c = cos(th));
			dx = -r * sin(th) - cinf->width;
			dy = -r * c;
		}else if (angle > 90) {
			r = cinf->width * (c = cos(th));
			dx = -r * c;
			dy = r * sin(th) - cinf->height;
		}else {
			r = cinf->height * (s = sin(th));
			dx = r * cos(th);
			dy = -r * s;
		}
		dx -= rect.origin.x - 0.5;
		dy -= rect.origin.y - 0.5;
	}

	NXPrintf(stream, "%s\n%s: %s\n",
		"%!PS-Adobe-2.0 EPSF-2.0", "%%Title", fname);
	NXPrintf(stream, "%s: 0 0 %d %d\n%s\n\ngsave\n",
		"%%BoundingBox", lx, ly, "%%EndComments");
	if (op == Rotation)
		NXPrintf(stream, "%d rotate\n", angle);
	else
		NXPrintf(stream, "%s scale\n",
			(op == Horizontal)?"-1 1":"1 -1");
	NXPrintf(stream, "%d %d translate\n%s\n", dx, dy, "%%BeginDocument: ");
	for (i = 0; i < n; i++)
		NXPutc(stream, *eps++);
	NXPrintf(stream, "\n%s\ngrestore\n", "%%EndDocument");
	NXFlush(stream);
	NXSeek(stream, 0L, NX_FROMSTART);
	// NXCloseMemory(stream, NX_FREEBUFFER);
	return stream;
}

/* New */
- (NXStream *)clipEPS: (NXRect *)select error: (int *)err
{
	NXStream *stream;
	NXEPSImageRep *rep;
	NXRect	rect;
	char	*eps, buf[512];
	int	i, n, bp;
	int	loc[4];

	*err = 0;
	rep = (NXEPSImageRep *)[[[self toyView] image] bestRepresentation];
	[rep getEPS:&eps length:&n];
	[rep getBoundingBox:&rect];
	loc[0] = rect.origin.x + select->origin.x;
	loc[1] = rect.origin.y + select->origin.y;
	loc[2] = loc[0] + (int)select->size.width;
	loc[3] = loc[1] + (int)select->size.height;
	stream = NXOpenMemory(NULL, 0, NX_READWRITE);
	if (stream == NULL) {
		*err = Err_MEMORY;
		return NULL;
	}
	for (i = 0, bp = 0; ; i++) {
		if (i >= n) {
			NXCloseMemory(stream, NX_FREEBUFFER);
			*err = Err_ILLG;
			return NULL;
		}
		if ((buf[bp++] = *eps++) >= ' ')
			continue;
		if (strncmp(buf, "%%BoundingBox", 13) == 0) {
			NXPrintf(stream, "%s: %d %d %d %d\n", "%%BoundingBox",
				loc[0], loc[1], loc[2], loc[3]);
			for (++i ; i < n; i++)
				NXPutc(stream, *eps++);
			break;
		}else {
			buf[bp] = 0;
			NXPrintf(stream, "%s", buf);
		}
		bp = 0;
	}
	NXFlush(stream);
	NXSeek(stream, 0L, NX_FROMSTART);
	// NXCloseMemory(stream, NX_FREEBUFFER);
	return stream;
}


/* New */
- (NXStream *)resizeEPS:(float)factor name:(const char *)fname error:(int *)err
{
	NXStream *stream;
	NXEPSImageRep *rep;
	NXRect	rect;
	char	*eps;
	int	i, n, loc[4];

	*err = 0;
	rep = (NXEPSImageRep *)[[[self toyView] image] bestRepresentation];
	[rep getEPS:&eps length:&n];
	[rep getBoundingBox:&rect];
	loc[0] = rect.origin.x * factor;
	loc[1] = rect.origin.y * factor;
	loc[2] = loc[0] + rect.size.width * factor;
	loc[3] = loc[1] + rect.size.height * factor;
	stream = NXOpenMemory(NULL, 0, NX_READWRITE);
	if (stream == NULL) {
		*err = Err_MEMORY;
		return NULL;
	}
	NXPrintf(stream, "%s\n%s: %s\n",
		"%!PS-Adobe-2.0 EPSF-2.0", "%%Title", fname);
	NXPrintf(stream, "%s: %d %d %d %d\n%s\n\n", "%%BoundingBox",
		loc[0], loc[1], loc[2], loc[3], "%%EndComments");
	NXPrintf(stream, "gsave\n%f %f scale\n%s\n",
		factor, factor, "%%BeginDocument: ");
	for (i = 0; i < n; i++)
		NXPutc(stream, *eps++);
	NXPrintf(stream, "\n%s\ngrestore\n", "%%EndDocument");
	NXFlush(stream);
	NXSeek(stream, 0L, NX_FROMSTART);
	// NXCloseMemory(stream, NX_FREEBUFFER);
	return stream;
}

@end
