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

#define  S_Rect		0
#define  S_RoundRect	1
#define  S_Oval		2

@implementation ImageOpr (SFrame)


static int sq_width, sq_x, sq_y;
static float t_rad = 0.0;
static float ov_x, ov_y;
static int background[3];

static void init_sftransp(float ratio, int shape, int color[], commonInfo *cinf)
{
	int i, x;

	for (i = 0; i < 3; i++)
		background[i] = color[i];
	if (t_rad <= 0.0) srandom(getpid());
	x = (cinf->width > cinf->height) ? cinf->height : cinf->width;
	if (shape == S_Oval) {
		ov_x = cinf->width / 2.0;
		ov_y = cinf->height / 2.0;
		t_rad = 1.0 - ratio * 2.0;
	}else {
		if (shape == S_Rect) {
			sq_width = x * ratio;
			t_rad = 0.0;
		}else { /* S_RoundRect */
			if (ratio >= 0.25) {
				sq_width = x * 0.5;
				t_rad = 1.0 - ratio * 2.0;
			}else {
				sq_width = x * ratio * 2.0;
				t_rad = 0.5;
			}
		}
		sq_x = cinf->width - sq_width;
		sq_y = cinf->height - sq_width;
	}
}

static int sfTransp(int shape, BOOL useAlpha, int ax, int ay)
{
	float v, w;
	int x, y, n;

	if (shape == S_Oval) {
		w = (ax - ov_x) / ov_x;
		v = (ay - ov_y) / ov_y;
		v = w * w + v * v;
	}else {
		x = (ax < sq_width) ? (sq_width - 1 - ax) : (ax - sq_x);
		y = (ay < sq_width) ? (sq_width - 1 - ay) : (ay - sq_y);
		if (x < 0 && y < 0)
			return AlphaOpaque;
		if (shape == S_Rect)
			v = (x >= y) ? (x * x) : (y * y);
		else { /* S_RoundRect */
			if (x < 0) x = 0;
			else if (y < 0) y = 0;
			v = x * x + y * y;
		}
		v /= (float)(sq_width * sq_width);
	}
	if ((v -= t_rad) < 0.0)
		return AlphaOpaque;
	v /= 1.0 - t_rad;
	if (useAlpha)
		return ((int)(v * 0xffff) > (random() & 0xffff))
			? AlphaTransp : AlphaOpaque;
	n = 255 * (1.0 - v);
	return (n < 0) ? 0 : ((n > 255) ? 255 : n);
}

static commonInfo *makeSFrameMap(float ratio, int shape, int color[],
	commonInfo *cinf, unsigned char *map[], unsigned char *newmap[])
{
	commonInfo *newinf = NULL;
	int pn, alp, cn;
	int x, y, i;
	BOOL useAlpha, beColor;
	int elm[MAXPLANE], ptr, av = 0;
	unsigned char *working[MAXPLANE];

	init_sftransp(ratio, shape, color, cinf);
	newmap[0] = NULL;
	if ((newinf = (commonInfo *)malloc(sizeof(commonInfo))) == NULL)
		goto ErrEXIT;
	useAlpha = (color[ALPHA] != AlphaOpaque);
	*newinf = *cinf;
	newinf->palette = NULL;
	newinf->palsteps = 0;
	newinf->isplanar = YES;
	if (!useAlpha && newinf->bits < 4)
		newinf->bits = 4;
	newinf->xbytes = byte_length(newinf->bits, newinf->width);
	newinf->alpha = useAlpha;
	beColor = (cinf->numcolors >= 3);
	if (!beColor && !useAlpha) {
		int d;
		for (i = 0; i < 3; i++) {
			d = color[i % 3] - color[(i+1) % 3];
			if (d > 5 || d < -5) {
				beColor = YES;
				break;
			}
		}
	}
	if (beColor)
		cn = 3;
	else {
		newinf->cspace = NX_OneIsWhiteColorSpace;
		cn = 1;
	}
	cinf->numcolors = pn = cn;
	if (useAlpha)
		alp = pn++;
	else alp = 0;	/* not used */

	if (allocImage(working, newinf->width, newinf->height, 8, pn))
		goto ErrEXIT;
	if (initGetPixel(cinf) != 0)
		goto ErrEXIT;
	resetPixel(map, 0);
	if (useAlpha)
	    for (y = 0; y < newinf->height; y++) {
		ptr = newinf->width * y;
		for (x = 0; x < newinf->width; x++) {
		    getPixel(&elm[RED], &elm[GREEN], &elm[BLUE], &elm[ALPHA]);
		    if (elm[ALPHA] == AlphaTransp
			    || (av = sfTransp(shape, YES, x, y)) == AlphaTransp) {
			for (i = 0; i < cn; i++)
			    working[i][ptr + x] = 0xff;
			working[alp][ptr + x] = AlphaTransp;
		    }else {
			for (i = 0; i < cn; i++)
			    working[i][ptr + x] = elm[i];
			working[alp][ptr + x] = (elm[ALPHA] < av) ? elm[ALPHA] : av;
		    }
		}
	    }
	else
	    for (y = 0; y < newinf->height; y++) {
		ptr = newinf->width * y;
		for (x = 0; x < newinf->width; x++) {
		    getPixel(&elm[RED], &elm[GREEN], &elm[BLUE], &elm[ALPHA]);
		    if ((av = sfTransp(shape, NO, x, y)) > elm[ALPHA])
		    	av = elm[ALPHA];
		    compositeColors(elm, background, av);
		    for (i = 0; i < cn; i++)
			working[i][ptr + x] = elm[i];
		}
	    }

	if (newinf->bits < 8) {
		if (allocImage(newmap, newinf->width, newinf->height, newinf->bits, pn))
			goto ErrEXIT;
		packWorkingImage(newinf, pn, working, newmap);
		free((void *)working[0]);
	}else {
		for (i = 0; i < MAXPLANE; i++)
			newmap[i] = working[i];
	}
	return newinf;

ErrEXIT:
	if (newinf)
		free((void *)newinf);
	if (working[0]) free((void *)working[0]);
	return NULL;
}


- softFrame:(float)ratio shape:(int)shape color:(int *)color
{
	ToyWin	*tw, *newtw = nil;
	ToyView	*tv = nil;
	commonInfo	*cinf, *newinf;
	const char *fnam;
	char fn[256];
	NXBitmapImageRep *rep;
	unsigned char *map[MAXPLANE], *newmap[MAXPLANE];

	if ((tw = [self keyParentWindow: SoftFrame]) == nil) {
		NXBeep();
		return self;
	}
	tv = [tw toyView];
	cinf = [tv commonInfo];
	fnam = [tw filename];
	if (![self checkCommonInfo:cinf filename:fnam])
		return self;
	sprintf(fn, "%s(Frame)", fnam);
	rep = (NXBitmapImageRep *)[[tv image] bestRepresentation];
	[rep getDataPlanes: map];
	newinf = makeSFrameMap(ratio, shape, color, cinf, map, newmap);
	if (newinf == NULL) {
		warnAlert(fnam, Err_MEMORY);
		return self;
	}
//	[theController messageDisplay: "Making Soft Frame..."];
	newtw = [[ToyWin alloc] init:tw by:SoftFrame];
	[newtw initLocateWindow:fn width:newinf->width height:newinf->height];
	[newtw makeComment: newinf from: cinf];
//	[theController messageDisplay:NULL];
	[newtw drawView:newmap info: newinf];

	[theController newWindow: newtw];
	return self;
}

@end
