/*  
    This file is part of MoveBlackView, a Screensaverbundle.

    Copyright (C) 1996-1998 Jens Heise

    Version 1.0
    
    MoveBlackView is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License,
    version 1, along with this program; if not, write to the Free 
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// The source for this screensaver is due to Eric P. Scott. It was originated
// as screensaver for loginwindow and only ported to BackSpace by myself. Its
// original name was "TimeToBlack.tar.gz" and can be found on 
// "peanuts.leo.org".
// A very small number of modifications were made by David Bau to add
// blacking behavior and also the TimeToMove and TimeToBlack defaults.
// Works like a charm under NS 3.1, but since it uses an unreleased API,
// there is no guarantee of anything in future versions.
//
// Some modifications were made by myself to support BackSpace-inspectors and
// user defined images. - Jens Heise.

#import "MoveBlackView.h"
#import "Thinker.h"

#define str_copy(str)	((str == NULL) ? NULL : NXCopyStringBuffer(str))
#define str_free(str)	{if (str) free(str);}


@implementation MoveBlackView


- (float)frandom
{
    return (random()&0x7fffffff)/(float)2147483648.0;
}

- (float)randBetween:(float)low :(float)high
{
    if (low>high) {
	register float temp;

    	temp=low;
	low=high;
	high=temp;
    }
    high-=low;
    high*=[self frandom];
    return low+high;
}


- moveImage
{
    imageFrame.origin.x=(float)floor((double)[self randBetween:0.0
	:bounds.size.width-imageFrame.size.width]);
    imageFrame.origin.y=(float)floor((double)[self randBetween:0.0
	:bounds.size.height-imageFrame.size.height]);
    return self;
}

- moveText
{
    register int i, j, k, l;

    i=0; do {
	textFrame.origin.x=floor((double)[self randBetween:0.0
	    :bounds.size.width-textFrame.size.width]);
	textFrame.origin.y=floor((double)[self randBetween:0.0
	    :bounds.size.height-textFrame.size.height]);
	if (!NXIntersectsRect(&textFrame, &imageFrame)) break;
    } while (++i<50);
    if (i>49) {
	register double w;

	if (imageFrame.size.width/2+imageFrame.origin.x<
	    bounds.size.width/2) {
	    k=imageFrame.origin.x+imageFrame.size.width;
	    w=bounds.size.width;
	}
	else {
	    k=0;
	    w=imageFrame.origin.x;
	}
	l=w;
	if (imageFrame.size.height/2+imageFrame.origin.y<
	    bounds.size.height/2) {
	    i=imageFrame.origin.y+imageFrame.size.height;
	    w=bounds.size.height;
	}
	else {
	    i=0;
	    w=imageFrame.origin.y;
	}
	j=w;
	if (textFrame.size.width<l-k&&textFrame.size.height<j-i) {
	    textFrame.origin.x=k;
	    textFrame.origin.y=i;
	}
    }
    return self;
}


- drawSelf:(const NXRect *)rects :(int)rectCount
{
    PSsetgray(NX_BLACK);
    NXRectFill(rects);
    if (!blackened) {
	[image composite:NX_SOVER toPoint:&imageFrame.origin];
	[hostname drawInside:&textFrame inView:self];
    }
    return self;
}

- oneStep
{
    struct timeval tv;
    struct timezone tz;
    int		oldBlack=blackened;

    if (blackened) 
    {	
	usleep(500000);	
	return self;
    } /* if */

    /* check if TimeToBlack has elapsed */
    if (timeToBlack > 0.0) 
    {
        gettimeofday(&tv,&tz);
        if (tv.tv_sec-startTime >= timeToBlack) 
	    blackened=YES;
    }

    gettimeofday(&tv,&tz);

    if (!blackened && (tv.tv_sec >= lastMove+timeToMove))
    {
	lastMove = tv.tv_sec;
	[self moveImage];
	[self moveText];
	[self display];
    } /* if */
    
    if (oldBlack != blackened)
	[self display];
   
    usleep(5000);	
    
    return self;
}

- initFrame:(NXRect *)frameRect
{
    char	h[100];
    char 	hn2[512];
    struct timeval 	tv;
    struct timezone 	tz;

    [super initFrame:frameRect];

    imageFile = NULL;
    image = nil;
    /* pick up image */
    [self getImageFile];

    /* pick up host name */
    if (gethostname(h, 100) == 0) {
	int 	i;

	for (i=0;i<strlen(h);i++) {
	    hn2[i*2]=h[i];
	    hn2[i*2+1]=' ';
	}
	hn2[strlen(h)*2]='\0';
	hostname=[[TextFieldCell alloc] initTextCell:hn2];
	[hostname setEditable:NO];
	[hostname setTextGray:0.333];
	[hostname setBackgroundGray:NX_BLACK];
	[hostname setFont:[Font newFont:"Times-Italic" size:36.0]];
	[hostname calcCellSize:&textFrame.size];
    }

    /* don't blacken at the start */
    blackened=NO;

    /* pick up defaults */
    [self getTimeToMove];
    if (timeToMove > 1800.0) timeToMove=1800.0;
    if (timeToMove < 1.0) timeToMove=1.0;
 
    [self getTimeToBlack];
    if (timeToBlack < 0.0) timeToBlack= -1.0;
    
    /* pick up starting time */
    gettimeofday(&tv,&tz);
    lastMove = startTime=tv.tv_sec;

    return self;
}


- sizeTo:(NXCoord)width :(NXCoord)height
{
	struct timeval tv;
	struct timezone tz;

	[super sizeTo:width :height];

	gettimeofday(&tv,&tz);
	lastMove = startTime = tv.tv_sec;	
	blackened = NO;

	[self moveImage];
	[self moveText];
	[self display];

	return self;
}


- setImageFile:sender
{
    char		str[MAXPATHLEN+1];
    const char *const 	fileTypes[5]={ "ps ", "eps", "tiff", "tif", NULL };
    OpenPanel		*openpanel=[[OpenPanel new] allowMultipleFiles:NO];
    
    if (sender != imageFileField)
    {
	[openpanel chooseDirectories:NO];
    
	if ([openpanel runModalForTypes:fileTypes]) 
	    strcpy(str, [openpanel filename]);
	else strcpy(str, (imageFile ? imageFile : ""));
    } /* if */
    else strcpy(str, [sender stringValue]);

    [imageFileField setStringValue:imageFile];

    NXWriteDefault("BackSpace", "MoveImageFile", str);
    [self getImageFile];
    
    return self;
} /* setImageFile: */


- (const char*)getImageFile
{
    const char *ptr;
    
    ptr = NXGetDefaultValue("BackSpace", "MoveImageFile");
    
    if (image)
	image = [image free];
    
    if (ptr && (strcmp(ptr, "") != 0))
    {
	str_free(imageFile);
	imageFile = str_copy(ptr);
    
	image=[[NXImage alloc] initFromFile:imageFile];
	[image getSize:&imageFrame.size];
	
	if (image && [image lockFocus])
	{
	    [image unlockFocus];
	    [imageFileField setStringValue:imageFile];
	    return imageFile;
	} /* if */
	else image = [image free];
    }
    
    if ((imageFile == NULL) || !image)
    {
	char 	path[MAXPATHLEN+1];
	
	sprintf(path,"%s/NextImage.tiff",
		[(BSThinker()) moduleDirectory:"MoveBlack"]);
	image=[[NXImage alloc] initFromFile:path];
	[image getSize:&imageFrame.size];
	[imageFileField setStringValue:path];
	
	return path;
    } 

    return NULL;
} /* ()getImageFile */


- setTimeToMove:sender
{
    char	str[100];
    
    timeToMove = [sender floatValue];
    [moveTimeSlider setIntValue:timeToMove];
    [moveTimeCell setIntValue:timeToMove];

    sprintf(str,"%d", (int)timeToMove);
    NXWriteDefault("BackSpace", "MoveImageTime", str);
    
    return self;
} /* setTimeToMove: */


- (double)getTimeToMove
{
	const char *ptr;
	float val;

	[moveTimeSlider setMinValue: 1];
	[moveTimeSlider setMaxValue: 300];
	
	ptr = NXGetDefaultValue("BackSpace", "MoveImageTime");
	if (ptr)
	{
	    sscanf(ptr,"%f",&val);
	    if (val >= 1 && val <= 300) timeToMove = val;
	    else timeToMove = 1;
	}
	else timeToMove = 10;

    return timeToMove;
} /* ()getTimeToMove */


- setTimeToBlack:sender
{
    char	str[100];
    
    if ([sender floatValue] > 0)
    {
	timeToBlack = [sender floatValue]*60;
	[blackTimeSlider setIntValue:timeToBlack/60];
	[blackTimeCell setIntValue:timeToBlack/60];
    } /* if */
    else 
    {
	timeToBlack = 0;
	[blackTimeSlider setIntValue:timeToBlack];
	[blackTimeCell setStringValue:"Off"];
    } /* if..else */

    sprintf(str,"%d", (int)timeToBlack);
    NXWriteDefault("BackSpace", "MoveBlackTime", str);
        
    return self;
} /* setTimeToBlack: */


- (double)getTimeToBlack
{
	const char *ptr;
	float val;

	[blackTimeSlider setMinValue: 0];
	[blackTimeSlider setMaxValue: 60];
	
	ptr = NXGetDefaultValue("BackSpace", "MoveBlackTime");
	if (ptr)
	{
	    sscanf(ptr,"%f",&val);
	    if (val >= 1) timeToBlack = val;
	    else timeToBlack = 0;
	}
	else timeToBlack = 0;

    return timeToBlack;
} /* ()getTimeToBlack */


- inspector:sender
{
    char buf[MAXPATHLEN];
	
    if (!inspectorPanel)
    {
	[NXBundle getPath:buf forResource:"MoveBlackView" ofType:"nib" 
		inDirectory:[sender moduleDirectory:"MoveBlack"] withVersion:0];
	[NXApp loadNibFile:buf owner:self withNames:NO];

	[imageFileField setStringValue:imageFile];
	[moveTimeSlider setIntValue:timeToMove];
	[moveTimeCell setIntValue:timeToMove];

	if (timeToBlack > 0)
	{
	    [blackTimeSlider setIntValue:timeToBlack/60];
	    [blackTimeCell setIntValue:timeToBlack/60];
	} /* if */
	else 
	{
	    timeToBlack = 0;
	    [blackTimeSlider setIntValue:timeToBlack];
	    [blackTimeCell setStringValue:"Off"];
	} /* if..else */
    }
    return inspectorPanel;
}


@end
