//----------------------------------------------------------------------------------------------------
//
//	DigitalClock
//
//	Inherits From:		Clock
//
//	Declared In:		DigitalClock.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 "DigitalClock.h"


#define TIMESTRING_OFFSET		12.0
#define DATESTRING_OFFSET		16.0
#define YEARSTRING_OFFSET		26.0

#define DIAGONAL_CONSTANT		0.707

static const char*  DAYS [7] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
static const char*  MONTHS [12] = 
{ "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };


@implementation DigitalClock

//----------------------------------------------------------------------------------------------------
//	Private Methods
//----------------------------------------------------------------------------------------------------
- (NXPoint) _locationForString: (STR)aString usingFont: aFont
{
	NXPoint	stringLocation;
	float		stringHeight = [aFont pointSize];
	float		stringWidth = [aFont getWidthOf:aString];
	
	if (style == DIGITAL_STYLE_DIAGONAL) 
		stringWidth = (stringWidth * DIAGONAL_CONSTANT) - ([aFont pointSize] / 2.0) +2;
	stringLocation.x = ((NX_WIDTH(&bounds) - stringWidth) / 2.0);

	if (style == DIGITAL_STYLE_DIAGONAL) stringHeight = -(stringWidth + [aFont pointSize] - 2);
	stringLocation.y = ((NX_HEIGHT(&bounds) / 2.0) + (stringHeight / 2.0));

	return stringLocation;
}


- _updateFont
{
	//  Called when change to an instance variable that would effect
	//  which font should be used.

 	if (timeFont) [timeFont free];
 	if (dateFont) [dateFont free];
 	if (yearFont) [yearFont free];

	switch ([self style])
		{
		case DIGITAL_STYLE_DIAGONAL:
   			timeFont = [Font newFont:"Times-Roman" size:([self wantsSeconds] ? 20 : 30) 
				style:0 matrix:NX_IDENTITYMATRIX];
			break;

		case DIGITAL_STYLE_STANDARD:
		default:
    			timeFont = [Font newFont:"Times-Roman" size:18 style:0 				matrix:NX_IDENTITYMATRIX];
    			dateFont = [Font newFont:"Helvetica" size:8 style:0 matrix:NX_IDENTITYMATRIX];
    			yearFont = [Font newFont:"Helvetica" size:9 style:0 matrix:NX_IDENTITYMATRIX];
			break;
		}
			
	return self;
}

	
//----------------------------------------------------------------------------------------------------
//	Initialization and Freeing
//----------------------------------------------------------------------------------------------------
- initFrame: (const NXRect *)aRect
{
	//  Give default characteristics.  Fix size to 64 x 64. 
	
	NXRect	frameRect;
	NXSetRect (&frameRect, NX_X(aRect), NX_Y(aRect), 64.0, 64.0);
	[super initFrame:&frameRect];
	[self style: DIGITAL_STYLE_STANDARD];
	[self timeColor: NX_COLORBLACK];
	[self dateColor: NX_COLORRED];
	[self wantsYear: NO];
	return self;
}


- free
{
 	if (timeFont) [timeFont free];
 	if (dateFont) [dateFont free];
 	if (yearFont) [yearFont free];
	return [super free];
}


//----------------------------------------------------------------------------------------------------
//	Setting Style
//-----------------------------------------------------------------------------------------------------
- style: (int) aStyle
{
	style = aStyle;
	[self _updateFont];
	[self update];
	return self;
}


- (int) style
{
	return style;
}


//----------------------------------------------------------------------------------------------------
//	Enabling Year Display
//-----------------------------------------------------------------------------------------------------
- wantsYear: (BOOL) aFlag
{
	wantsYear = aFlag;
	[self update];
	return self;
}


- (BOOL) wantsYear
{
	return wantsYear;
}



//----------------------------------------------------------------------------------------------------
//	Accessing Display Colors
//----------------------------------------------------------------------------------------------------
- timeColor: (NXColor) aColor
{
	timeColor = aColor;
	[self update];
	return self;
}


- dateColor: (NXColor) aColor;
{
	dateColor = aColor;
	[self update];
	return self;
}


- (NXColor) timeColor
{
	return timeColor;
}


- (NXColor) dateColor;
{
	return dateColor;
}


//----------------------------------------------------------------------------------------------------
//	Action Methods
//----------------------------------------------------------------------------------------------------
- takeClockStyleFlagFrom :sender
{
	if ([sender isKindOf: [Matrix class]])
		sender = [sender selectedCell];
		
	if ([sender respondsTo: @selector (state)])
		[self style: [sender state]];
		
	return self;
}


- takeWantsYearFlagFrom :sender
{
	if ([sender isKindOf: [Matrix class]])
		sender = [sender selectedCell];
		
	if ([sender respondsTo: @selector (state)])
		[self wantsYear: [sender state]];
		
	return self;
}


- takeTimeColorFrom: sender
{
	if ([sender respondsTo: @selector (color)]) [self timeColor: [sender color]];
	return self;
}


- takeDateColorFrom: sender
{
	if ([sender respondsTo: @selector (color)]) [self dateColor: [sender color]];
	return self;
}


//----------------------------------------------------------------------------------------------------
//	Draw Methods
//-----------------------------------------------------------------------------------------------------
- drawClockFace
{
	return self;
}


- drawTime
{
    	int 		hour = HOUR(displayTimeAndDate);
    	char 	stringBuffer[10];
	NXPoint	stringLocation;
	
	if (! flags.wantsMilitaryTime)
		{
    		hour = fmod (HOUR(displayTimeAndDate),12);
    		if (! hour) hour = 12;
		}
		
	if (flags.wantsMilitaryTime)
		sprintf (stringBuffer, "%.2d:%.2d", hour, MINUTE(displayTimeAndDate));
	else
		sprintf (stringBuffer, "%d:%.2d", hour, MINUTE(displayTimeAndDate));

   	 if (flags.wantsSeconds)
        	sprintf (stringBuffer,"%s:%.2d", stringBuffer, SECOND(displayTimeAndDate));

	stringLocation = [self _locationForString:stringBuffer usingFont: timeFont];

    	[timeFont set];
	NXSetColor (timeColor);
	
	if (style == DIGITAL_STYLE_DIAGONAL)
		{
		PSmoveto (stringLocation.x, (stringLocation.y));
	    	PSrotate (45.0);
		}
	else
		PSmoveto (stringLocation.x, (stringLocation.y - TIMESTRING_OFFSET));

	PSshow (stringBuffer);

	return self;
}


- drawDate
{
    	char  	stringBuffer[15];
    	NXPoint	stringLocation;
		
	if ( (flags.wantsDate == NO) || (style == DIGITAL_STYLE_DIAGONAL) ) return self;

	sprintf (stringBuffer,"%s %s %d", 
		DAYS[WEEKDAY(displayTimeAndDate)],
		MONTHS[MONTH(displayTimeAndDate)],
		DAY(displayTimeAndDate));

	stringLocation = [self _locationForString:stringBuffer usingFont: dateFont];

    	[dateFont set];
	NXSetColor (dateColor);
	PSmoveto (stringLocation.x, (stringLocation.y - DATESTRING_OFFSET));
	PSshow (stringBuffer);

	if ( ! [self wantsYear]) return self;

	sprintf (stringBuffer,"%.4d", (1900 + YEAR(displayTimeAndDate)));
	stringLocation = [self _locationForString:stringBuffer usingFont: yearFont];
    	[yearFont set];
	PSmoveto (stringLocation.x, (stringLocation.y - YEARSTRING_OFFSET));
	PSshow (stringBuffer);

	return self;
}


//----------------------------------------------------------------------------------------------------
//	Archiving Methods
//----------------------------------------------------------------------------------------------------
- read: (NXTypedStream*) stream
{
	[super read: stream];
	NXReadTypes (stream, "@@@ic", &timeFont, &dateFont, &yearFont, &style, &wantsYear);
	timeColor = NXReadColor (stream);
	dateColor = NXReadColor (stream);
	return self;
}


- write: (NXTypedStream*) stream
{
	[super write: stream];
	NXWriteTypes (stream, "@@@ic", &timeFont, &dateFont, &yearFont, &style, &wantsYear);
	NXWriteColor (stream, timeColor);
	NXWriteColor (stream, dateColor);
	return self;
}


//----------------------------------------------------------------------------------------------------
//	Superclass Overrides
//-----------------------------------------------------------------------------------------------------
- wantsSeconds: (BOOL) aFlag
{
	flags.wantsSeconds = aFlag;
	[self _updateFont];
	[self update];
	return self;
}


- clockFace: (NXImage*) anImage
{
	return self;
}


//----------------------------------------------------------------------------------------------------
//	IB Methods
//----------------------------------------------------------------------------------------------------
- getMinSize:(NXSize *)minSize maxSize:(NXSize *)maxSize from:(int)where
{
	//  Constrains resize within IB.
	
	minSize->width = maxSize->width = 64.0;
	minSize->height = maxSize->height = 64.0;
	return self;
}


- (const char*) getInspectorClassName
{
	//  Returns the name of the class responsible for managing custom 
	//  IB Attributes inspection.
		
	return "DigitalClockInspector";
}


@end