//
//	MiscClockView.m -- a simple view class for displaying date/time
//		Written by Scott Anguish Copyright (c) 1993 by Scott Anguish.
//				Version 1.2.  All rights reserved.
//
//		This notice may not be removed from this source code.
//
//	This object is included in the MiscKit by permission from the author
//	and its use is governed by the MiscKit license, found in the file
//	"LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
//	for a list of all applicable permissions and restrictions.
//	
//	Aug 30, 1996 Converted to OpenStep by Jeremy Bettis <jeremy@hksys.com>

#import <sys/time.h>	

#import "MiscClockView.h"

#import <AppKit/NSImage.h>
#import <AppKit/psopsOpenStep.h>

@interface MiscClockView(private)
- (void)_setUp;
@end

@implementation MiscClockView


#define Misc_BuildRect(a, b, c, d, e) a = NSMakeRect((b), (c), (d), (e));


+ (void)initialize
{
	[MiscClockView setVersion:4];
	return;
}

- (void)_setUp
{
	NSSize	oneSize, twoSize;

	if (theImage) return; // don't want to leak!

	theImage = [[NSImage alloc] initByReferencingFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"MiscClockStuff" ofType:@"tiff"]];


 /* Yes this is ugly, and there is alot of extra junk in here, but to a
  * large degree at this point I didn't know where else to store these
  * co-ordinates where I wouldn't loose them! */

	Misc_BuildRect (imageA, 65.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (imageP, 74.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (DigitalNumbers[1], 89.0, 0.0, 4.0, 11.0);
	Misc_BuildRect (DigitalNumbers[2], 93.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (DigitalNumbers[3], 104.0, 0.0, 8.0, 11.0);
	Misc_BuildRect (DigitalNumbers[4], 112.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (DigitalNumbers[5], 121.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (DigitalNumbers[6], 130.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (DigitalNumbers[7], 140.0, 0.0, 8.0, 11.0);
	Misc_BuildRect (DigitalNumbers[8], 148.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (DigitalNumbers[9], 157.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (DigitalNumbers[0], 166.0, 0.0, 9.0, 11.0);
	Misc_BuildRect (imageColon, 175.0, 0.0, 3.0, 11.0);
	Misc_BuildRect (imageAM, 179.0, 0.0, 12.0, 6.0);
	Misc_BuildRect (imagePM, 192.0, 0.0, 11.0, 6.0);

	Misc_BuildRect (DayNames[1], 0, 65, 19, 5);
	Misc_BuildRect (DayNames[2], 0, 59, 19, 5);
	Misc_BuildRect (DayNames[3], 0, 53, 19, 5);
	Misc_BuildRect (DayNames[4], 0, 47, 19, 5);
	Misc_BuildRect (DayNames[5], 0, 41, 19, 5);
	Misc_BuildRect (DayNames[6], 0, 35, 19, 5);
	Misc_BuildRect (DayNames[0], 0, 29, 19, 5);

	Misc_BuildRect (MonthNames[0], 40, 66, 22, 5);
	Misc_BuildRect (MonthNames[1], 40, 60, 22, 5);
	Misc_BuildRect (MonthNames[2], 40, 54, 22, 5);
	Misc_BuildRect (MonthNames[3], 40, 48, 22, 5);
	Misc_BuildRect (MonthNames[4], 40, 42, 22, 5);
	Misc_BuildRect (MonthNames[5], 40, 36, 22, 5);
	Misc_BuildRect (MonthNames[6], 40, 30, 22, 5);
	Misc_BuildRect (MonthNames[7], 40, 24, 22, 5);
	Misc_BuildRect (MonthNames[8], 40, 18, 22, 5);
	Misc_BuildRect (MonthNames[9], 40, 12, 22, 5);
	Misc_BuildRect (MonthNames[10], 40, 6, 22, 5);
	Misc_BuildRect (MonthNames[11], 40, 0, 22, 5);

	Misc_BuildRect (DateNumbers[0], 172.0, 14.0, 10.0, 17.0);
	Misc_BuildRect (DateNumbers[1], 65.0, 14.0, 8.0, 17.0);
	Misc_BuildRect (DateNumbers[2], 76.0, 14.0, 10.0, 17.0);
	Misc_BuildRect (DateNumbers[3], 88.0, 14.0, 9.0, 17.0);
	Misc_BuildRect (DateNumbers[4], 100.0, 14.0, 10.0, 17.0);
	Misc_BuildRect (DateNumbers[5], 112.0, 14.0, 10.0, 17.0);
	Misc_BuildRect (DateNumbers[6], 124.0, 14.0, 10.0, 17.0);
	Misc_BuildRect (DateNumbers[7], 136.0, 14.0, 10.0, 17.0);
	Misc_BuildRect (DateNumbers[8], 148.0, 14.0, 10.0, 17.0);
	Misc_BuildRect (DateNumbers[9], 160.0, 14.0, 10.0, 17.0);

	Misc_BuildRect (YearNumbers[0], 12.0, 8.0, 6.0, 5.0);
	Misc_BuildRect (YearNumbers[1], 0.0, 20.0, 2.0, 5.0);
	Misc_BuildRect (YearNumbers[2], 2.0, 20.0, 5.0, 5.0);
	Misc_BuildRect (YearNumbers[3], 7.0, 20.0, 5.0, 5.0);
	Misc_BuildRect (YearNumbers[4], 12.0, 20.0, 5.0, 5.0);
	Misc_BuildRect (YearNumbers[5], 0.0, 14.0, 5.0, 5.0);
	Misc_BuildRect (YearNumbers[6], 5.0, 14.0, 6.0, 5.0);
	Misc_BuildRect (YearNumbers[7], 11.0, 14.0, 5.0, 5.0);
	Misc_BuildRect (YearNumbers[8], 0.0, 8.0, 6.0, 5.0);
	Misc_BuildRect (YearNumbers[9], 6.0, 8.0, 6.0, 5.0);
	Misc_BuildRect (YearColon, 18.0, 25.0, 1.0, 5.0);

	Misc_BuildRect (clockbase, 64, 72, 64, 64);

	oneSize = DigitalNumbers[1].size;
	twoSize = DigitalNumbers[2].size;
	colonPosition.x = oneSize.width + twoSize.width + 7.0;

	timedEntry = 0;
	if (keepingTime)
	{
		[self startClock:self];
	}
}


- initWithFrame:(NSRect)frameRect
{

    [super initWithFrame:frameRect];
    hidden=NO;
    keepingTime=NO;
    [self _setUp];
    return self;

}

- (void)sizeToFit
{
    [self setFrameSize:NSMakeSize(64,75)];
}

- (void)drawRect:(NSRect)rect
{
    NSPoint	imageOrigin;
    NSSize	size, theSize, tensSize = {0.0, 0.0}, onesSize, twoSize;
    NSRect	imageAyear, imageByear, imageCyear, imageDyear;
    float	width, widthA, widthB, widthC;
    float	imageAdjust;
    int		currentYear, hrs;

    if (hidden) {
        PSsetgray(NSLightGray);
        NSRectFill([self bounds]);
        }

    onesSize = DigitalNumbers[1].size;
    twoSize = DigitalNumbers[2].size;

    if (!militaryTime)
        colonPosition.x = onesSize.width + twoSize.width + 7.0;
    else
        colonPosition.x = 30;

    if (showYear)
        {
        imageAdjust = 5;
        colonPosition.y = 51;
        }
    else
        {
        imageAdjust = 0;
        colonPosition.y = 46;
        }


    imageOrigin.x = 0;
    imageOrigin.y = 0 + imageAdjust;	//(0)

    [theImage compositeToPoint:imageOrigin fromRect:clockbase operation:NSCompositeCopy];


    if (militaryTime)
        {
        hrs = hours;
        }
    else
        {
        hrs = hours % 12;
        if (!hrs)	hrs = 12;
        }

    size = imageAM.size;
    imageOrigin.x = 44;
    imageOrigin.y = 48 + imageAdjust;	//(48)
    if (!militaryTime)
        {
        if (meridian)
            {
            imageOrigin.x = 45;
            [theImage compositeToPoint:imageOrigin fromRect:imagePM operation:NSCompositeCopy];
            }
        else
            [theImage compositeToPoint:imageOrigin fromRect:imageAM operation:NSCompositeCopy];
        }

    imageOrigin = colonPosition;
    if (hrs / 10 || militaryTime)
        tensSize = DigitalNumbers[hrs / 10].size;


    onesSize = DigitalNumbers[hrs % 10].size;
    imageOrigin.x -= tensSize.width + onesSize.width;

    if (hrs / 10 || militaryTime)
        {
        [theImage compositeToPoint:imageOrigin fromRect:DigitalNumbers[hrs / 10] operation:NSCompositeCopy];
        imageOrigin.x += tensSize.width;
        }

    [theImage compositeToPoint:imageOrigin fromRect:DigitalNumbers[hrs % 10] operation:NSCompositeCopy];
    imageOrigin.x += onesSize.width;

    size = imageColon.size;
    [theImage compositeToPoint:imageOrigin fromRect:imageColon operation:NSCompositeCopy];
    imageOrigin.x += size.width;

    size = DigitalNumbers[minutes / 10].size;
    [theImage compositeToPoint:imageOrigin fromRect:DigitalNumbers[minutes / 10] operation:NSCompositeCopy];
    imageOrigin.x += size.width;
    [theImage compositeToPoint:imageOrigin fromRect:DigitalNumbers[minutes % 10] operation:NSCompositeCopy];

    imageOrigin.x = 21;
    imageOrigin.y = 34 + imageAdjust;	//(34)
    [theImage compositeToPoint:imageOrigin fromRect:DayNames[weekday] operation:NSCompositeCopy];

    imageOrigin.x = 19;
    imageOrigin.y = 9 + imageAdjust;	//(9)
    [theImage compositeToPoint:imageOrigin fromRect:MonthNames[month] operation:NSCompositeCopy];

    tensSize.width = 0.0;
    tensSize.height = 0.0;


    imageOrigin.x = 30;
    imageOrigin.y = 15 + imageAdjust; //(15)
    if (date / 10)
        tensSize = DateNumbers[date / 10].size;
    onesSize = DateNumbers[date % 10].size;
    imageOrigin.x -= (tensSize.width + onesSize.width) / 2;
    if (date / 10)
        [theImage compositeToPoint:imageOrigin fromRect:DateNumbers[date / 10] operation:NSCompositeCopy];
    imageOrigin.x += tensSize.width + 1;
    [theImage compositeToPoint:imageOrigin fromRect:DateNumbers[date % 10] operation:NSCompositeCopy];

    //Draw the year
    if (showYear)
        {
        currentYear = [self yearOfCommonEra];
        imageAyear = YearNumbers[currentYear / 1000];
        currentYear = currentYear % 1000;

        imageByear = YearNumbers[currentYear / 100];
        currentYear = currentYear % 100;

        imageCyear = YearNumbers[currentYear / 10];
        currentYear = currentYear % 10;

        imageDyear = YearNumbers[currentYear];

        theSize = imageAyear.size;
        widthA = theSize.width;
        theSize = imageByear.size;
        widthB = theSize.width;
        theSize = imageCyear.size;
        widthC = theSize.width;
        theSize = imageDyear.size;
        width = widthA + widthB + widthC + theSize.width;

        imageOrigin.x = 32 - (width / 2.0);
        imageOrigin.y = 0;
        [theImage compositeToPoint:imageOrigin fromRect:imageAyear operation:NSCompositeCopy];
        imageOrigin.x = imageOrigin.x + widthA;
        [theImage compositeToPoint:imageOrigin fromRect:imageByear operation:NSCompositeCopy];
        imageOrigin.x = imageOrigin.x + widthB;
        [theImage compositeToPoint:imageOrigin fromRect:imageCyear operation:NSCompositeCopy];
        imageOrigin.x = imageOrigin.x + widthC;
        [theImage compositeToPoint:imageOrigin fromRect:imageDyear operation:NSCompositeCopy];
        }
}

- (void)setSecondOfMinute:(int)theSeconds
{
	seconds = theSeconds;
}

- (void)setMinuteOfHour:(int)theMinutes
{
	minutes = theMinutes;
}

- (void)setHourOfDay:(int)theHours
{
	hours = theHours % 24;
	if (hours <= 12)
	{
		[self setMeridian:0];
	}
	else
	{
		[self setMeridian:1];
	}
}

- (void)setDayOfWeek:(int)theWeekday
{
	weekday = theWeekday;
}

- (void)setDayOfMonth:(int)theDate
{
	date = theDate;
}

- (void)setMonthOfYear:(int)theMonth
{
	month = theMonth;
}

- (void)setYearOfCommonEra:(int)theYear
{
	year = theYear;
}

- (void)setMeridian:(int)theMeridian
{
	meridian = theMeridian;
}

- (void)takeMinuteOfHourFrom:sender
{
	[self setMinuteOfHour:[sender intValue]];
	[self display];
}

- (void)takeHourOfDayFrom:sender
{
	int  localhours = [sender intValue];

	localhours %= 24;
	if (localhours <= 12)
	{
		[self setMeridian:0];
	}
	else
	{
		[self setMeridian:1];
	}
	[self setHourOfDay:localhours];
	[self display];
}
	
- (void)takeDayOfWeekFrom:sender
{
	[self setDayOfWeek:[sender intValue]];
	[self display];
}

- (void)takeDayOfMonthFrom:sender
{
	[self setDayOfMonth:[sender intValue]];
	[self display];
}

- (void)takeMonthOfYearFrom:sender
{
	[self setMonthOfYear:[sender intValue]];
	[self display];
}

- (void)setTime:(struct tm *) theTime
{
	seconds = theTime->tm_sec;
	minutes = theTime->tm_min;
	hours = theTime->tm_hour;
	if (hours <= 12)
	{
		meridian = 0;
	}
	else
	{
		meridian = 1;
	};
	date = theTime->tm_mday;
	month = theTime->tm_mon;
	year = theTime->tm_year + 1900;
	weekday = theTime->tm_wday;
};

- (int)yearOfCommonEra
{
	return year;
}

- (int)monthOfYear
{
	return month;
}

- (int)dayOfWeek
{
	return weekday;
}

- (int)dayOfMonth
{
	return date;
}

- (int)hourOfDay
{
	return hours;
}

- (int)minuteOfHour
{
	return minutes;
}

- (int)secondOfMinute
{
	return seconds;
}


- (BOOL)militaryTime
{
	return militaryTime;
}

- (BOOL)showYear
{
	return showYear;
}

- (void)setShowYear:(BOOL)state
{
	showYear = state;
}


- (void)setMilitaryTime:(BOOL)state
{
	militaryTime = state;
}


- (BOOL)keepingTime
{
	return keepingTime;
}


- (void)setKeepingTime:(BOOL)yesno
{
	keepingTime = yesno;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    int myVersion = [aDecoder versionForClassName:NSStringFromClass([self class])];

      [super initWithCoder:aDecoder];
      if (myVersion < 2)
      {
         [aDecoder decodeValuesOfObjCTypes:"iiiiiiiiii", &seconds, &minutes, &hours,
              &date, &month, &year, &weekday, &meridian, &showYear, &militaryTime];
      }
      else
      {
         [aDecoder decodeValuesOfObjCTypes:"iiiiiiiicc", &seconds, &minutes, &hours,
              &date, &month, &year, &weekday, &meridian, &showYear, &militaryTime];
         if (myVersion < 4)
             year += 1900;
      }
      if (myVersion < 1)
      {
         keepingTime = NO;
      }
      else if (myVersion == 1)
      {
         [aDecoder decodeValueOfObjCType:"i" at:&keepingTime];
      }
      else
      {
         [aDecoder decodeValueOfObjCType:"c" at:&keepingTime];
      }
      if (myVersion > 2) {
         [aDecoder decodeValueOfObjCType:"c" at:&hidden];
      } else {
         hidden = NO;
      }
      [self _setUp];
      return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
	[super encodeWithCoder:aCoder];
	[aCoder encodeValuesOfObjCTypes:"iiiiiiiicc", &seconds, &minutes, &hours,
	&date, &month, &year, &weekday, &meridian, &showYear, &militaryTime];
	[aCoder encodeValueOfObjCType:"c" at:&keepingTime];
	[aCoder encodeValueOfObjCType:"c" at:&hidden];
}

- (void)setHide:(BOOL)hide
{
   hidden = hide;

}

- (BOOL)isHidden
{
   return hidden;
}

- (void)startClock:sender
{
    if (!keepingTime)
        {
        [self setToCurrentTime:self];
        timedEntry = [[NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(setToCurrentTime:) userInfo:0 repeats:YES] retain];
        keepingTime = YES;
        }
}

- (void)stopClock:sender
{
    if (timedEntry)
    {
        [timedEntry invalidate];
        [timedEntry release];
        [self setToCurrentTime:self];
        keepingTime = NO;
        timedEntry = 0;
    }

}

- (void)dealloc
{
    [theImage release];
    [timedEntry invalidate];
    [timedEntry release];
    [super dealloc];
}

- (void)setToCurrentTime:sender
{
    struct timeval		tp;
    struct timezone	tzp;
    struct tm     		*tv;

    gettimeofday (&tp, &tzp);
    tv = localtime (&tp.tv_sec);
    [self setTime:tv];
    [self display];
}

- (void)setDate:(NSCalendarDate *)dateObj
{
    [self setSecondOfMinute:[dateObj secondOfMinute]];
    [self setMinuteOfHour:[dateObj minuteOfHour]];
    [self setHourOfDay:[dateObj hourOfDay]];
    [self setDayOfWeek:[dateObj dayOfWeek]];
    [self setDayOfMonth:[dateObj dayOfMonth]];
    [self setMonthOfYear:[dateObj monthOfYear]];
    [self setYearOfCommonEra:[dateObj yearOfCommonEra]];
}

- (NSCalendarDate *)calendarDate
{
    return [NSCalendarDate dateWithYear:year month:month day:date hour:hours minute:minutes second:seconds timeZone:[NSTimeZone localTimeZone]];
}

@end
