//----------------------------------------------------------------------------------------------------
//
//	FoneController
//
//	Inherits From:		Object
//
//	Declared In:		FoneController.h
//
//	Disclaimer
//
//		You may freely copy, distribute and reuse this software and its
//		associated documentation. I disclaim any warranty of any kind, 
//		expressed or implied, as to its fitness for any particular use.
//
//----------------------------------------------------------------------------------------------------
#import "FoneController.h"
#import <dpsclient/dpsNeXT.h>


#define	_PATTERN_END	13

static int	animationPattern[_PATTERN_END] = {0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0};
static int	patternIterator;
static int	loopCount;


@implementation FoneController

//---------------------------------------------------------------------------------------------------------
//	Private Methods
//---------------------------------------------------------------------------------------------------------
- (NXPoint) _centerPoint: anImage
{
	//  You must center the composited image within the contentView of the
	//  appIcon window.
	
	NXSize	appTileSize;
	NXSize	imageSize;
	NXPoint	centerPoint;

	[appTile getSize: &appTileSize];
	[anImage getSize: &imageSize];
	
	if  ( imageSize.width < appTileSize.width ) 
		centerPoint.x += (appTileSize.width - imageSize.width ) / 2.0;
	
	if  ( imageSize.height < appTileSize.height ) 
		centerPoint.y += (appTileSize.height - imageSize.height ) / 2.0;
		
	return centerPoint;
}


- _display: anImage
{
	//  NXAppTile is composited first at 0,0 of the icon window's content view 
	//  (this is required in order to maintain the NeXT icon look).  'anImage' is 
	//  then composited at center (centering is also a requirement).

	NXPoint	contentViewOrigin = { 0.0, 0.0 };
	NXPoint	centerPoint = [self _centerPoint: anImage];
	
	[appIconContentView lockFocus];
	[appTile composite:NX_SOVER toPoint:&contentViewOrigin];
	[anImage composite:NX_SOVER toPoint:&centerPoint];
	[appIconContentView unlockFocus];
	[appIconContentView display];

	return self;
}


- _animate
{
	//  This contains logic for the icon animation (image sequencing).  Three
	//  images are used (contained in imageList).  The animationPattern
	//  provides an index into that list, giving us the right image at the right
	//  time.  The icon will 'ring' twice, and leave the phone off-hook to indicate
	//  unanswered calls.
	
	static int	offset;
	
	[self _display: [imageList objectAt: animationPattern[patternIterator++]]];
	
	if (patternIterator == (_PATTERN_END - offset))
		{
		[self removeTimedEntry];
		patternIterator = 0;
		loopCount++;
		if (loopCount < 2)
			{
			offset = 1;
			[self perform: @selector(ring:) with:self afterDelay:500 cancelPrevious:YES];
			}
		else
			{
			loopCount = offset = 0;
			[self _display: [imageList objectAt: 1]];
			}			
		}
		
	return self;
}


//---------------------------------------------------------------------------------------------------------
//	DPS Timed Entry Methods
//---------------------------------------------------------------------------------------------------------
void Animate (timedEntry, now, self)
	DPSTimedEntry	timedEntry;
	double			now;
	id				self;
{
	//  This is the callback function for the DPS Timed Entry.  It in turn 
	//  calls our _animate method.  DPS Timed Entries require functions
	//  not methods, as callbacks.
	
	[ (id) self  _animate];
}


- removeTimedEntry
{
	if (timedEntry)  
		{
		DPSRemoveTimedEntry (timedEntry);
		timedEntry = 0;
		}
		
	return self;
}


//---------------------------------------------------------------------------------------------------------
//	Application Delegate Method
//---------------------------------------------------------------------------------------------------------
- appDidInit: sender
{
	//  App has inited.  We can now get to the things we need to initialize.
	//  Create the imageList (the list of images used for animation).  Get the 
	//  standard NXAppTile, icon window content view, and move the icon 
	//  somewhere obvious.
	
	imageList = [[List alloc] init];
	[imageList insertObject: [NXImage findImageNamed: "Phone0"] at: 0];
	[imageList insertObject: [NXImage findImageNamed: "Phone1"] at: 1];
	[imageList insertObject: [NXImage findImageNamed: "Phone2"] at: 2];

	appTile = [NXImage findImageNamed: "NXAppTile"];
	appIconContentView = [[NXApp appIcon] contentView];
	[[NXApp appIcon] moveTo: 540 :355];

	return self;
}
	
	
//---------------------------------------------------------------------------------------------------------
//	Action Methods
//---------------------------------------------------------------------------------------------------------
- ring: sender
{
	//  'Ring' and add a timed entry to begin the animation sequence...
	
	if (timedEntry)  return self;

	[[[Sound findSoundFor: "Ring"] play: nil] free];
    	timedEntry = DPSAddTimedEntry(0.2, Animate, (void*)self, NX_MODALRESPTHRESHOLD);

    	return self;
}


- answer: sender
{
	//  Indicate 'Answer' by placing the fone on-hook.  Do necessary housekeeping.
	
	[self removeTimedEntry];
	[[[Sound findSoundFor: "Ring"] stop: nil] free];
	[self _display: [imageList objectAt: 0]];
	patternIterator = 0;
	loopCount = 0;
	return self;
}


@end
