#import "../ImageOpr.h"
#import <appkit/Application.h>
#import <appkit/publicWraps.h>
#import <appkit/NXBitmapImageRep.h>
#import <appkit/Control.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <libc.h>
#import "../TVController.h"
#import "../ToyWin.h"
#import "../ToyView.h"
#import "../common.h"
#import "../getpixel.h"
#import "imageOperation.h"


@implementation ImageOpr (CutDownBits)

/* Local Method */
- doCutDown:(const char *)fn parent:parent
	info:(commonInfo *)cinf map:(unsigned char **)map to:(int)bits
{
	ToyWin	*tw;
	commonInfo *newinf = NULL;
	unsigned char *working[MAXPLANE], *planes[MAXPLANE];
	int	i, pl;

	working[0] = planes[0] = NULL;
	tw = NULL;
	if ((newinf = (commonInfo *)malloc(sizeof(commonInfo))) == NULL)
		goto ErrEXIT;
	*newinf = *cinf;
	if (cinf->cspace == NX_OneIsBlackColorSpace)
		newinf->cspace = NX_OneIsWhiteColorSpace;
		/* getPixel() fixes 0 as Black */
	newinf->bits = bits;
	newinf->xbytes = byte_length(bits, newinf->width);
	newinf->palette = NULL;
	newinf->palsteps = 0;
	newinf->isplanar = YES;
	pl = newinf->numcolors;
	if (newinf->alpha) pl++;

	if (allocImage(planes, newinf->width, newinf->height, bits, pl))
		goto ErrEXIT;
	tw = [[ToyWin alloc] init:parent by:CutDown];
	[tw initLocateWindow:fn width:newinf->width height:newinf->height];
	[tw makeComment: newinf from: cinf];

	if (!cinf->isplanar || cinf->bits < 8) {
		int	x, y, ptr, pidx;
		int	idx[MAXPLANE];
		int	pix[MAXPLANE];

		for (i = 0; i < newinf->numcolors; i++) idx[i] = i;
		for ( ; i < MAXPLANE; i++) idx[i] = -1;
		if (newinf->alpha) idx[ALPHA] = pl;
		if (allocImage(working, newinf->width, newinf->height, 8, pl))
			goto ErrEXIT;
		resetPixel(map, 0);
		for (y = 0; y < newinf->height; y++) {
			ptr = y * newinf->width;
			for (x = 0; x < newinf->width; x++) {
				getPixelA(pix);
				for (i = 0; i <= ALPHA; i++) {
					if ((pidx = idx[i]) < 0) continue;
					working[pidx][ptr + x] = pix[i];
				}
			}
		}
		packWorkingImage(newinf, pl, working, planes);
		free((void *)working[0]);
	}else
		packWorkingImage(newinf, pl, map, planes);
	if ([tw drawView:planes info: newinf] == nil)
		goto ErrEXIT;
	[theController newWindow: tw];
	return self;

ErrEXIT:
	if (working[0]) free((void *)working[0]);
	if (planes[0]) free((void *)planes[0]);
	if (newinf)  free((void *)newinf);
	if (tw) [[tw window] performClose: self];
		/* This call frees tw */
	return nil;
}


- cutDownBitsTo:(int)bits
{
	ToyWin	*tw;
	ToyView	*tv = NULL;
	NXImageRep	*rep;
	commonInfo	*cinf;
	unsigned char	*map[MAXPLANE];
	const char	*fnam;
	char	fn[256];
	int	err;

	if ((tw = [theController keyWindow]) == nil ||
		(bits != 4 && bits != 2 && bits != 1)) {
		NXBeep();
		return self;
	}
	tv = [tw toyView];
	cinf = [tv commonInfo];
	fnam = [tw filename];
	if (cinf->type == Type_eps) {
		warnAlert(fnam, Err_EPS_IMPL);
		return self;
	}
	if (cinf->bits <= bits) {
		warnAlert(fnam, Err_OPR_IMPL);
		return self;
	}
	if (cinf->cspace == NX_CMYKColorSpace) {
		warnAlert(fnam, Err_IMPLEMENT);
		return self;
	}
	if (cinf->width >= MAXWidth || cinf->height >= MAXWidth) {
		errAlert(fnam, Err_MEMORY);
		return self;
	}
	sprintf(fn, "%s(%dBits)", fnam, bits);

	rep = [[tv image] bestRepresentation];
	[(NXBitmapImageRep *)rep getDataPlanes: map];
	if ((err = initGetPixel(cinf)) != 0) {
		errAlert(fnam, err);
		return self;
	}
	if ([self doCutDown:fn parent:tw info:cinf map:map to:bits] == nil)
		errAlert(fn, Err_MEMORY);
	return self;
}

@end
