// ClockView.m
// By Jayson Adams, NeXT Developer Support Team
// You may freely copy, distribute and reuse the code in this example.
// NeXT disclaims any warranty of any kind, expressed or implied, as to its
// fitness for any particular use.

#import <math.h>
#import <appkit/Application.h>
#import <appkit/Slider.h>
#import <appkit/NXImage.h>
#import "ClockView.h"
#import <Date.h>

typedef struct _TimerStruct {
	Date *date;
	ClockView *view;
} TimerStruct, *TimerStructPtr;
static TimerStruct t_timerStruct;
static long t_start,t_now;
static long t_min,t_sec;

#define ABS(x) (x < 0 ? -(x) : (x))
 
void MinuteSecondTimer(DPSTimedEntry teNumber, double now,
	TimerStructPtr ts)
{
	/* Display the current time */
	t_now = [ts->date sysTime];
	
	t_min = (t_now - t_start) / 60;
	t_sec = t_now - t_start - 60 * t_min;
	t_min %= 60;

	[ts->view display];
}

@implementation ClockView


/* instance methods */

- initFrame:(NXRect *)frameRect
{
NXSize oneSize, twoSize;
int i;
char *numberNames[] = {"DigitalZero", "DigitalOne", "DigitalTwo",
    				  "DigitalThree", "DigitalFour", "DigitalFive",
				  "DigitalSix", "DigitalSeven", "DigitalEight",
				  "DigitalNine", ""};
				  
	[super initFrame : frameRect];
	
/* get the images we'll use in drawSelf:: */
	clockImage = [NXImage findImageNamed : "Clock"];
	
	for (i = 0; *numberNames[i]; i++)
			numbers[i] = [NXImage findImageNamed:numberNames[i]];

	colon = [NXImage findImageNamed : "Colon"];
	amImage = [NXImage findImageNamed : "AM"];
	pmImage = [NXImage findImageNamed : "PM"];
	
/* compute the colon's location (it never changes) */
	[numbers[1] getSize : &oneSize];
	[numbers[2] getSize : &twoSize];
	colonPosition_clock.x = oneSize.width + twoSize.width + 4.0;
	colonPosition_clock.y = ceil((bounds.size.height - twoSize.height) / 2.0); 
	/* Center the ':' for the timer */
	colonPosition_timer.x = bounds.size.width / 2.0;
	colonPosition_timer.y = colonPosition_clock.y;

	/* Init the date to the current time */
	dateObj = [[Date alloc] initFromNow];
	/* Check my time to see if it is AM or PM */
	if ([dateObj hours] < 12)
		meridianImage = amImage;
	else
		meridianImage = pmImage;

	return self;
}

/* Date initialization methods */
- setDate : (short) d : (short) m : (short) y
{
	if([dateObj initFromDate : d : m : y] == nil)
		return nil;
	/* Check my time to see if it is AM or PM */
	if ([dateObj hours] < 12)
		meridianImage = amImage;
	else
		meridianImage = pmImage;
	[self display];
	return self;
}

- setTime : (short) hr : (short) min : (short) sec
{
	if([dateObj setTime : hr : min : sec] == nil)
		return nil;
	/* Check my time to see if it is AM or PM */
	if ([dateObj hours] < 12)
		meridianImage = amImage;
	else
		meridianImage = pmImage;
	[self display];
	return self;
}

- now
{
	if([dateObj initFromNow] == nil)
		return nil;
	[self display];
	return self;
}

- startMinSecTimer : sender
{
	t_start = [dateObj sysTime];
	t_timerStruct.date = dateObj;
	t_timerStruct.view = self;
	/* Start the proc which updates the display every second */
	min_sec_timer = DPSAddTimedEntry(1.0, MinuteSecondTimer, &t_timerStruct,
		NX_MODALRESPTHRESHOLD);
	timerActive = YES;
	[self display];

	return self;
}

- endTimer : sender
{
	DPSRemoveTimedEntry(min_sec_timer);
	timerActive = NO;
	return self;
}

- drawSelf:(NXRect *)rects :(int)count
{
NXPoint	position;
NXSize	size, hoursTensSize = {0.0, 0.0}, hoursUnitsSize;
int t0,t1;

	/* Set the hour & minute (minute & second) positions
		depending on the timer state */
	if(timerActive == YES)
	{
		t0 = t_min;
		t1 = t_sec;
	}
	else
	{
		t0 = [dateObj hours];
		if(t0 > 12)
			t0 %= 12;
		t1 = [dateObj minutes];
	}

/* draw the background */
	[clockImage composite:NX_COPY toPoint:&(bounds.origin)];

/* AM or PM */
	if(timerActive == NO)
	{
		[meridianImage getSize:&size];
		position.x = bounds.size.width - size.width - 4.0;
		position.y = floor((bounds.size.height - size.height) / 2.0);
		[meridianImage composite:NX_COPY toPoint:&position];
	}

/* compute starting position for all drawing;  the colon is stationary */
	if(timerActive == NO)
		position = colonPosition_clock;
	else
		position = colonPosition_timer;

	if (t0 / 10)
	{
		[numbers[t0 / 10] getSize:&hoursTensSize];
	}
	[numbers[t0 % 10] getSize:&hoursUnitsSize];
	position.x -= hoursTensSize.width + hoursUnitsSize.width;
	
/* draw the hours tens digit */
	if (t0 / 10)
	{
		[numbers[t0 / 10] composite:NX_COPY toPoint:&position];
		position.x += hoursTensSize.width;
	}
	
/* hours units digit */
	[numbers[t0 % 10] composite:NX_COPY toPoint:&position];
	position.x += hoursUnitsSize.width;
	
/* draw the colon */  
	[[colon getSize:&size] composite:NX_COPY toPoint:&position];
	position.x += size.width;
	
/* tens digit of minutes */
	[[numbers[t1 / 10] getSize:&size] composite:NX_COPY
								toPoint:&position];
	position.x += size.width;
	
/* minutes units digit */
	[numbers[t1 % 10] composite:NX_COPY toPoint:&position];
	
	return self;
}

@end
