/*
	Background.m
		based on "Background"
		by Scott Hess and Andreas Windemut (1991)
*/

#import "Background.h"
#import <dpsclient/wraps.h>
#import <appkit/Application.h>
#import <appkit/Window.h>
#import <appkit/NXImage.h>
#import <appkit/Control.h>
#import <appkit/screens.h>
#import <defaults/defaults.h>
#import <stdio.h>
#import "../PSsplat.h"
#import "../backgops.h"
#import "../TVController.h"

#define  PSsplat(r, p)   _PSsplat( (r)->origin.x, (r)->origin.y, \
		(r)->size.width, (r)->size.height, (p)->x, (p)->y )
#define  WLevel_Behind	(-2)
#define  WLevel_Front	30	/* must be < 50 (BackSpace's SaverWindow) */
#define  TooLargeRatio	2.2

#define  bgMonoDefault	0
#define  bgMonoCustom	1
#define  bgColorDefault	2
#define  bgColorCustom	3


@implementation Background:View

- initFrame:(const NXRect *)frameRect;
{
	[super initFrame: frameRect];
	[NXApp getScreenSize:&screenSize];
	image = NULL;
	isfront = NO;
	bgPaint = bgMonoDefault;
	return self;
}

- free
{
	if (image != nil)
		[image free];
	[super free];
	return self;
}

/* Local Method */
- getDafaultBGColor
{
	const NXScreen *sc;
	const char *defcolor;

	sc = [NXApp colorScreen];
	if (sc->depth == NX_TwoBitGrayDepth
		|| sc->depth == NX_EightBitGrayDepth) {
		defcolor = NXGetDefaultValue("NeXT1", "BWBackgroundColor");
		if (!defcolor)
			bgPaint = bgMonoDefault;	
		else {
			sscanf(defcolor, "%f", &bgColor[0]);
			bgPaint = bgMonoCustom;	
		}
	}else {
		defcolor = NXGetDefaultValue("NeXT1", "BackgroundColor");
		if (!defcolor)
			bgPaint = bgColorDefault;
		else {
			sscanf(defcolor, "%f%f%f",
				&bgColor[0], &bgColor[1], &bgColor[2]);
			bgPaint = bgColorCustom;
		}
	}
	return self;
}

/* Local Method */
- paintDefault:(NXRect *)rect
{
	switch (bgPaint) {
	case bgMonoDefault:
		PSsetgray(NX_DKGRAY);
		break;
	case bgMonoCustom:
		PSsetgray(bgColor[0]);
		break;
	case bgColorDefault:
		PSsetrgbcolor(0.33333, 0.33333, 0.46667);
		break;
	case bgColorCustom:
		PSsetrgbcolor(bgColor[0], bgColor[1], bgColor[2]);
		break;
	default:
		PSsetgray(NX_DKGRAY);
		break;
	}
	NXRectFill(rect);
	return self;
}


- (Window *)initWinAttr
{
	Window *win;
	NXRect rect;

	[self getFrame: &rect];
	win = [[Window allocFromZone:[self zone]]
			initContent:&rect style:NX_TOKENSTYLE 
			backing:NX_BUFFERED  buttonMask:0 defer:NO];
	[win setContentView: self];
	[win useOptimizedDrawing:YES];
	[win removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK
		| NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
		| NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
		| NX_KEYDOWNMASK | NX_KEYUPMASK | NX_CURSORUPDATEMASK)];
	[self getDafaultBGColor];
/* { */	[self lockFocus];
	[self paintDefault: &rect];
/* } */	[self unlockFocus];
	[self toBehind: self];
	return win;
}

- (BOOL)acceptsFirstMouse
{
	return YES;
}

- toBehind:sender
{
	PSsetwindowlevel(WLevel_Behind, [window windowNum]);
	[window orderWindow:NX_BELOW relativeTo:0];
	[window removeFromEventMask:NX_MOUSEDOWNMASK];
	[theController backWinFront: (isfront = NO)];
	return self;
}

- toFront:sender
{
	PSsetwindowlevel(WLevel_Front, [window windowNum]);
//	[window orderFront:sender];
	[window addToEventMask:NX_MOUSEDOWNMASK];
	[theController backWinFront:(isfront = YES)];
	return self;
}

- mouseDown:(NXEvent *)event
{
	[[NXApp hide: self] unhide: self];
	/* These calls are needed because of illegal action of WM. */
	return [self toBehind: self];
}

- (BOOL)isFront
{
	return isfront;
}


/* Local Method */
- (double)enlargeScale: (const NXSize *)size by: (int)method err:(int *)err
{
	double xr, yr, w, ratio = 1.0;

	if (err) *err = 0;
	xr = (double)screenSize.width / size->width;
	yr = (double)screenSize.height / size->height;
	if (method == bk_FitScreen)
		ratio = (xr < yr) ? xr : yr;
	else if (err == NULL)	/* bk_CoverScreen for Bitmap */
		ratio = (xr > yr) ? xr : yr;
	else { /* bk_CoverScreen */
		if (xr > yr) {
			w = xr * size->height / (double)screenSize.height;
			ratio = xr;
		}else {
			w = yr * size->width / (double)screenSize.width;
			ratio = yr;
		}
		if (w > TooLargeRatio) { /* Too Large */
			ratio = (xr < yr) ? xr : yr; /* bk_FitScreen */
			*err = 1;
		}
	}
	return ratio;
}

- setImage: (NXImage *)backimage hasAlpha:(BOOL)alpha with: (int)method
{
	NXSize sz, nwsz;
	NXPoint pnt;
	double	ratio = 1.0;
	int	mode;
	BOOL	large = FALSE;

	drawMethod = method;
	[backimage getSize: &sz];
	if (sz.width <= 0 || sz.height <= 0)
		return self;
	if (image != NULL)
		[image free];
	image = [[NXImage allocFromZone:[self zone]] setScalable:YES];
	if (image == NULL)
		return nil;

	if (drawMethod == bk_FitScreen || drawMethod == bk_CoverScreen) {
		ratio = [self enlargeScale:&sz by:drawMethod err:NULL];
		nwsz.width = sz.width * ratio;
		nwsz.height = sz.height * ratio;
		drawMethod = bk_Centering;
	}else
		nwsz = sz;
	/* To make size of 'image' smaller than screen */
	pnt.x = pnt.y = 0;
	if (nwsz.width > screenSize.width) {
		pnt.x = (screenSize.width - nwsz.width) / (ratio * 2.0);
		nwsz.width = screenSize.width;
		large = TRUE;
	}
	if (nwsz.height > screenSize.height) {
		pnt.y = (screenSize.height - nwsz.height) / (ratio * 2.0);
		nwsz.height = screenSize.height;
		large = TRUE;
	}

	if (large) {
		sz.width = nwsz.width / ratio;
		sz.height = nwsz.height / ratio;
	}
	[image setSize: &sz];
	[self getDafaultBGColor];
	mode = alpha ? NX_SOVER : NX_COPY;
/* { */	[image lockFocus];
	if (alpha) {
		NXRect rect;
		rect.size = sz;
		rect.origin.x = rect.origin.y = 0;
		[self paintDefault: &rect];
	}
	[backimage composite:mode toPoint:&pnt];
/* } */	[image unlockFocus];
	[image setSize: &nwsz];

	return self;
}

- setStream: (NXStream *)stream with: (int)method
{
	NXImage *backimage;
	NXSize	sz;
	int	err = 0;
	id	rtn;

	if ((backimage = [NXImage allocFromZone:[self zone]]) == NULL)
		return nil;
	[backimage initFromStream: stream];
	[backimage getSize: &sz];
	if (method == bk_FitScreen || method == bk_CoverScreen) {
		double r = [self enlargeScale:&sz by:method err:&err];
		sz.width *= r;
		sz.height *= r;
		method = bk_Centering;
		[backimage setScalable:YES];
		[backimage setSize: &sz];
	}
	rtn = [self setImage: backimage hasAlpha:YES with:method];
	[backimage free];
	return (err ? nil : rtn);
}

- drawSelf:(NXRect *)rect :(int)count
{
	NXSize sz;
	NXPoint pnt;

	if (image == nil)
		return self;
	[image getSize:&sz];
	if (sz.width <= 0 || sz.height <= 0)
		return self;

	if (drawMethod == bk_Centering) { /* Centering */
		[self paintDefault: rect];
		pnt.x = (screenSize.width - sz.width) / 2;
		pnt.y = (screenSize.height - sz.height) / 2;
		[image composite:NX_COPY toPoint:&pnt];
	}else {
		int i, wd, ht;
		NXRect irect;

		if (drawMethod == bk_Tiling || sz.height >= screenSize.height) {
	/* Tiling */
			wd = irect.size.width = sz.width;
			ht = irect.size.height = sz.height;
		}else {
	/* Brick Work */
			wd = (int)(sz.width) / 2;
			pnt.x = -wd, pnt.y = sz.height;
			[image composite:NX_COPY toPoint:&pnt];
			pnt.x = sz.width - wd;
			[image composite:NX_COPY toPoint:&pnt];
			wd = irect.size.width = sz.width;
			ht = irect.size.height = sz.height * 2;
		}
		pnt.x = pnt.y = 0;
		[image composite:NX_COPY toPoint:&pnt];

		irect.origin = pnt;
		for(i = wd; i < screenSize.width; i += wd) {
			pnt.x = i;
			PSsplat(&irect, &pnt);
		}
		pnt.x=0;
		irect.size.width = screenSize.width;
		for(i = ht; i < screenSize.height; i += ht) {
			pnt.y = i;
			PSsplat(&irect, &pnt);
		}
	}
	return self;
}

@end
