//
// Copyright 1995 (c) Icebox Software Manufactory, Inc.  All Rights Reserved.
//


#import "LineView.h"

#define STEPFACTOR	( 12 )
#define BORDER	( 3 )

@implementation LineView

float frandom();
float randBetween(float a, float b);

void moveIt (DPSTimedEntry te, double now, void *self)
{
	[(id)self _moveIt]; 
	// do not return a value
}


- _moveIt
{
	int		index;

	// Move the line by moving the point components
	// by the value in each delta.
	pt1.x += dx1;
	pt1.y += dy1;
	pt2.x += dx2;
	pt2.y += dy2;

	// If the point has move out of the view bounds, then limit
	// the sucker and change the direction and assign a new delta value.
	if (pt1.x > NX_WIDTH(&bounds) || pt1.x < 0.0) {
		dx1 = randBetween(1.0, NX_WIDTH(&bounds) / STEPFACTOR) * ((dx1 > 0.0) ? -1 : 1);
		pt1.x = ((pt1.x < 0.0) ? 0.0 : NX_WIDTH(&bounds));
	}
	if (pt1.y > NX_HEIGHT(&bounds) || pt1.y < 0.0) {
		dy1 = randBetween(1.0, NX_HEIGHT(&bounds) / STEPFACTOR) * ((dy1 > 0.0) ? -1 : 1);
		pt1.y = ((pt1.y < 0.0) ? 0.0 : NX_HEIGHT(&bounds));
	}
	if (pt2.x > NX_WIDTH(&bounds) || pt2.x < 0.0) {
		dx2 = randBetween(1.0, NX_WIDTH(&bounds) / STEPFACTOR) * ((dx2 > 0.0) ? -1 : 1);
		pt2.x = ((pt2.x < 0.0) ? 0.0 : NX_WIDTH(&bounds));
	}
	if (pt2.y > NX_HEIGHT(&bounds) || pt2.y < 0.0) {
		dy2 = randBetween(1.0, NX_HEIGHT(&bounds) / STEPFACTOR) * ((dy2 > 0.0) ? -1 : 1);
		pt2.y = ((pt2.y < 0.0) ? 0.0 : NX_HEIGHT(&bounds));
	}

	// Now move the lines in the array down ...
	for ( index = MAXLINES - 1; index >= 1; index-- ) {
		lines[index].begin = lines[index - 1].begin;
		lines[index].end = lines[index - 1].end;
	}
	// ... and then fill in the 'new' line with our calculated values.
	lines[0].begin = pt1;
	lines[0].end = pt2;

	[self display];

	return ( self );
}


- initFrame:(const NXRect *)newFrame
{
	// Make sure this view's other ivars are set up.
	[super initFrame:newFrame];

	// Randomize the point locations.
	pt1.x = randBetween(BORDER, NX_WIDTH(newFrame));
	pt1.y = randBetween(BORDER, NX_HEIGHT(newFrame));
	pt2.x = randBetween(BORDER, NX_WIDTH(newFrame));
	pt2.y = randBetween(BORDER, NX_HEIGHT(newFrame));

	// Randomize the delta values, and 
	dx1 = randBetween(BORDER, NX_WIDTH(newFrame) / STEPFACTOR) * ((randBetween(-1.0, 1.0) >= 0) ? -1 : 1);
	dy1 = randBetween(BORDER, NX_HEIGHT(newFrame) / STEPFACTOR) * ((randBetween(-1.0, 1.0) >= 0) ? -1 : 1);
	dx2 = randBetween(BORDER, NX_WIDTH(newFrame) / STEPFACTOR) * ((randBetween(-1.0, 1.0) >= 0) ? -1 : 1);
	dy2 = randBetween(BORDER, NX_HEIGHT(newFrame) / STEPFACTOR) * ((randBetween(-1.0, 1.0) >= 0) ? -1 : 1);

	return ( self );
}


- drawSelf:(const NXRect *)rects :(int)rectCount
{
	int		index;

	// Erase the backing with the backing color ...
	(void) PSsetrgbcolor(backingRed, backingGreen, backingBlue);
	(void) NXRectFill(rects);

	// ... and then draw the line(s) with the line color.
	(void) PSsetrgbcolor(lineRed, lineGreen, lineBlue);
	(void) PSsetlinewidth(lineWidth);
	for ( index = numberOfLines - 1; index >= 0; index-- ) {
		(void) PSmoveto(lines[index].begin.x, lines[index].begin.y);
		(void) PSlineto(lines[index].end.x, lines[index].end.y);
	}
	(void) PSstroke();

	return ( self );
}


- clear
{
	(void) PSsetrgbcolor(backingRed, backingGreen, backingBlue);
	(void) NXRectFill(&bounds);

	return ( self );
}


- start
{
	if ( myTE == NULL ) {
		myTE = DPSAddTimedEntry(speed, &moveIt, self, NX_BASETHRESHOLD);
	}

	return ( self );
}


- stop
{
	if ( myTE ) {
		DPSRemoveTimedEntry(myTE);
		myTE = (DPSTimedEntry)0;
	}

	return ( self );
}


- lineColor:(NXColor)newColor
{
	(void) NXConvertColorToRGBA(newColor, &lineRed, &lineGreen, &lineBlue, &lineAlpha);
	return ( self );
}


- backingColor:(NXColor)newColor
{
	(void) NXConvertColorToRGBA(newColor, &backingRed, &backingGreen, &backingBlue, &backingAlpha);
	return ( self );
}


- lineWidth:(float)newLineWidth
{
	lineWidth = newLineWidth;
	return ( self );
}


- speed:(float)newSpeed
{
	speed = newSpeed;

	[self stop];
	[self start];

	return ( self );
}


- numberOfLines:(float)newNumberOfLines
{
	numberOfLines = newNumberOfLines;
	return ( self );
}


// This should return a float between 0 and 1.
// Stolen from NeXT and the Thinker.m class by Sam Streeper.
///
float frandom()
{
	float val = (random() & 0x7fffffff);
	val /= 0x7fffffff;
	return val;
}


float randBetween(float a, float b)
{
	float val, scale, t;

	if (a > b)
	{	t = a; a = b; b = t;
	}
	
	scale = (b-a);
	val = scale * frandom();
	return (a + val);
}

@end
