/* BBImageAnimator.m				 
 *
 * This produces some nice Animatoins. Switching the images inside a
 * button object.
 *
 * For interface-info see the header file. The comments in this file mostly
 * cover only the real implementation details.
 *
 * Written by: 		Thomas Engel
 * Created:    		28.10.1993 (Copyleft)
 * Last modified: 	07.05.1994
 */

#import "BBImageAnimator.h"

// Here is a little C-Funktion. We need this one for timed entry handling.

void handler( DPSTimedEntry teNumber, double now, void *userData )
{
	id animator = (id)userData;
	[animator switchToNextFrame];
}

@implementation BBImageAnimator

- setDelegate:anObject
{
	delegate = anObject;
	return self;
}

- setTargetButton:aButton
{
	targetButton = aButton;
	return self;
}

- setBounceSettingField:aTextField;
{
	bounceSettingField = aTextField;
	bounceAnimation = [bounceSettingField intValue];
	return self;
}

- setFrameCountSettingField:aTextField;
{
	frameCountSettingField = aTextField;
	frameCount = [frameCountSettingField intValue];
	return self;	
}

- setSpeedSettingField:aTextField;
{
	speedSettingField = aTextField;
	frameDelay = 1 / [speedSettingField doubleValue];
	return self;
}

- startAnimation:sender
{
	// First check if the settings are useful. If not do nothing!
	// Create a timed entry and set all default values. Even the frame
	// numbers are 1....frameCount we set it to 0. This is because the
	// switch method does the counting and switching and at the moment
	// we are not showing any image...just the basic number 0. OK ?

	if( !targetButton ||
	    !sourceImageMatrix ||
		frameCount < 1 ||
		frameDelay < 0.0001 ||
		frameDelay > 20 ) return self;

	currentFrame = 0;
	bouncing = NO;
	
	animateTE = DPSAddTimedEntry( frameDelay, (DPSTimedEntryProc)handler,
								  self, NX_BASETHRESHOLD );
	return self;
}

- stopAnimation
{
	// We only remove the timed entry. This object will not restore the
	// original icon!
	
	if( animateTE )
	{	
		DPSRemoveTimedEntry( animateTE );
		animateTE = 0;
		
		if( [delegate respondsTo:@selector(animationDidStop:)] )
			[delegate animationDidStop:self];
	}
	return self;
}

- switchToNextFrame
{
	BOOL	lastFrame = NO;
	id		sourceButton;
	
	// Whats the new frame ? Or did we already show the last one ?
	// First calculate the next logical image and then check for end of anim.
	
	if( bouncing )
			currentFrame--;
	else 	currentFrame++;
	
	if( currentFrame > frameCount )
	{
		if( bounceAnimation )
		{
			bouncing = YES;
			currentFrame = frameCount-1;
		}
		else lastFrame = YES;
	}	

	if( currentFrame < 1 ) lastFrame = YES; 
	
	// If there is a image to show...lets try it:
	
	if( !lastFrame )
	{
		sourceButton = [sourceImageMatrix findCellWithTag:currentFrame];
		if( sourceButton )	
			[targetButton setImage:[sourceButton image]];
	}
	// Seems like we did show the last image during the last timed entry.
	// So stop right now. With this delayed stop we ensure that the last image
	// of our animation is also displayed for at least frameDelay seconds.
	
	else [self stopAnimation];
	
	return self;
}

@end

/*
 * History: 07.05.94 Changed some names .
 *
 *			19.01.94 Removed the [image display] call because not needed.
 *
 *
 * Bugs: - Not really
 */