/*
    kfc - Kurt's Free Calendar
    Copyright 1995 Kurt Werle

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#import "MonthView.h"
#import "CalendarController.h"
#import <math.h>

@implementation MonthView

- initFrame:(const NXRect *)frameRect
{
    int                 i;

    [super initFrame:frameRect];

    activeDay = nil;
    displayedMonthDay = [[MiscTime alloc] init];
    [displayedMonthDay setDay:0];
    [displayedMonthDay setHour:12];

    for (i = 0; i < DAYSINMONTHVIEW; i++)
    {
	[self addSubview:monthDayView[i] = [[DayView alloc] init]];
    }

    return self;
}

- free
{
    if (displayedMonthDay)
    {
	[displayedMonthDay free];
    }
    return[super free];
}

/* Initialize one of my content days. */
- initDayNumber:(int)theDay forMonth:(id)thisMonth inView:(int)theView
{
    id                  aDay;

    if (thisMonth)
    {
	aDay = [[MiscTime alloc] init];
	[aDay copyTimeFrom:thisMonth];
	[aDay setDay:theDay - 1];
    }
    else
	aDay = nil;
    [monthDayView[theView] initDayViewDay:aDay];
    if (aDay)
    {
	[aDay free];
    }
    return self;
}

/* Highlight the current day. */
- flip_Highlight_of_activeDay
{
    NXRect              theRect;

    if (([activeDay month] == [displayedMonthDay month])
	&& ([activeDay year] == [displayedMonthDay year]))
    {
	[self lockFocus];
	[monthDayView[[activeDay day] + [displayedMonthDay dayOfWeek]]
	 getFrame:&theRect];
	NXHighlightRect (&theRect);
	[self unlockFocus];
	[[self window] flushWindow];
    }
    return self;
}

- clear
{
    [self lockFocus];
    NXEraseRect (&bounds);
    NXFrameRect (&bounds);
    [self unlockFocus];
    return self;
}

/* Frame all of my days. */
- drawSelf:(const NXRect *)rects :(int)rectCount
{
    int                 i;
    NXRect              DayViewRect;

    [super drawSelf:rects :rectCount];
    PSsetgray (0.0);

    [self clear];

    for (i = [displayedMonthDay dayOfWeek];
	 i < [displayedMonthDay dayOfWeek] + daysthismonth; i++)
    {
	[monthDayView[i] getFrame:&DayViewRect];
	NXFrameRectWithWidth (&DayViewRect, 0);
    }

    [self flip_Highlight_of_activeDay];
    return self;
}

/* Tell my delegate I need to display. */
- updateDisplay
{
    if (([activeDay month] != [displayedMonthDay month]) ||
	([activeDay year] != [displayedMonthDay year]))
    {
	return[delegate update_MonthView_With_CurrentDay];
    }

    [self flip_Highlight_of_activeDay];

    return self;
}

/* Init the monthview so it displays the correct month. */
- initMonthWithFirstDay:(id)FirstDay
{
    int                 i,
                        PartialWeeksThisMonth;
    NXRect              DayViewRect;

    [displayedMonthDay setMonth:[FirstDay month]];
    [displayedMonthDay setYear:[FirstDay year]];

    daysthismonth = [MiscTime daysInMonth:[displayedMonthDay month] ofYear:[displayedMonthDay year]];

	/* Take care of all the days before the first day of the month. */
    NXSetRect (&DayViewRect, 0.0, 0.0, 0.0, 0.0);
    for (i = 0; i < [displayedMonthDay dayOfWeek]; i++)
    {
	[self initDayNumber:-1 forMonth:nil inView:i];
	[monthDayView[i] setFrame:&DayViewRect];
    }

    PartialWeeksThisMonth = ceil (([displayedMonthDay dayOfWeek] +
				   daysthismonth) / 7.0);

    for (i = [displayedMonthDay dayOfWeek];
	 i < [displayedMonthDay dayOfWeek] + daysthismonth; i++)
    {
	NXSetRect (&DayViewRect, (i % 7) * frame.size.width / 7,
		   ((PartialWeeksThisMonth - 1) - (int)i / 7)
		   * frame.size.height / PartialWeeksThisMonth,
		   frame.size.width / 7,
		   frame.size.height / PartialWeeksThisMonth);
	[monthDayView[i] setFrame:&DayViewRect];

	[self initDayNumber:i - [displayedMonthDay dayOfWeek] + 1
	 forMonth:displayedMonthDay inView:i];
    }

	/* Take care of all the days after the last day of the month. */
    NXSetRect (&DayViewRect, 0.0, 0.0, 0.0, 0.0);
    for (i = [displayedMonthDay dayOfWeek] + daysthismonth; i < DAYSINMONTHVIEW; i++)
    {
	[self initDayNumber:-1 forMonth:nil inView:i];
	[monthDayView[i] setFrame:&DayViewRect];
    }


    return self;
}

/* Set the active day. */
- setActiveDay:(id)theDay
{
    activeDay = theDay;
    return self;
}

/* Tell some of my dayviews to display a given appointment. */
- displayAppointment:theAppointment atTimes:timesToDisplay
{
    int                 i;

    for (i = 0; i < [timesToDisplay count]; i++)
    {
	int                 daytodisplay;

	daytodisplay = [displayedMonthDay dayOfWeek] +
	  [[timesToDisplay objectAt:i] day];
	if ((daytodisplay - [displayedMonthDay dayOfWeek] >= 0) &&
	    (daytodisplay - [displayedMonthDay dayOfWeek] < daysthismonth))
	{
	    [monthDayView[daytodisplay] addAppointment:theAppointment];
	}
    }
    return self;
}

- iWasClicked:sender
{
    [self flip_Highlight_of_activeDay];
    [activeDay copyTimeFrom:[sender myDate]];
    [self flip_Highlight_of_activeDay];
    return self;
}

- iWasDoubleClicked:sender
{
    [delegate editDaysAppointments:sender];
    return self;
}

/*
 This is totally wrong.  It pisses me off that I can't seem to find a better place for 'arrow left' and 'arrow right' definitions.  Is NeXT gonna fix this?!?
*/
- keyDown:(NXEvent *)theEvent
{
    switch (theEvent -> data.key.charCode)
    {
    case 173:			/* up */
	{
	    [self flip_Highlight_of_activeDay];
	    [activeDay subtractDays:7];
	    break;
	}
    case 172:			/* left */
	{
	    [self flip_Highlight_of_activeDay];
	    [activeDay subtractDays:1];
	    break;
	}
    case 175:			/* down */
	{
	    [self flip_Highlight_of_activeDay];
	    [activeDay addDays:7];
	    break;
	}
    case 174:			/* right */
	{
	    [self flip_Highlight_of_activeDay];
	    [activeDay addDays:1];
	    break;
	}
    case '\r':
	{
	    return[delegate editDaysAppointments:
	     monthDayView[[activeDay day] + [displayedMonthDay dayOfWeek]]];
	}
    default:
	{
	    return[super keyDown:theEvent];
	}
    }
    [self updateDisplay];

    return self;
}

@end
